* Re: [PATCH] dt-bindings: watchdog: Convert Aspeed binding to DT schema
From: Zev Weiss @ 2024-04-02 23:30 UTC (permalink / raw)
To: Andrew Jeffery
Cc: wim, linux, robh, krzysztof.kozlowski+dt, conor+dt, joel,
linux-watchdog, devicetree, linux-arm-kernel, linux-aspeed,
linux-kernel
In-Reply-To: <20240402120118.282035-1-andrew@codeconstruct.com.au>
On Tue, Apr 02, 2024 at 05:01:18AM PDT, Andrew Jeffery wrote:
>Squash warnings such as:
>
>```
>arch/arm/boot/dts/aspeed/aspeed-bmc-facebook-galaxy100.dtb: /ahb/apb@1e600000/watchdog@1e785000: failed to match any schema with compatible: ['aspeed,ast2400-wdt']
>```
>
>Signed-off-by: Andrew Jeffery <andrew@codeconstruct.com.au>
>---
> .../bindings/watchdog/aspeed,ast2400-wdt.yaml | 130 ++++++++++++++++++
> .../bindings/watchdog/aspeed-wdt.txt | 73 ----------
> 2 files changed, 130 insertions(+), 73 deletions(-)
> create mode 100644 Documentation/devicetree/bindings/watchdog/aspeed,ast2400-wdt.yaml
> delete mode 100644 Documentation/devicetree/bindings/watchdog/aspeed-wdt.txt
>
>diff --git a/Documentation/devicetree/bindings/watchdog/aspeed,ast2400-wdt.yaml b/Documentation/devicetree/bindings/watchdog/aspeed,ast2400-wdt.yaml
>new file mode 100644
>index 000000000000..10fcb50c4051
>--- /dev/null
>+++ b/Documentation/devicetree/bindings/watchdog/aspeed,ast2400-wdt.yaml
>@@ -0,0 +1,130 @@
>+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
>+%YAML 1.2
>+---
>+$id: http://devicetree.org/schemas/watchdog/aspeed,ast2400-wdt.yaml#
>+$schema: http://devicetree.org/meta-schemas/core.yaml#
>+
>+title: Aspeed watchdog timer controllers
>+
>+maintainers:
>+ - Andrew Jeffery <andrew@codeconstruct.com.au>
>+
>+properties:
>+ compatible:
>+ enum:
>+ - aspeed,ast2400-wdt
>+ - aspeed,ast2500-wdt
>+ - aspeed,ast2600-wdt
>+
>+ reg:
>+ maxItems: 1
>+
>+ clocks: true
>+
>+ aspeed,reset-type:
>+ enum:
>+ - cpu
>+ - soc
>+ - system
>+ - none
>+ description: |
>+ Reset behaviour - The watchdog can be programmed to generate one of three
>+ different types of reset when a timeout occcurs.
>+
>+ Specifying 'cpu' will only reset the processor on a timeout event.
>+
>+ Specifying 'soc' will reset a configurable subset of the SoC's controllers
Might be worth clarifying that it's configurable only on ast2500 &
ast2600, and which property (aspeed,reset-mask) configures it?
>+ on a timeout event. Controllers critical to the SoC's operation may remain untouched.
>+
>+ Specifying 'system' will reset all controllers on a timeout event, as if EXTRST had been asserted.
>+ Specifying "none" will cause the timeout event to have no reset effect.
Tiny nit: quoting (single vs. double) is slightly inconsistent between
values here.
>+ Another watchdog engine on the chip must be used for chip reset operations.
>+
>+ The default reset type is "system"
>+
>+ aspeed,alt-boot:
>+ $ref: /schemas/types.yaml#/definitions/flag
>+ description: |
>+ Direct the watchdog to configure the SoC to boot from the alternative boot
>+ region if a timeout occurs.
>+
>+ aspeed,external-signal:
>+ $ref: /schemas/types.yaml#/definitions/flag
>+ description: |
>+ Assert the timeout event on an external signal pin associated with the
>+ watchdog controller instance. The pin must be muxed appropriately.
>+
>+ aspeed,ext-pulse-duration:
>+ $ref: /schemas/types.yaml#/definitions/uint32
>+ description: |
>+ The duration, in microseconds, of the pulse emitted on the external signal pin
>+
>+ aspeed,ext-push-pull:
>+ $ref: /schemas/types.yaml#/definitions/flag
>+ description: |
>+ If aspeed,external-signal is specified in the node, set the external
>+ signal pin's drive type to push-pull. If aspeed,ext-push-pull is not
>+ specified then the pin is configured as open-drain.
>+
>+ aspeed,ext-active-high:
>+ $ref: /schemas/types.yaml#/definitions/flag
>+ description: |
>+ If both aspeed,external-signal and aspeed,ext-push-pull are specified in
>+ the node, set the pulse polarity to active-high. If aspeed,ext-active-high
>+ is not specified then the pin is configured as active-low.
>+
>+ aspeed,reset-mask:
>+ $ref: /schemas/types.yaml#/definitions/uint32-array
>+ minItems: 1
>+ maxItems: 2
>+ description: |
>+ A bitmaks indicating which peripherals will be reset if the watchdog
Typo: "bitmask"
>+ timer expires. On AST2500 SoCs this should be a single word defined using
>+ the AST2500_WDT_RESET_* macros; on AST2600 SoCs this should be a two-word
>+ array with the first word defined using the AST2600_WDT_RESET1_* macros,
>+ and the second word defined using the AST2600_WDT_RESET2_* macros.
>+
>+required:
>+ - compatible
>+ - reg
>+
>+allOf:
>+ - if:
>+ anyOf:
>+ - required:
>+ - aspeed,ext-push-pull
>+ - required:
>+ - aspeed,ext-active-high
>+ - required:
>+ - aspeed,reset-mask
>+ then:
>+ properties:
>+ compatible:
>+ enum:
>+ - aspeed,ast2500-wdt
>+ - aspeed,ast2600-wdt
>+ - if:
>+ required:
>+ - aspeed,ext-active-high
>+ then:
>+ required:
>+ - aspeed,ext-push-pull
>+
>+additionalProperties: false
>+
>+examples:
>+ - |
>+ wdt1: watchdog@1e785000 {
>+ compatible = "aspeed,ast2400-wdt";
>+ reg = <0x1e785000 0x1c>;
>+ aspeed,reset-type = "system";
>+ aspeed,external-signal;
>+ };
>+ - |
>+ #include <dt-bindings/watchdog/aspeed-wdt.h>
>+ wdt2: watchdog@1e785040 {
>+ compatible = "aspeed,ast2600-wdt";
>+ reg = <0x1e785040 0x40>;
>+ aspeed,reset-mask = <AST2600_WDT_RESET1_DEFAULT
>+ (AST2600_WDT_RESET2_DEFAULT & ~AST2600_WDT_RESET2_LPC)>;
>+ };
>diff --git a/Documentation/devicetree/bindings/watchdog/aspeed-wdt.txt b/Documentation/devicetree/bindings/watchdog/aspeed-wdt.txt
>deleted file mode 100644
>index 3208adb3e52e..000000000000
>--- a/Documentation/devicetree/bindings/watchdog/aspeed-wdt.txt
>+++ /dev/null
>@@ -1,73 +0,0 @@
>-Aspeed Watchdog Timer
>-
>-Required properties:
>- - compatible: must be one of:
>- - "aspeed,ast2400-wdt"
>- - "aspeed,ast2500-wdt"
>- - "aspeed,ast2600-wdt"
>-
>- - reg: physical base address of the controller and length of memory mapped
>- region
>-
>-Optional properties:
>-
>- - aspeed,reset-type = "cpu|soc|system|none"
>-
>- Reset behavior - Whenever a timeout occurs the watchdog can be programmed
>- to generate one of three different, mutually exclusive, types of resets.
>-
>- Type "none" can be specified to indicate that no resets are to be done.
>- This is useful in situations where another watchdog engine on chip is
>- to perform the reset.
>-
>- If 'aspeed,reset-type=' is not specified the default is to enable system
>- reset.
>-
>- Reset types:
>-
>- - cpu: Reset CPU on watchdog timeout
>-
>- - soc: Reset 'System on Chip' on watchdog timeout
>-
>- - system: Reset system on watchdog timeout
>-
>- - none: No reset is performed on timeout. Assumes another watchdog
>- engine is responsible for this.
>-
>- - aspeed,alt-boot: If property is present then boot from alternate block.
>- - aspeed,external-signal: If property is present then signal is sent to
>- external reset counter (only WDT1 and WDT2). If not
>- specified no external signal is sent.
>- - aspeed,ext-pulse-duration: External signal pulse duration in microseconds
>-
>-Optional properties for AST2500-compatible watchdogs:
>- - aspeed,ext-push-pull: If aspeed,external-signal is present, set the pin's
>- drive type to push-pull. The default is open-drain.
>- - aspeed,ext-active-high: If aspeed,external-signal is present and and the pin
>- is configured as push-pull, then set the pulse
>- polarity to active-high. The default is active-low.
>-
>-Optional properties for AST2500- and AST2600-compatible watchdogs:
>- - aspeed,reset-mask: A bitmask indicating which peripherals will be reset if
>- the watchdog timer expires. On AST2500 this should be a
>- single word defined using the AST2500_WDT_RESET_* macros;
>- on AST2600 this should be a two-word array with the first
>- word defined using the AST2600_WDT_RESET1_* macros and the
>- second word defined using the AST2600_WDT_RESET2_* macros.
>-
>-Examples:
>-
>- wdt1: watchdog@1e785000 {
>- compatible = "aspeed,ast2400-wdt";
>- reg = <0x1e785000 0x1c>;
>- aspeed,reset-type = "system";
>- aspeed,external-signal;
>- };
>-
>- #include <dt-bindings/watchdog/aspeed-wdt.h>
>- wdt2: watchdog@1e785040 {
>- compatible = "aspeed,ast2600-wdt";
>- reg = <0x1e785040 0x40>;
>- aspeed,reset-mask = <AST2600_WDT_RESET1_DEFAULT
>- (AST2600_WDT_RESET2_DEFAULT & ~AST2600_WDT_RESET2_LPC)>;
>- };
>--
>2.39.2
>
^ permalink raw reply
* Re: [PATCH RFC v2 0/4] wifi: ath10k: support board-specific firmware overrides
From: Jeff Johnson @ 2024-04-02 23:40 UTC (permalink / raw)
To: Dmitry Baryshkov, Kalle Valo, David S. Miller, Eric Dumazet,
Jakub Kicinski, Paolo Abeni, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Bjorn Andersson, Konrad Dybcio
Cc: ath10k, linux-wireless, netdev, devicetree, linux-arm-msm,
Krzysztof Kozlowski
In-Reply-To: <CAA8EJprpmC6+ePxw_G6y9YEszndq1VonS1HP=aP9OVHNm42LLw@mail.gmail.com>
On 3/29/2024 9:47 PM, Dmitry Baryshkov wrote:
> On Wed, 6 Mar 2024 at 10:16, Dmitry Baryshkov
> <dmitry.baryshkov@linaro.org> wrote:
>>
>> On WCN3990 platforms actual firmware, wlanmdsp.mbn, is sideloaded to the
>> modem DSP via the TQFTPserv. These MBN files are signed by the device
>> vendor, can only be used with the particular SoC or device.
>>
>> Unfortunately different firmware versions come with different features.
>> For example firmware for SDM845 doesn't use single-chan-info-per-channel
>> feature, while firmware for QRB2210 / QRB4210 requires that feature.
>>
>> Allow board DT files to override the subdir of the fw dir used to lookup
>> the firmware-N.bin file decribing corresponding WiFi firmware.
>> For example, adding firmware-name = "qrb4210" property will make the
>> driver look for the firmware-N.bin first in ath10k/WCN3990/hw1.0/qrb4210
>> directory and then fallback to the default ath10k/WCN3990/hw1.0 dir.
>>
>> Signed-off-by: Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
>> ---
>> Changes in v2:
>> - Fixed the comment about the default board name being NULL (Kalle)
>> - Expanded commit message to provide examples for firmware paths (Kalle)
>> - Added a note regarding board-2.bin to the commit message (Kalle)
>> - Link to v1: https://lore.kernel.org/r/20240130-wcn3990-firmware-path-v1-0-826b93202964@linaro.org
>>
>> ---
>> Dmitry Baryshkov (4):
>> dt-bindings: net: wireless: ath10k: describe firmware-name property
>> wifi: ath10k: support board-specific firmware overrides
>> arm64: dts: qcom: qrb2210-rb1: add firmware-name qualifier to WiFi node
>> arm64: dts: qcom: qrb4210-rb1: add firmware-name qualifier to WiFi node
>
> Kalle, Jeff, is there anything pending on me on this series?
>
Nothing from me -- this is outside my area of expertise so I'm deferring to Kalle.
Kalle?
^ permalink raw reply
* RE: [PATCH v3 6/7] PCI: dwc: rcar-gen4: Add support for r8a779g0
From: Yoshihiro Shimoda @ 2024-04-03 0:03 UTC (permalink / raw)
To: Geert Uytterhoeven
Cc: lpieralisi@kernel.org, kw@linux.com, robh@kernel.org,
bhelgaas@google.com, krzysztof.kozlowski+dt@linaro.org,
conor+dt@kernel.org, jingoohan1@gmail.com, mani@kernel.org,
marek.vasut+renesas@gmail.com, linux-pci@vger.kernel.org,
devicetree@vger.kernel.org, linux-renesas-soc@vger.kernel.org
In-Reply-To: <CAMuHMdXCsye4kEP4=1rYNx97VpXHjjNg9BFawnUBADfL2ADQTw@mail.gmail.com>
Hi Geert-san,
> From: Geert Uytterhoeven, Sent: Tuesday, April 2, 2024 4:53 PM
>
> Hi Shimoda-san,
>
> On Mon, Apr 1, 2024 at 4:40 AM Yoshihiro Shimoda
> <yoshihiro.shimoda.uh@renesas.com> wrote:
> > This driver previously supported r8a779f0 (R-Car S4-8). Add support
> > for r8a779g0 (R-Car V4H).
> >
> > To support r8a779g0, it requires specific firmware.
> >
> > Signed-off-by: Yoshihiro Shimoda <yoshihiro.shimoda.uh@renesas.com>
>
> Thanks for your patch!
Thank you for your review!
> > --- a/drivers/pci/controller/dwc/pcie-rcar-gen4.c
> > +++ b/drivers/pci/controller/dwc/pcie-rcar-gen4.c
>
> > +static int rcar_gen4_pcie_update_phy_firmware(struct rcar_gen4_pcie *rcar)
> > +{
> > + const u32 check_addr[] = { 0x00101018, 0x00101118, 0x00101021, 0x00101121};
> > + struct dw_pcie *dw = &rcar->dw;
> > + const struct firmware *fw;
> > + unsigned int i, timeout;
> > + u32 data;
> > + int ret;
> > +
> > + ret = request_firmware(&fw, RCAR_GEN4_PCIE_FIRMWARE_NAME, dw->dev);
> > + if (ret) {
> > + dev_err(dw->dev, "%s: Requesting firmware failed\n", __func__);
> > + return ret;
> > + }
> > +
> > + for (i = 0; i < (fw->size / 2); i++) {
> > + data = fw->data[i * 2] | fw->data[(i * 2) + 1] << 8;
> > + timeout = 100;
> > +retry_data:
> > + dw_pcie_writel_dbi(dw, PRTLGC89, RCAR_GEN4_PCIE_FIRMWARE_BASE_ADDR + i);
> > + dw_pcie_writel_dbi(dw, PRTLGC90, data);
> > + if (rcar_gen4_pcie_reg_check_bit(rcar, PRTLGC89, BIT(30)) < 0) {
>
> If you would invert the logic here, you could "break" here, ...
>
> > + if (!(--timeout)) {
> > + ret = -ETIMEDOUT;
> > + goto exit;
> > + }
> > + usleep_range(100, 200);
> > + goto retry_data;
>
> ... and convert "retry_data: ... goto retry_data" into "do { ... } while (1)",
> avoiding the goto.
Thank you for your suggestion. I'll fix it.
> > + }
> > + }
> > +
> > + rcar_gen4_pcie_phy_reg_update_bits(rcar, RCAR_GEN4_PCIE_PHY_0f8, BIT(17), BIT(17));
> > +
> > + for (i = 0; i < ARRAY_SIZE(check_addr); i++) {
> > + timeout = 100;
> > +retry_check:
> > + dw_pcie_writel_dbi(dw, PRTLGC89, check_addr[i]);
> > + ret = rcar_gen4_pcie_reg_check_bit(rcar, PRTLGC89, BIT(30));
> > + ret |= rcar_gen4_pcie_reg_check_bit(rcar, PRTLGC90, BIT(0));
> > + if (ret < 0) {
> > + if (!(--timeout)) {
> > + ret = -ETIMEDOUT;
> > + goto exit;
> > + }
> > + usleep_range(100, 200);
> > + goto retry_check;
>
> Likewise.
I'll fix it.
Best regards,
Yoshihiro Shimoda
> > + }
> > + }
> > +
> > + ret = 0;
> > +exit:
> > + release_firmware(fw);
> > +
> > + return ret;
> > +}
>
> Gr{oetje,eeting}s,
>
> Geert
>
> --
> Geert Uytterhoeven -- There's lots of Linux beyond ia32 -- geert@linux-m68k.org
>
> In personal conversations with technical people, I call myself a hacker. But
> when I'm talking to journalists I just say "programmer" or something like that.
> -- Linus Torvalds
^ permalink raw reply
* Re: [PATCH v3] clk: starfive: pll: Fix lower rate of CPUfreq by setting PLL0 rate to 1.5GHz
From: Bo Gan @ 2024-04-03 0:26 UTC (permalink / raw)
To: Krzysztof Kozlowski, Xingyu Wu, Michael Turquette, Stephen Boyd,
Conor Dooley, Emil Renner Berthing, Rob Herring,
Krzysztof Kozlowski
Cc: Paul Walmsley, Palmer Dabbelt, Albert Ou, Hal Feng, linux-kernel,
linux-clk, linux-riscv, devicetree
In-Reply-To: <8d21b1bc-9402-41d4-bd81-c521c8a33d2d@kernel.org>
On 4/2/24 9:18 AM, Krzysztof Kozlowski wrote:
> On 02/04/2024 11:09, Xingyu Wu wrote:
>> CPUfreq supports 4 cpu frequency loads on 375/500/750/1500MHz.
>> But now PLL0 rate is 1GHz and the cpu frequency loads become
>> 333/500/500/1000MHz in fact.
>>
>> So PLL0 rate should be default set to 1.5GHz. But setting the
>> PLL0 rate need certain steps:
>>
>> 1. Change the parent of cpu_root clock to OSC clock.
>> 2. Change the divider of cpu_core if PLL0 rate is higher than
>> 1.25GHz before CPUfreq boot.
>> 3. Change the parent of cpu_root clock back to PLL0 clock.
>>
>> Reviewed-by: Hal Feng <hal.feng@starfivetech.com>
>> Fixes: e2c510d6d630 ("riscv: dts: starfive: Add cpu scaling for JH7110 SoC")
>> Signed-off-by: Xingyu Wu <xingyu.wu@starfivetech.com>
>> ---
>>
>> Hi Stephen and Emil,
>>
>> This patch fixes the issue about lower rate of CPUfreq[1] by setting PLL0
>> rate to 1.5GHz.
>>
>> In order not to affect the cpu operation, setting the PLL0 rate need
>> certain steps. The cpu_root's parent clock should be changed first. And
>> the divider of the cpu_core clock should be set to 2 so they won't crash
>> when setting 1.5GHz without voltage regulation. Due to PLL driver boot
>> earlier than SYSCRG driver, cpu_core and cpu_root clocks are using by
>> ioremap().
>>
>> [1]: https://github.com/starfive-tech/VisionFive2/issues/55
>>
>> Previous patch link:
>> v2: https://lore.kernel.org/all/20230821152915.208366-1-xingyu.wu@starfivetech.com/
>> v1: https://lore.kernel.org/all/20230811033631.160912-1-xingyu.wu@starfivetech.com/
>>
>> Thanks,
>> Xingyu Wu
>> ---
>> .../jh7110-starfive-visionfive-2.dtsi | 5 +
>> .../clk/starfive/clk-starfive-jh7110-pll.c | 102 ++++++++++++++++++
>
> Please do not mix DTS and driver code. That's not really portable. DTS
> is being exported and used in other projects.
>
> ...
>
>>
>> @@ -458,6 +535,8 @@ static int jh7110_pll_probe(struct platform_device *pdev)
>> struct jh7110_pll_priv *priv;
>> unsigned int idx;
>> int ret;
>> + struct device_node *np;
>> + struct resource res;
>>
>> priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
>> if (!priv)
>> @@ -489,6 +568,29 @@ static int jh7110_pll_probe(struct platform_device *pdev)
>> return ret;
>> }
>>
>> + priv->is_first_set = true;
>> + np = of_find_compatible_node(NULL, NULL, "starfive,jh7110-syscrg");
>
> Your drivers should not do it. It's fragile, hides true link/dependency.
> Please use phandles.
>
>
>> + if (!np) {
>> + ret = PTR_ERR(np);
>> + dev_err(priv->dev, "failed to get syscrg node\n");
>> + goto np_put;
>> + }
>> +
>> + ret = of_address_to_resource(np, 0, &res);
>> + if (ret) {
>> + dev_err(priv->dev, "failed to get syscrg resource\n");
>> + goto np_put;
>> + }
>> +
>> + priv->syscrg_base = ioremap(res.start, resource_size(&res));
>> + if (!priv->syscrg_base)
>> + ret = -ENOMEM;
>
> Why are you mapping other device's IO? How are you going to ensure
> synced access to registers?
>
>
>
> Best regards,
> Krzysztof
>
>
> _______________________________________________
> linux-riscv mailing list
> linux-riscv@lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/linux-riscv
>
Hi Xingyu,
Echoing Krzysztof's point. This piece code seems wrong to me. This logic belongs
to syscrg, rather than pll. Why don't you do the pll0->osc->pll0 switching from
syscrg side during probing?
Bo
^ permalink raw reply
* Re: [PATCH 5/5] arm64: dts: Add device tree source for the Au-Zone Maivin Starter Kit
From: Shawn Guo @ 2024-04-03 0:30 UTC (permalink / raw)
To: Laurent Pinchart
Cc: devicetree, imx, linux-arm-kernel, Trevor Zaharichuk, Greg Lytle,
Shawn Guo, Sascha Hauer, Pengutronix Kernel Team, Fabio Estevam,
Rob Herring, Krzysztof Kozlowski, Conor Dooley
In-Reply-To: <20240325203245.31660-6-laurent.pinchart@ideasonboard.com>
On Mon, Mar 25, 2024 at 10:32:45PM +0200, Laurent Pinchart wrote:
> The Maivin board is an AI vision starter kit sold by Au-Zone
> Technologies, developed in collaboration with Toradex and Vision
> Components. It is based on a Toradex Verdin i.MX8MP SoM.
>
> Add a device tree that covers the base set the peripherals found on the
> board:
>
> - Ethernet
> - USB
> - SD card slot
> - CAN and serial ports (RS232 and RS485)
> - DACs, EEPROMs, temperature sensor
> - PCI M.2 and CSI regulators
>
> An additional pinctrl group is included for the M.2 modem, but hasn't
> been tested due to lack of compatible hardware.
>
> Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
> ---
> arch/arm64/boot/dts/freescale/Makefile | 1 +
> .../boot/dts/freescale/imx8mp-maivin.dts | 236 ++++++++++++++++++
> 2 files changed, 237 insertions(+)
> create mode 100644 arch/arm64/boot/dts/freescale/imx8mp-maivin.dts
>
> diff --git a/arch/arm64/boot/dts/freescale/Makefile b/arch/arm64/boot/dts/freescale/Makefile
> index 045250d0a040..03af8c242649 100644
> --- a/arch/arm64/boot/dts/freescale/Makefile
> +++ b/arch/arm64/boot/dts/freescale/Makefile
> @@ -165,6 +165,7 @@ dtb-$(CONFIG_ARCH_MXC) += imx8mp-dhcom-pdk2.dtb
> dtb-$(CONFIG_ARCH_MXC) += imx8mp-dhcom-pdk3.dtb
> dtb-$(CONFIG_ARCH_MXC) += imx8mp-evk.dtb
> dtb-$(CONFIG_ARCH_MXC) += imx8mp-icore-mx8mp-edimm2.2.dtb
> +dtb-$(CONFIG_ARCH_MXC) += imx8mp-maivin.dtb
> dtb-$(CONFIG_ARCH_MXC) += imx8mp-msc-sm2s-ep1.dtb
> dtb-$(CONFIG_ARCH_MXC) += imx8mp-phyboard-pollux-rdk.dtb
> dtb-$(CONFIG_ARCH_MXC) += imx8mp-skov-revb-hdmi.dtb
> diff --git a/arch/arm64/boot/dts/freescale/imx8mp-maivin.dts b/arch/arm64/boot/dts/freescale/imx8mp-maivin.dts
> new file mode 100644
> index 000000000000..2d1c8e782465
> --- /dev/null
> +++ b/arch/arm64/boot/dts/freescale/imx8mp-maivin.dts
> @@ -0,0 +1,236 @@
> +// SPDX-License-Identifier: GPL-2.0+ OR MIT
> +/*
> + * Copyright 2021 Au-Zone Technologies
> + * Copyright 2024 Ideas on Board
> + */
> +
> +/dts-v1/;
> +
> +#include <dt-bindings/gpio/gpio.h>
> +#include <dt-bindings/input/linux-event-codes.h>
> +#include <dt-bindings/leds/common.h>
> +
> +#include "imx8mp-verdin.dtsi"
> +#include "imx8mp-verdin-nonwifi.dtsi"
> +
> +/ {
> + model = "Au-Zone Maivin AI Vision Starter Kit";
> + compatible = "au-zone,maivin-starter-kit",
> + "toradex,verdin-imx8mp-nonwifi",
> + "toradex,verdin-imx8mp",
> + "fsl,imx8mp";
> +
> + gpio-keys {
> + compatible = "gpio-keys";
> + pinctrl-0 = <&pinctrl_sw1>;
> +
> + button-0 {
> + label = "SW1";
> + linux,code = <BTN_MISC>;
> + interrupts-extended = <&gpio3 16 IRQ_TYPE_LEVEL_LOW>;
> + };
> + };
> +
> + leds {
> + compatible = "gpio-leds";
> + pinctrl-0 = <&pinctrl_led>;
> +
> + led-0 {
> + color = <LED_COLOR_ID_BLUE>;
> + function = LED_FUNCTION_STATUS;
> + linux,default-trigger = "heartbeat";
> + gpios = <&gpio3 14 GPIO_ACTIVE_HIGH>;
> + };
> + };
> +
> + csi_3v3: regulator-csi-3v3 {
> + compatible = "regulator-fixed";
> + regulator-name = "CSI_3V3";
> + pinctrl-0 = <&pinctrl_csi_3v3>;
> + gpio = <&gpio3 7 GPIO_ACTIVE_HIGH>;
> + enable-active-high;
> + startup-delay-us = <50000>; /* TODO: Determine the right value */
> + };
> +
> + m2_3v3: regulator-m2-3v3 {
> + compatible = "regulator-fixed";
> + regulator-name = "M2_3V3";
> + regulator-max-microvolt = <3300000>;
> + regulator-min-microvolt = <3300000>;
> + pinctrl-0 = <&pinctrl_m2_3v3>;
> + gpio = <&gpio3 1 GPIO_ACTIVE_HIGH>;
> + enable-active-high;
> + };
> +
> + /* Carrier Board Supply 3V3_SW */
> + reg_3v3: regulator-3v3-sw {
> + compatible = "regulator-fixed";
> + regulator-max-microvolt = <3300000>;
> + regulator-min-microvolt = <3300000>;
> + regulator-name = "3V3_SW";
> + };
> +};
> +
> +&eqos {
> + status = "okay";
> +};
> +
> +/* Verdin CAN_1 */
> +&flexcan1 {
> + status = "okay";
> +};
> +
> +/* Verdin CAN_2 */
> +&flexcan2 {
> + status = "okay";
> +};
> +
> +/* Verdin I2C_2_DSI */
> +&i2c2 {
> + status = "okay";
> +
> + clock-frequency = <400000>;
> + scl-gpios = <&gpio5 16 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>;
> + sda-gpios = <&gpio5 17 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>;
We usually end property list with 'status'.
> +
> + dac@d {
> + compatible = "ti,dac081c081";
> + reg = <0x0d>;
> + vref-supply = <&csi_3v3>;
> + };
> +};
> +
> +/* Verdin I2C_4_CSI */
> +&i2c3 {
> + status = "okay";
> +
> + dac@d {
> + compatible = "ti,dac081c081";
> + reg = <0x0d>;
> + vref-supply = <&csi_3v3>;
> + };
> +};
> +
> +/* Verdin I2C_1 */
> +&i2c4 {
> + status = "okay";
> +
> + temp-sensor@4b {
> + compatible = "ti,tmp102";
> + reg = <0x4b>;
> + };
> +
> + /* EEPROM on the rear connector interface */
> + eeprom@54 {
> + compatible = "st,24c02", "atmel,24c02";
> + pagesize = <16>;
> + reg = <0x54>;
> + };
> +};
> +
> +/* EEPROM on the carrier board */
> +&eeprom_carrier_board {
> + status = "okay";
> +};
> +
> +&iomuxc {
> + pinctrl_csi_3v3: csi-3v3-grp {
> + fsl,pins = <
> + MX8MP_IOMUXC_NAND_DATA01__GPIO3_IO07 0x184 /* SODIMM 58 */
> + >;
> + };
> +
> + gpio7grp {
> + fsl,pins = <
> + MX8MP_IOMUXC_SAI1_RXD1__GPIO4_IO03 0x82 /* SODIMM 220 */
> + >;
> + };
> +
> + gpio8grp {
> + fsl,pins = <
> + MX8MP_IOMUXC_SAI1_RXC__GPIO4_IO01 0x82 /* SODIMM 222 */
> + >;
> + };
> +
> + pinctrl_led: ledgrp {
> + fsl,pins = <
> + MX8MP_IOMUXC_NAND_DQS__GPIO3_IO14 0x82 /* SODIMM 66 */
> + >;
> + };
> +
> + /* M.2 power off and reset */
> + pinctrl_m2: m2grp {
> + fsl,pins = <
> + MX8MP_IOMUXC_NAND_DATA00__GPIO3_IO06 0x82 /* SODIMM 56 */
> + MX8MP_IOMUXC_NAND_DATA03__GPIO3_IO09 0x82 /* SODIMM 62 */
> + >;
> + };
> +
> + pinctrl_m2_3v3: m2-3v3-grp {
> + fsl,pins = <
> + MX8MP_IOMUXC_NAND_CE0_B__GPIO3_IO01 0x82 /* SODIMM 54 */
> + >;
> + };
> +
> + pinctrl_sw1: sw1grp {
> + fsl,pins = <
> + /*
> + * SW1 shortens the pin to ground when pressed, enable
> + * the internal pull-up.
> + */
> + MX8MP_IOMUXC_NAND_READY_B__GPIO3_IO16 0x1c0 /* SODIMM 64 */
> + >;
> + };
> +};
> +
> +®_usdhc2_vmmc {
> + vin-supply = <®_3v3>;
> +};
> +
> +/* Verdin UART_1 */
> +/* Enabling RS-485 operation */
> +&uart1 {
> + fsl,uart-has-rtscts;
uart-has-rtscts instead.
Shawn
> + linux,rs485-enabled-at-boot-time;
> +};
> +
> +/* Verdin UART_2, for M.2 card slot */
> +&uart2 {
> + status = "okay";
> +};
> +
> +/* Verdin UART_3, used as the Linux Console */
> +&uart3 {
> + status = "okay";
> +};
> +
> +/* Verdin USB_1, USB recovery */
> +&usb3_phy0 {
> + status = "okay";
> +};
> +
> +&usb3_0 {
> + status = "okay";
> +};
> +
> +&usb_dwc3_0 {
> + status = "okay";
> +};
> +
> +/* Verdin USB_2, for M.2 card slot */
> +&usb3_phy1 {
> + status = "okay";
> +};
> +
> +&usb3_1 {
> + status = "okay";
> +};
> +
> +&usb_dwc3_1 {
> + status = "okay";
> +};
> +
> +/* Verdin SD_1, for SD card slot */
> +&usdhc2 {
> + status = "okay";
> +};
> --
> Regards,
>
> Laurent Pinchart
>
^ permalink raw reply
* [PATCH v8 2/4] ASoc: PCM6240: Create header file for PCM6240 Family driver code
From: Shenghao Ding @ 2024-04-03 0:31 UTC (permalink / raw)
To: linux-kernel
Cc: lgirdwood, broonie, robh+dt, krzysztof.kozlowski+dt, conor+dt,
linux-sound, devicetree, perex, tiwai, 13916275206, mohit.chawla,
soyer, jkhuang3, tiwai, pdjuandi, manisha.agrawal, aviel,
hnagalla, praneeth, Baojun.Xu, Shenghao Ding
In-Reply-To: <20240403003159.389-1-shenghao-ding@ti.com>
PCM6240 driver implements a flexible and configurable setting for register
and filter coefficients, to one, two or even multiple PCM6240 Family Audio
chips.
Signed-off-by: Shenghao Ding <shenghao-ding@ti.com>
---
v8:
- use some reasonable format of changelog.
- Link to v3: https://lore.kernel.org/all/20240203030504.1724-2-shenghao-ding@ti.com/
V7:
- No changes.
V6:
- No changes.
V5:
- No changes.
V4:
- No changes.
V3:
- remove unused data structure.
- Link to v2: https://lore.kernel.org/all/20240126035855.1785-2-shenghao-ding@ti.com/
---
sound/soc/codecs/pcm6240.h | 236 +++++++++++++++++++++++++++++++++++++
1 file changed, 236 insertions(+)
create mode 100644 sound/soc/codecs/pcm6240.h
diff --git a/sound/soc/codecs/pcm6240.h b/sound/soc/codecs/pcm6240.h
new file mode 100644
index 000000000000..49a313305b26
--- /dev/null
+++ b/sound/soc/codecs/pcm6240.h
@@ -0,0 +1,236 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+//
+// ALSA SoC Texas Instruments PCM6240 Family Audio ADC/DAC/Router
+//
+// Copyright (C) 2022 - 2024 Texas Instruments Incorporated
+// https://www.ti.com
+//
+// The PCM6240 driver implements a flexible and configurable
+// algo coefficient setting for one, two, or even multiple
+// PCM6240 Family Audio chips.
+//
+// Author: Shenghao Ding <shenghao-ding@ti.com>
+//
+
+#ifndef __PCM6240_H__
+#define __PCM6240_H__
+
+enum pcm_device {
+ ADC3120,
+ ADC5120,
+ ADC6120,
+ DIX4192,
+ PCM1690,
+ PCM3120,
+ PCM3140,
+ PCM5120,
+ PCM5140,
+ PCM6120,
+ PCM6140,
+ PCM6240,
+ PCM6260,
+ PCM9211,
+ PCMD3140,
+ PCMD3180,
+ PCMD512X,
+ TAA5212,
+ TAA5412,
+ TAD5212,
+ TAD5412,
+ MAX_DEVICE,
+};
+
+#define PCMDEV_GENERIC_VOL_CTRL 0x0
+#define PCMDEV_PCM1690_VOL_CTRL 0x1
+#define PCMDEV_PCM1690_FINE_VOL_CTRL 0x2
+
+/* Maximum number of I2C addresses */
+#define PCMDEVICE_MAX_I2C_DEVICES 4
+/* Maximum number defined in REGBIN protocol */
+#define PCMDEVICE_MAX_REGBIN_DEVICES 8
+#define PCMDEVICE_CONFIG_SUM 64
+#define PCMDEVICE_BIN_FILENAME_LEN 64
+
+#define PCMDEVICE_RATES (SNDRV_PCM_RATE_44100 | \
+ SNDRV_PCM_RATE_48000)
+#define PCMDEVICE_MAX_CHANNELS 8
+#define PCMDEVICE_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | \
+ SNDRV_PCM_FMTBIT_S20_3LE | \
+ SNDRV_PCM_FMTBIT_S24_3LE | \
+ SNDRV_PCM_FMTBIT_S24_LE | \
+ SNDRV_PCM_FMTBIT_S32_LE)
+
+/* PAGE Control Register (available in page0 of each book) */
+#define PCMDEVICE_PAGE_SELECT 0x00
+#define PCMDEVICE_REG(page, reg) ((page * 128) + reg)
+#define PCMDEVICE_REG_SWRESET PCMDEVICE_REG(0X0, 0x01)
+#define PCMDEVICE_REG_SWRESET_RESET BIT(0)
+
+#define ADC5120_REG_CH1_ANALOG_GAIN PCMDEVICE_REG(0X0, 0x3d)
+#define ADC5120_REG_CH1_DIGITAL_GAIN PCMDEVICE_REG(0X0, 0x3e)
+#define ADC5120_REG_CH2_ANALOG_GAIN PCMDEVICE_REG(0X0, 0x42)
+#define ADC5120_REG_CH2_DIGITAL_GAIN PCMDEVICE_REG(0X0, 0x43)
+
+#define PCM1690_REG_MODE_CTRL PCMDEVICE_REG(0X0, 0x46)
+#define PCM1690_REG_MODE_CTRL_DAMS_MSK BIT(7)
+#define PCM1690_REG_MODE_CTRL_DAMS_FINE_STEP 0x0
+#define PCM1690_REG_MODE_CTRL_DAMS_WIDE_RANGE 0x80
+
+#define PCM1690_REG_CH1_DIGITAL_GAIN PCMDEVICE_REG(0X0, 0x48)
+#define PCM1690_REG_CH2_DIGITAL_GAIN PCMDEVICE_REG(0X0, 0x49)
+#define PCM1690_REG_CH3_DIGITAL_GAIN PCMDEVICE_REG(0X0, 0x4a)
+#define PCM1690_REG_CH4_DIGITAL_GAIN PCMDEVICE_REG(0X0, 0x4b)
+#define PCM1690_REG_CH5_DIGITAL_GAIN PCMDEVICE_REG(0X0, 0x4c)
+#define PCM1690_REG_CH6_DIGITAL_GAIN PCMDEVICE_REG(0X0, 0x4d)
+#define PCM1690_REG_CH7_DIGITAL_GAIN PCMDEVICE_REG(0X0, 0x4e)
+#define PCM1690_REG_CH8_DIGITAL_GAIN PCMDEVICE_REG(0X0, 0x4f)
+
+#define PCM6240_REG_CH1_ANALOG_GAIN PCMDEVICE_REG(0X0, 0x3d)
+#define PCM6240_REG_CH1_DIGITAL_GAIN PCMDEVICE_REG(0X0, 0x3e)
+#define PCM6240_REG_CH2_ANALOG_GAIN PCMDEVICE_REG(0X0, 0x42)
+#define PCM6240_REG_CH2_DIGITAL_GAIN PCMDEVICE_REG(0X0, 0x43)
+#define PCM6240_REG_CH3_ANALOG_GAIN PCMDEVICE_REG(0X0, 0x47)
+#define PCM6240_REG_CH3_DIGITAL_GAIN PCMDEVICE_REG(0X0, 0x48)
+#define PCM6240_REG_CH4_ANALOG_GAIN PCMDEVICE_REG(0X0, 0x4c)
+#define PCM6240_REG_CH4_DIGITAL_GAIN PCMDEVICE_REG(0X0, 0x4d)
+
+#define PCM6260_REG_CH1_ANALOG_GAIN PCMDEVICE_REG(0X0, 0x3d)
+#define PCM6260_REG_CH1_DIGITAL_GAIN PCMDEVICE_REG(0X0, 0x3e)
+#define PCM6260_REG_CH2_ANALOG_GAIN PCMDEVICE_REG(0X0, 0x42)
+#define PCM6260_REG_CH2_DIGITAL_GAIN PCMDEVICE_REG(0X0, 0x43)
+#define PCM6260_REG_CH3_ANALOG_GAIN PCMDEVICE_REG(0X0, 0x47)
+#define PCM6260_REG_CH3_DIGITAL_GAIN PCMDEVICE_REG(0X0, 0x48)
+#define PCM6260_REG_CH4_ANALOG_GAIN PCMDEVICE_REG(0X0, 0x4c)
+#define PCM6260_REG_CH4_DIGITAL_GAIN PCMDEVICE_REG(0X0, 0x4d)
+#define PCM6260_REG_CH5_ANALOG_GAIN PCMDEVICE_REG(0X0, 0x51)
+#define PCM6260_REG_CH5_DIGITAL_GAIN PCMDEVICE_REG(0X0, 0x52)
+#define PCM6260_REG_CH6_ANALOG_GAIN PCMDEVICE_REG(0X0, 0x56)
+#define PCM6260_REG_CH6_DIGITAL_GAIN PCMDEVICE_REG(0X0, 0x57)
+
+#define PCM9211_REG_SW_CTRL PCMDEVICE_REG(0X0, 0x40)
+#define PCM9211_REG_SW_CTRL_MRST_MSK BIT(7)
+#define PCM9211_REG_SW_CTRL_MRST 0x0
+
+#define PCM9211_REG_CH1_DIGITAL_GAIN PCMDEVICE_REG(0X0, 0x46)
+#define PCM9211_REG_CH2_DIGITAL_GAIN PCMDEVICE_REG(0X0, 0x47)
+
+#define PCMD3140_REG_CH1_DIGITAL_GAIN PCMDEVICE_REG(0X0, 0x3E)
+#define PCMD3140_REG_CH2_DIGITAL_GAIN PCMDEVICE_REG(0X0, 0x43)
+#define PCMD3140_REG_CH3_DIGITAL_GAIN PCMDEVICE_REG(0X0, 0x48)
+#define PCMD3140_REG_CH4_DIGITAL_GAIN PCMDEVICE_REG(0X0, 0x4D)
+
+#define PCMD3180_REG_CH1_DIGITAL_GAIN PCMDEVICE_REG(0X0, 0x3E)
+#define PCMD3180_REG_CH2_DIGITAL_GAIN PCMDEVICE_REG(0X0, 0x43)
+#define PCMD3180_REG_CH3_DIGITAL_GAIN PCMDEVICE_REG(0X0, 0x48)
+#define PCMD3180_REG_CH4_DIGITAL_GAIN PCMDEVICE_REG(0X0, 0x4D)
+#define PCMD3180_REG_CH5_DIGITAL_GAIN PCMDEVICE_REG(0X0, 0x52)
+#define PCMD3180_REG_CH6_DIGITAL_GAIN PCMDEVICE_REG(0X0, 0x57)
+#define PCMD3180_REG_CH7_DIGITAL_GAIN PCMDEVICE_REG(0X0, 0x5C)
+#define PCMD3180_REG_CH8_DIGITAL_GAIN PCMDEVICE_REG(0X0, 0x61)
+
+#define TAA5412_REG_CH1_DIGITAL_VOLUME PCMDEVICE_REG(0X0, 0x52)
+#define TAA5412_REG_CH2_DIGITAL_VOLUME PCMDEVICE_REG(0X0, 0x57)
+#define TAA5412_REG_CH3_DIGITAL_VOLUME PCMDEVICE_REG(0X0, 0x5B)
+#define TAA5412_REG_CH4_DIGITAL_VOLUME PCMDEVICE_REG(0X0, 0x5F)
+
+#define TAA5412_REG_CH1_FINE_GAIN PCMDEVICE_REG(0X0, 0x53)
+#define TAA5412_REG_CH2_FINE_GAIN PCMDEVICE_REG(0X0, 0x58)
+#define TAA5412_REG_CH3_FINE_GAIN PCMDEVICE_REG(0X0, 0x5C)
+#define TAA5412_REG_CH4_FINE_GAIN PCMDEVICE_REG(0X0, 0x60)
+
+#define PCMDEVICE_CMD_SING_W 0x1
+#define PCMDEVICE_CMD_BURST 0x2
+#define PCMDEVICE_CMD_DELAY 0x3
+#define PCMDEVICE_CMD_FIELD_W 0x4
+
+enum pcmdevice_bin_blk_type {
+ PCMDEVICE_BIN_BLK_COEFF = 1,
+ PCMDEVICE_BIN_BLK_POST_POWER_UP,
+ PCMDEVICE_BIN_BLK_PRE_SHUTDOWN,
+ PCMDEVICE_BIN_BLK_PRE_POWER_UP,
+ PCMDEVICE_BIN_BLK_POST_SHUTDOWN
+};
+
+enum pcmdevice_fw_state {
+ PCMDEVICE_FW_LOAD_OK = 0,
+ PCMDEVICE_FW_LOAD_FAILED
+};
+
+struct pcmdevice_regbin_hdr {
+ unsigned int img_sz;
+ unsigned int checksum;
+ unsigned int binary_version_num;
+ unsigned int drv_fw_version;
+ unsigned int timestamp;
+ unsigned char plat_type;
+ unsigned char dev_family;
+ unsigned char reserve;
+ unsigned char ndev;
+ unsigned char devs[PCMDEVICE_MAX_REGBIN_DEVICES];
+ unsigned int nconfig;
+ unsigned int config_size[PCMDEVICE_CONFIG_SUM];
+};
+
+struct pcmdevice_block_data {
+ unsigned char dev_idx;
+ unsigned char block_type;
+ unsigned short yram_checksum;
+ unsigned int block_size;
+ unsigned int n_subblks;
+ unsigned char *regdata;
+};
+
+struct pcmdevice_config_info {
+ char cfg_name[64];
+ unsigned int nblocks;
+ unsigned int real_nblocks;
+ unsigned char active_dev;
+ struct pcmdevice_block_data **blk_data;
+};
+
+struct pcmdevice_regbin {
+ struct pcmdevice_regbin_hdr fw_hdr;
+ int ncfgs;
+ struct pcmdevice_config_info **cfg_info;
+};
+
+struct pcmdevice_irqinfo {
+ int gpio;
+ int nmb;
+};
+
+struct pcmdevice_priv {
+ struct snd_soc_component *component;
+ struct i2c_client *client;
+ struct device *dev;
+ struct mutex codec_lock;
+ struct gpio_desc *hw_rst;
+ struct regmap *regmap;
+ struct pcmdevice_regbin regbin;
+ struct pcmdevice_irqinfo irq_info;
+ unsigned int addr[PCMDEVICE_MAX_I2C_DEVICES];
+ unsigned int chip_id;
+ int cur_conf;
+ int fw_state;
+ int ndev;
+ unsigned char bin_name[PCMDEVICE_BIN_FILENAME_LEN];
+ unsigned char dev_name[I2C_NAME_SIZE];
+};
+
+/* mixer control */
+struct pcmdevice_mixer_control {
+ int max;
+ int reg;
+ unsigned int dev_no;
+ unsigned int shift;
+ unsigned int invert;
+};
+struct pcmdev_ctrl_info {
+ const unsigned int *gain;
+ const struct pcmdevice_mixer_control *pcmdev_ctrl;
+ unsigned int ctrl_array_size;
+ snd_kcontrol_get_t *get;
+ snd_kcontrol_put_t *put;
+ int pcmdev_ctrl_name_id;
+};
+#endif /* __PCM6240_H__ */
--
2.34.1
^ permalink raw reply related
* [PATCH v8 0/4] ASoc: PCM6240: mixer-test report
From: Shenghao Ding @ 2024-04-03 0:31 UTC (permalink / raw)
To: linux-kernel
Cc: lgirdwood, broonie, robh+dt, krzysztof.kozlowski+dt, conor+dt,
linux-sound, devicetree, perex, tiwai, 13916275206, mohit.chawla,
soyer, jkhuang3, tiwai, pdjuandi, manisha.agrawal, aviel,
hnagalla, praneeth, Baojun.Xu, Shenghao Ding
mixer-test report:
root@am335x-evm:/bin# mixer-test
TAP version 13
# Card 0 - TI BeagleBone Black (TI BeagleBone Black)
1..7
ok 1 get_value.0.0
# 0.0 pcmd3180-i2c-2 Profile id
ok 2 name.0.0
ok 3 write_default.0.0
ok 4 write_valid.0.0
ok 5 write_invalid.0.0
ok 6 event_missing.0.0
ok 7 event_spurious.0.0
# Totals: pass:7 fail:0 xfail:0 xpass:0 skip:0 error:0
root@am335x-evm:/bin#
Signed-off-by: Shenghao Ding <shenghao-ding@ti.com>
---
Shenghao Ding (4):
ASoc: PCM6240: Create PCM6240 Family driver code
ASoc: PCM6240: Create header file for PCM6240 Family driver code
ASoc: PCM6240: Add compile item for PCM6240 Family driver
ASoc: dt-bindings: PCM6240: Add initial DT binding
.../devicetree/bindings/sound/ti,pcm6240.yaml | 177 ++
sound/soc/codecs/Kconfig | 10 +
sound/soc/codecs/Makefile | 2 +
sound/soc/codecs/pcm6240.c | 2070 +++++++++++++++++
sound/soc/codecs/pcm6240.h | 236 ++
5 files changed, 2495 insertions(+)
create mode 100644 Documentation/devicetree/bindings/sound/ti,pcm6240.yaml
create mode 100644 sound/soc/codecs/pcm6240.c
create mode 100644 sound/soc/codecs/pcm6240.h
--
2.34.1
^ permalink raw reply
* [PATCH v8 1/4] ASoc: PCM6240: Create PCM6240 Family driver code
From: Shenghao Ding @ 2024-04-03 0:31 UTC (permalink / raw)
To: linux-kernel
Cc: lgirdwood, broonie, robh+dt, krzysztof.kozlowski+dt, conor+dt,
linux-sound, devicetree, perex, tiwai, 13916275206, mohit.chawla,
soyer, jkhuang3, tiwai, pdjuandi, manisha.agrawal, aviel,
hnagalla, praneeth, Baojun.Xu, Shenghao Ding
In-Reply-To: <20240403003159.389-1-shenghao-ding@ti.com>
PCM6240 driver implements a flexible and configurable setting for register
and filter coefficients, to one, two or even multiple PCM6240 Family Audio
chips.
Signed-off-by: Shenghao Ding <shenghao-ding@ti.com>
---
v8:
- use some reasonable format of changelog.
- | Reported-by: kernel test robot <lkp@intel.com>
| Reported-by: Dan Carpenter <dan.carpenter@linaro.org>
| Closes: https://lore.kernel.org/r/202404021225.mx5KlUlV-lkp@intel.com/
- Link to v7: https://lore.kernel.org/all/20240331021835.1470-2-shenghao-ding@ti.com/
---
sound/soc/codecs/pcm6240.c | 2070 ++++++++++++++++++++++++++++++++++++
1 file changed, 2070 insertions(+)
create mode 100644 sound/soc/codecs/pcm6240.c
diff --git a/sound/soc/codecs/pcm6240.c b/sound/soc/codecs/pcm6240.c
new file mode 100644
index 000000000000..6e7bcb17454c
--- /dev/null
+++ b/sound/soc/codecs/pcm6240.c
@@ -0,0 +1,2070 @@
+// SPDX-License-Identifier: GPL-2.0
+//
+// ALSA SoC Texas Instruments PCM6240 Family Audio ADC/DAC Device
+//
+// Copyright (C) 2022 - 2024 Texas Instruments Incorporated
+// https://www.ti.com
+//
+// The PCM6240 driver implements a flexible and configurable
+// algo coefficient setting for one, two, or even multiple
+// PCM6240 Family chips.
+//
+// Author: Shenghao Ding <shenghao-ding@ti.com>
+//
+
+#include <asm/unaligned.h>
+#include <linux/firmware.h>
+#include <linux/gpio.h>
+#include <linux/i2c.h>
+#include <linux/module.h>
+#include <linux/of_irq.h>
+#include <linux/regmap.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/tlv.h>
+
+#include "pcm6240.h"
+
+static const struct i2c_device_id pcmdevice_i2c_id[] = {
+ { "adc3120", ADC3120 },
+ { "adc5120", ADC5120 },
+ { "adc6120", ADC6120 },
+ { "dix4192", DIX4192 },
+ { "pcm1690", PCM1690 },
+ { "pcm3120", PCM3120 },
+ { "pcm3140", PCM3140 },
+ { "pcm5120", PCM5120 },
+ { "pcm5140", PCM5140 },
+ { "pcm6120", PCM6120 },
+ { "pcm6140", PCM6140 },
+ { "pcm6240", PCM6240 },
+ { "pcm6260", PCM6260 },
+ { "pcm9211", PCM9211 },
+ { "pcmd3140", PCMD3140 },
+ { "pcmd3180", PCMD3180 },
+ { "pcmd512x", PCMD512X },
+ { "taa5212", TAA5212 },
+ { "taa5412", TAA5412 },
+ { "tad5212", TAD5212 },
+ { "tad5412", TAD5412 },
+ {}
+};
+MODULE_DEVICE_TABLE(i2c, pcmdevice_i2c_id);
+
+static const char *const pcmdev_ctrl_name[] = {
+ "%s-i2c-%d-dev%d-ch%d-ana-gain",
+ "%s-i2c-%d-dev%d-ch%d-digi-gain",
+ "%s-i2c-%d-dev%d-ch%d-fine-gain",
+};
+
+static const char *const pcmdev_ctrl_name_with_prefix[] = {
+ "%s-dev%d-ch%d-ana-gain",
+ "%s-dev%d-ch%d-digi-gain",
+ "%s-dev%d-ch%d-fine-gain",
+};
+
+static const struct pcmdevice_mixer_control adc5120_analog_gain_ctl[] = {
+ {
+ .shift = 1,
+ .reg = ADC5120_REG_CH1_ANALOG_GAIN,
+ .max = 0x54,
+ .invert = 0,
+ },
+ {
+ .shift = 1,
+ .reg = ADC5120_REG_CH2_ANALOG_GAIN,
+ .max = 0x54,
+ .invert = 0,
+ }
+};
+
+static const struct pcmdevice_mixer_control adc5120_digi_gain_ctl[] = {
+ {
+ .shift = 0,
+ .reg = ADC5120_REG_CH1_DIGITAL_GAIN,
+ .max = 0xff,
+ .invert = 0,
+ },
+ {
+ .shift = 0,
+ .reg = ADC5120_REG_CH2_DIGITAL_GAIN,
+ .max = 0xff,
+ .invert = 0,
+ }
+};
+
+static const struct pcmdevice_mixer_control pcm1690_digi_gain_ctl[] = {
+ {
+ .shift = 0,
+ .reg = PCM1690_REG_CH1_DIGITAL_GAIN,
+ .max = 0xff,
+ .invert = 0,
+ },
+ {
+ .shift = 0,
+ .reg = PCM1690_REG_CH2_DIGITAL_GAIN,
+ .max = 0xff,
+ .invert = 0,
+ },
+ {
+ .shift = 0,
+ .reg = PCM1690_REG_CH3_DIGITAL_GAIN,
+ .max = 0xff,
+ .invert = 0,
+ },
+ {
+ .shift = 0,
+ .reg = PCM1690_REG_CH4_DIGITAL_GAIN,
+ .max = 0xff,
+ .invert = 0,
+ },
+ {
+ .shift = 0,
+ .reg = PCM1690_REG_CH5_DIGITAL_GAIN,
+ .max = 0xff,
+ .invert = 0,
+ },
+ {
+ .shift = 0,
+ .reg = PCM1690_REG_CH6_DIGITAL_GAIN,
+ .max = 0xff,
+ .invert = 0,
+ },
+ {
+ .shift = 0,
+ .reg = PCM1690_REG_CH7_DIGITAL_GAIN,
+ .max = 0xff,
+ .invert = 0,
+ },
+ {
+ .shift = 0,
+ .reg = PCM1690_REG_CH8_DIGITAL_GAIN,
+ .max = 0xff,
+ .invert = 0,
+ }
+};
+
+static const struct pcmdevice_mixer_control pcm6240_analog_gain_ctl[] = {
+ {
+ .shift = 2,
+ .reg = PCM6240_REG_CH1_ANALOG_GAIN,
+ .max = 0x42,
+ .invert = 0,
+ },
+ {
+ .shift = 2,
+ .reg = PCM6240_REG_CH2_ANALOG_GAIN,
+ .max = 0x42,
+ .invert = 0,
+ },
+ {
+ .shift = 2,
+ .reg = PCM6240_REG_CH3_ANALOG_GAIN,
+ .max = 0x42,
+ .invert = 0,
+ },
+ {
+ .shift = 2,
+ .reg = PCM6240_REG_CH4_ANALOG_GAIN,
+ .max = 0x42,
+ .invert = 0,
+ }
+};
+
+static const struct pcmdevice_mixer_control pcm6240_digi_gain_ctl[] = {
+ {
+ .shift = 0,
+ .reg = PCM6240_REG_CH1_DIGITAL_GAIN,
+ .max = 0xff,
+ .invert = 0,
+ },
+ {
+ .shift = 0,
+ .reg = PCM6240_REG_CH2_DIGITAL_GAIN,
+ .max = 0xff,
+ .invert = 0,
+ },
+ {
+ .shift = 0,
+ .reg = PCM6240_REG_CH3_DIGITAL_GAIN,
+ .max = 0xff,
+ .invert = 0,
+ },
+ {
+ .shift = 0,
+ .reg = PCM6240_REG_CH4_DIGITAL_GAIN,
+ .max = 0xff,
+ .invert = 0,
+ }
+};
+
+static const struct pcmdevice_mixer_control pcm6260_analog_gain_ctl[] = {
+ {
+ .shift = 2,
+ .reg = PCM6260_REG_CH1_ANALOG_GAIN,
+ .max = 0x42,
+ .invert = 0,
+ },
+ {
+ .shift = 2,
+ .reg = PCM6260_REG_CH2_ANALOG_GAIN,
+ .max = 0x42,
+ .invert = 0,
+ },
+ {
+ .shift = 2,
+ .reg = PCM6260_REG_CH3_ANALOG_GAIN,
+ .max = 0x42,
+ .invert = 0,
+ },
+ {
+ .shift = 2,
+ .reg = PCM6260_REG_CH4_ANALOG_GAIN,
+ .max = 0x42,
+ .invert = 0,
+ },
+ {
+ .shift = 2,
+ .reg = PCM6260_REG_CH5_ANALOG_GAIN,
+ .max = 0x42,
+ .invert = 0,
+ },
+ {
+ .shift = 2,
+ .reg = PCM6260_REG_CH6_ANALOG_GAIN,
+ .max = 0x42,
+ .invert = 0,
+ }
+};
+
+static const struct pcmdevice_mixer_control pcm6260_digi_gain_ctl[] = {
+ {
+ .shift = 0,
+ .reg = PCM6260_REG_CH1_DIGITAL_GAIN,
+ .max = 0xff,
+ .invert = 0,
+ },
+ {
+ .shift = 0,
+ .reg = PCM6260_REG_CH2_DIGITAL_GAIN,
+ .max = 0xff,
+ .invert = 0,
+ },
+ {
+ .shift = 0,
+ .reg = PCM6260_REG_CH3_DIGITAL_GAIN,
+ .max = 0xff,
+ .invert = 0,
+ },
+ {
+ .shift = 0,
+ .reg = PCM6260_REG_CH4_DIGITAL_GAIN,
+ .max = 0xff,
+ .invert = 0,
+ },
+ {
+ .shift = 0,
+ .reg = PCM6260_REG_CH5_DIGITAL_GAIN,
+ .max = 0xff,
+ .invert = 0,
+ },
+ {
+ .shift = 0,
+ .reg = PCM6260_REG_CH6_DIGITAL_GAIN,
+ .max = 0xff,
+ .invert = 0,
+ }
+};
+
+static const struct pcmdevice_mixer_control pcm9211_digi_gain_ctl[] = {
+ {
+ .shift = 0,
+ .reg = PCM9211_REG_CH1_DIGITAL_GAIN,
+ .max = 0xff,
+ .invert = 0,
+ },
+ {
+ .shift = 0,
+ .reg = PCM9211_REG_CH2_DIGITAL_GAIN,
+ .max = 0xff,
+ .invert = 0,
+ }
+};
+
+static const struct pcmdevice_mixer_control pcmd3140_digi_gain_ctl[] = {
+ {
+ .shift = 0,
+ .reg = PCMD3140_REG_CH1_DIGITAL_GAIN,
+ .max = 0xff,
+ .invert = 0,
+ },
+ {
+ .shift = 0,
+ .reg = PCMD3140_REG_CH2_DIGITAL_GAIN,
+ .max = 0xff,
+ .invert = 0,
+ },
+ {
+ .shift = 0,
+ .reg = PCMD3140_REG_CH3_DIGITAL_GAIN,
+ .max = 0xff,
+ .invert = 0,
+ },
+ {
+ .shift = 0,
+ .reg = PCMD3140_REG_CH4_DIGITAL_GAIN,
+ .max = 0xff,
+ .invert = 0,
+ }
+};
+
+static const struct pcmdevice_mixer_control pcmd3180_digi_gain_ctl[] = {
+ {
+ .shift = 0,
+ .reg = PCMD3180_REG_CH1_DIGITAL_GAIN,
+ .max = 0xff,
+ .invert = 0,
+ },
+ {
+ .shift = 0,
+ .reg = PCMD3180_REG_CH2_DIGITAL_GAIN,
+ .max = 0xff,
+ .invert = 0,
+ },
+ {
+ .shift = 0,
+ .reg = PCMD3180_REG_CH3_DIGITAL_GAIN,
+ .max = 0xff,
+ .invert = 0,
+ },
+ {
+ .shift = 0,
+ .reg = PCMD3180_REG_CH4_DIGITAL_GAIN,
+ .max = 0xff,
+ .invert = 0,
+ },
+ {
+ .shift = 0,
+ .reg = PCMD3180_REG_CH5_DIGITAL_GAIN,
+ .max = 0xff,
+ .invert = 0,
+ },
+ {
+ .shift = 0,
+ .reg = PCMD3180_REG_CH6_DIGITAL_GAIN,
+ .max = 0xff,
+ .invert = 0,
+ },
+ {
+ .shift = 0,
+ .reg = PCMD3180_REG_CH7_DIGITAL_GAIN,
+ .max = 0xff,
+ .invert = 0,
+ },
+ {
+ .shift = 0,
+ .reg = PCMD3180_REG_CH8_DIGITAL_GAIN,
+ .max = 0xff,
+ .invert = 0,
+ }
+};
+
+static const struct pcmdevice_mixer_control taa5412_digi_vol_ctl[] = {
+ {
+ .shift = 0,
+ .reg = TAA5412_REG_CH1_DIGITAL_VOLUME,
+ .max = 0xff,
+ .invert = 0,
+ },
+ {
+ .shift = 0,
+ .reg = TAA5412_REG_CH2_DIGITAL_VOLUME,
+ .max = 0xff,
+ .invert = 0,
+ },
+ {
+ .shift = 0,
+ .reg = TAA5412_REG_CH3_DIGITAL_VOLUME,
+ .max = 0xff,
+ .invert = 0,
+ },
+ {
+ .shift = 0,
+ .reg = TAA5412_REG_CH4_DIGITAL_VOLUME,
+ .max = 0xff,
+ .invert = 0,
+ },
+};
+
+static const struct pcmdevice_mixer_control taa5412_fine_gain_ctl[] = {
+ {
+ .shift = 4,
+ .reg = TAA5412_REG_CH1_FINE_GAIN,
+ .max = 0xf,
+ .invert = 0,
+ },
+ {
+ .shift = 4,
+ .reg = TAA5412_REG_CH2_FINE_GAIN,
+ .max = 0xf,
+ .invert = 0,
+ },
+ {
+ .shift = 4,
+ .reg = TAA5412_REG_CH3_FINE_GAIN,
+ .max = 0xf,
+ .invert = 4,
+ },
+ {
+ .shift = 0,
+ .reg = TAA5412_REG_CH4_FINE_GAIN,
+ .max = 0xf,
+ .invert = 4,
+ },
+};
+
+static const DECLARE_TLV_DB_MINMAX_MUTE(pcmd3140_dig_gain_tlv,
+ -10000, 2700);
+static const DECLARE_TLV_DB_MINMAX_MUTE(pcm1690_fine_dig_gain_tlv,
+ -12750, 0);
+static const DECLARE_TLV_DB_MINMAX_MUTE(pcm1690_dig_gain_tlv,
+ -25500, 0);
+static const DECLARE_TLV_DB_MINMAX_MUTE(pcm9211_dig_gain_tlv,
+ -11450, 2000);
+static const DECLARE_TLV_DB_MINMAX_MUTE(adc5120_fgain_tlv,
+ -10050, 2700);
+static const DECLARE_TLV_DB_LINEAR(adc5120_chgain_tlv, 0, 4200);
+static const DECLARE_TLV_DB_MINMAX_MUTE(pcm6260_fgain_tlv,
+ -10000, 2700);
+static const DECLARE_TLV_DB_LINEAR(pcm6260_chgain_tlv, 0, 4200);
+static const DECLARE_TLV_DB_MINMAX_MUTE(taa5412_dig_vol_tlv,
+ -8050, 4700);
+static const DECLARE_TLV_DB_LINEAR(taa5412_fine_gain_tlv,
+ -80, 70);
+
+static int pcmdev_change_dev(struct pcmdevice_priv *pcm_priv,
+ unsigned short dev_no)
+{
+ struct i2c_client *client = (struct i2c_client *)pcm_priv->client;
+ struct regmap *map = pcm_priv->regmap;
+ int ret;
+
+ if (client->addr == pcm_priv->addr[dev_no])
+ return 0;
+
+ client->addr = pcm_priv->addr[dev_no];
+ /* All pcmdevices share the same regmap, clear the page
+ * inside regmap once switching to another pcmdevice.
+ * Register 0 at any pages inside pcmdevice is the same
+ * one for page-switching.
+ */
+ ret = regmap_write(map, PCMDEVICE_PAGE_SELECT, 0);
+ if (ret < 0)
+ dev_err(pcm_priv->dev, "%s: err = %d\n", __func__, ret);
+
+ return ret;
+}
+
+static int pcmdev_dev_read(struct pcmdevice_priv *pcm_dev,
+ unsigned int dev_no, unsigned int reg, unsigned int *val)
+{
+ struct regmap *map = pcm_dev->regmap;
+ int ret;
+
+ if (dev_no >= pcm_dev->ndev) {
+ dev_err(pcm_dev->dev, "%s: no such channel(%d)\n", __func__,
+ dev_no);
+ return -EINVAL;
+ }
+
+ ret = pcmdev_change_dev(pcm_dev, dev_no);
+ if (ret < 0) {
+ dev_err(pcm_dev->dev, "%s: chg dev err = %d\n", __func__, ret);
+ return ret;
+ }
+
+ ret = regmap_read(map, reg, val);
+ if (ret < 0)
+ dev_err(pcm_dev->dev, "%s: err = %d\n", __func__, ret);
+
+ return ret;
+}
+
+static int pcmdev_dev_update_bits(struct pcmdevice_priv *pcm_dev,
+ unsigned int dev_no, unsigned int reg, unsigned int mask,
+ unsigned int value)
+{
+ struct regmap *map = pcm_dev->regmap;
+ int ret;
+
+ if (dev_no >= pcm_dev->ndev) {
+ dev_err(pcm_dev->dev, "%s: no such channel(%d)\n", __func__,
+ dev_no);
+ return -EINVAL;
+ }
+
+ ret = pcmdev_change_dev(pcm_dev, dev_no);
+ if (ret < 0) {
+ dev_err(pcm_dev->dev, "%s: chg dev err = %d\n", __func__, ret);
+ return ret;
+ }
+
+ ret = regmap_update_bits(map, reg, mask, value);
+ if (ret < 0)
+ dev_err(pcm_dev->dev, "%s: update_bits err=%d\n",
+ __func__, ret);
+
+ return ret;
+}
+
+static int pcmdev_get_volsw(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol, int vol_ctrl_type)
+{
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
+ struct pcmdevice_priv *pcm_dev =
+ snd_soc_component_get_drvdata(component);
+ struct pcmdevice_mixer_control *mc =
+ (struct pcmdevice_mixer_control *)kcontrol->private_value;
+ int max = mc->max, ret;
+ unsigned int mask = BIT(fls(max)) - 1;
+ unsigned int dev_no = mc->dev_no;
+ unsigned int shift = mc->shift;
+ unsigned int reg = mc->reg;
+ unsigned int val;
+
+ mutex_lock(&pcm_dev->codec_lock);
+
+ if (pcm_dev->chip_id == PCM1690) {
+ ret = pcmdev_dev_read(pcm_dev, dev_no, PCM1690_REG_MODE_CTRL,
+ &val);
+ if (ret) {
+ dev_err(pcm_dev->dev, "%s: read mode err=%d\n",
+ __func__, ret);
+ goto out;
+ }
+ val &= PCM1690_REG_MODE_CTRL_DAMS_MSK;
+ /* Set to wide-range mode, before using vol ctrl. */
+ if (!val && vol_ctrl_type == PCMDEV_PCM1690_VOL_CTRL) {
+ ucontrol->value.integer.value[0] = -25500;
+ goto out;
+ }
+ /* Set to fine mode, before using fine vol ctrl. */
+ if (val && vol_ctrl_type == PCMDEV_PCM1690_FINE_VOL_CTRL) {
+ ucontrol->value.integer.value[0] = -12750;
+ goto out;
+ }
+ }
+
+ ret = pcmdev_dev_read(pcm_dev, dev_no, reg, &val);
+ if (ret) {
+ dev_err(pcm_dev->dev, "%s: read err=%d\n",
+ __func__, ret);
+ goto out;
+ }
+
+ val = (val >> shift) & mask;
+ val = (val > max) ? max : val;
+ val = mc->invert ? max - val : val;
+ ucontrol->value.integer.value[0] = val;
+out:
+ mutex_unlock(&pcm_dev->codec_lock);
+ return ret;
+}
+
+static int pcmdevice_get_volsw(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ return pcmdev_get_volsw(kcontrol, ucontrol, PCMDEV_GENERIC_VOL_CTRL);
+}
+
+static int pcm1690_get_volsw(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ return pcmdev_get_volsw(kcontrol, ucontrol, PCMDEV_PCM1690_VOL_CTRL);
+}
+
+static int pcm1690_get_finevolsw(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ return pcmdev_get_volsw(kcontrol, ucontrol,
+ PCMDEV_PCM1690_FINE_VOL_CTRL);
+}
+
+static int pcmdev_put_volsw(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol, int vol_ctrl_type)
+{
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
+ struct pcmdevice_priv *pcm_dev =
+ snd_soc_component_get_drvdata(component);
+ struct pcmdevice_mixer_control *mc =
+ (struct pcmdevice_mixer_control *)kcontrol->private_value;
+ int max = mc->max, err = 1;
+ unsigned int mask = BIT(fls(max)) - 1;
+ unsigned int dev_no = mc->dev_no;
+ unsigned int shift = mc->shift;
+ unsigned int val, val_mask;
+ unsigned int reg = mc->reg;
+
+ mutex_lock(&pcm_dev->codec_lock);
+ val = ucontrol->value.integer.value[0] & mask;
+ val = (val > max) ? max : val;
+ val = mc->invert ? max - val : val;
+ val_mask = mask << shift;
+ val = val << shift;
+
+ switch (vol_ctrl_type) {
+ case PCMDEV_PCM1690_VOL_CTRL:
+ val_mask |= PCM1690_REG_MODE_CTRL_DAMS_MSK;
+ val |= PCM1690_REG_MODE_CTRL_DAMS_WIDE_RANGE;
+ break;
+ case PCMDEV_PCM1690_FINE_VOL_CTRL:
+ val_mask |= PCM1690_REG_MODE_CTRL_DAMS_MSK;
+ val |= PCM1690_REG_MODE_CTRL_DAMS_FINE_STEP;
+ break;
+ }
+
+ err = pcmdev_dev_update_bits(pcm_dev, dev_no, reg, val_mask, val);
+ if (err) {
+ dev_err(pcm_dev->dev, "%s: update_bits err = %d\n",
+ __func__, err);
+ err = 0;
+ }
+
+ mutex_unlock(&pcm_dev->codec_lock);
+ return err;
+}
+
+static int pcmdevice_put_volsw(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ return pcmdev_put_volsw(kcontrol, ucontrol, PCMDEV_GENERIC_VOL_CTRL);
+}
+
+static int pcm1690_put_volsw(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ return pcmdev_put_volsw(kcontrol, ucontrol, PCMDEV_PCM1690_VOL_CTRL);
+}
+
+static int pcm1690_put_finevolsw(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ return pcmdev_put_volsw(kcontrol, ucontrol,
+ PCMDEV_PCM1690_FINE_VOL_CTRL);
+}
+
+static const struct pcmdev_ctrl_info pcmdev_gain_ctl_info[][2] = {
+ // ADC3120
+ {
+ {
+ .gain = adc5120_chgain_tlv,
+ .pcmdev_ctrl = adc5120_analog_gain_ctl,
+ .ctrl_array_size = ARRAY_SIZE(adc5120_analog_gain_ctl),
+ .get = pcmdevice_get_volsw,
+ .put = pcmdevice_put_volsw,
+ .pcmdev_ctrl_name_id = 0,
+ },
+ {
+ .gain = adc5120_fgain_tlv,
+ .pcmdev_ctrl = adc5120_digi_gain_ctl,
+ .ctrl_array_size = ARRAY_SIZE(adc5120_digi_gain_ctl),
+ .get = pcmdevice_get_volsw,
+ .put = pcmdevice_put_volsw,
+ .pcmdev_ctrl_name_id = 1,
+ },
+ },
+ // ADC5120
+ {
+ {
+ .gain = adc5120_chgain_tlv,
+ .pcmdev_ctrl = adc5120_analog_gain_ctl,
+ .ctrl_array_size = ARRAY_SIZE(adc5120_analog_gain_ctl),
+ .get = pcmdevice_get_volsw,
+ .put = pcmdevice_put_volsw,
+ .pcmdev_ctrl_name_id = 0,
+ },
+ {
+ .gain = adc5120_fgain_tlv,
+ .pcmdev_ctrl = adc5120_digi_gain_ctl,
+ .ctrl_array_size = ARRAY_SIZE(adc5120_digi_gain_ctl),
+ .get = pcmdevice_get_volsw,
+ .put = pcmdevice_put_volsw,
+ .pcmdev_ctrl_name_id = 1,
+ },
+ },
+ // ADC6120
+ {
+ {
+ .gain = adc5120_chgain_tlv,
+ .pcmdev_ctrl = adc5120_analog_gain_ctl,
+ .ctrl_array_size = ARRAY_SIZE(adc5120_analog_gain_ctl),
+ .get = pcmdevice_get_volsw,
+ .put = pcmdevice_put_volsw,
+ .pcmdev_ctrl_name_id = 0,
+ },
+ {
+ .gain = adc5120_fgain_tlv,
+ .pcmdev_ctrl = adc5120_digi_gain_ctl,
+ .ctrl_array_size = ARRAY_SIZE(adc5120_digi_gain_ctl),
+ .get = pcmdevice_get_volsw,
+ .put = pcmdevice_put_volsw,
+ .pcmdev_ctrl_name_id = 1,
+ },
+ },
+ // DIX4192
+ {
+ {
+ .ctrl_array_size = 0,
+ },
+ {
+ .ctrl_array_size = 0,
+ },
+ },
+ // PCM1690
+ {
+ {
+ .gain = pcm1690_fine_dig_gain_tlv,
+ .pcmdev_ctrl = pcm1690_digi_gain_ctl,
+ .ctrl_array_size = ARRAY_SIZE(pcm1690_digi_gain_ctl),
+ .get = pcm1690_get_volsw,
+ .put = pcm1690_put_volsw,
+ .pcmdev_ctrl_name_id = 1,
+ },
+ {
+ .gain = pcm1690_dig_gain_tlv,
+ .pcmdev_ctrl = pcm1690_digi_gain_ctl,
+ .ctrl_array_size = ARRAY_SIZE(pcm1690_digi_gain_ctl),
+ .get = pcm1690_get_finevolsw,
+ .put = pcm1690_put_finevolsw,
+ .pcmdev_ctrl_name_id = 2,
+ },
+ },
+ // PCM3120
+ {
+ {
+ .gain = adc5120_chgain_tlv,
+ .pcmdev_ctrl = adc5120_analog_gain_ctl,
+ .ctrl_array_size = ARRAY_SIZE(adc5120_analog_gain_ctl),
+ .get = pcmdevice_get_volsw,
+ .put = pcmdevice_put_volsw,
+ .pcmdev_ctrl_name_id = 0,
+ },
+ {
+ .gain = adc5120_fgain_tlv,
+ .pcmdev_ctrl = adc5120_digi_gain_ctl,
+ .ctrl_array_size = ARRAY_SIZE(adc5120_digi_gain_ctl),
+ .get = pcmdevice_get_volsw,
+ .put = pcmdevice_put_volsw,
+ .pcmdev_ctrl_name_id = 1,
+ },
+ },
+ // PCM3140
+ {
+ {
+ .gain = pcm6260_chgain_tlv,
+ .pcmdev_ctrl = pcm6240_analog_gain_ctl,
+ .ctrl_array_size = ARRAY_SIZE(pcm6240_analog_gain_ctl),
+ .get = pcmdevice_get_volsw,
+ .put = pcmdevice_put_volsw,
+ .pcmdev_ctrl_name_id = 0,
+ },
+ {
+ .gain = pcm6260_fgain_tlv,
+ .pcmdev_ctrl = pcm6240_digi_gain_ctl,
+ .ctrl_array_size = ARRAY_SIZE(pcm6240_digi_gain_ctl),
+ .get = pcmdevice_get_volsw,
+ .put = pcmdevice_put_volsw,
+ .pcmdev_ctrl_name_id = 1,
+ },
+ },
+ // PCM5120
+ {
+ {
+ .gain = adc5120_chgain_tlv,
+ .pcmdev_ctrl = adc5120_analog_gain_ctl,
+ .ctrl_array_size = ARRAY_SIZE(adc5120_analog_gain_ctl),
+ .get = pcmdevice_get_volsw,
+ .put = pcmdevice_put_volsw,
+ .pcmdev_ctrl_name_id = 0,
+ },
+ {
+ .gain = adc5120_fgain_tlv,
+ .pcmdev_ctrl = adc5120_digi_gain_ctl,
+ .ctrl_array_size = ARRAY_SIZE(adc5120_digi_gain_ctl),
+ .get = pcmdevice_get_volsw,
+ .put = pcmdevice_put_volsw,
+ .pcmdev_ctrl_name_id = 1,
+ },
+ },
+ // PCM5140
+ {
+ {
+ .gain = pcm6260_chgain_tlv,
+ .pcmdev_ctrl = pcm6240_analog_gain_ctl,
+ .ctrl_array_size = ARRAY_SIZE(pcm6240_analog_gain_ctl),
+ .get = pcmdevice_get_volsw,
+ .put = pcmdevice_put_volsw,
+ .pcmdev_ctrl_name_id = 0,
+ },
+ {
+ .gain = pcm6260_fgain_tlv,
+ .pcmdev_ctrl = pcm6240_digi_gain_ctl,
+ .ctrl_array_size = ARRAY_SIZE(pcm6240_digi_gain_ctl),
+ .get = pcmdevice_get_volsw,
+ .put = pcmdevice_put_volsw,
+ .pcmdev_ctrl_name_id = 1,
+ },
+ },
+ // PCM6120
+ {
+ {
+ .gain = adc5120_chgain_tlv,
+ .pcmdev_ctrl = adc5120_analog_gain_ctl,
+ .ctrl_array_size = ARRAY_SIZE(adc5120_analog_gain_ctl),
+ .get = pcmdevice_get_volsw,
+ .put = pcmdevice_put_volsw,
+ .pcmdev_ctrl_name_id = 0,
+ },
+ {
+ .gain = adc5120_fgain_tlv,
+ .pcmdev_ctrl = adc5120_digi_gain_ctl,
+ .ctrl_array_size = ARRAY_SIZE(adc5120_digi_gain_ctl),
+ .get = pcmdevice_get_volsw,
+ .put = pcmdevice_put_volsw,
+ .pcmdev_ctrl_name_id = 1,
+ },
+ },
+ // PCM6140
+ {
+ {
+ .gain = pcm6260_chgain_tlv,
+ .pcmdev_ctrl = pcm6240_analog_gain_ctl,
+ .ctrl_array_size = ARRAY_SIZE(pcm6240_analog_gain_ctl),
+ .get = pcmdevice_get_volsw,
+ .put = pcmdevice_put_volsw,
+ .pcmdev_ctrl_name_id = 0,
+ },
+ {
+ .gain = pcm6260_fgain_tlv,
+ .pcmdev_ctrl = pcm6240_digi_gain_ctl,
+ .ctrl_array_size = ARRAY_SIZE(pcm6240_digi_gain_ctl),
+ .get = pcmdevice_get_volsw,
+ .put = pcmdevice_put_volsw,
+ .pcmdev_ctrl_name_id = 1,
+ },
+ },
+ // PCM6240
+ {
+ {
+ .gain = pcm6260_chgain_tlv,
+ .pcmdev_ctrl = pcm6240_analog_gain_ctl,
+ .ctrl_array_size = ARRAY_SIZE(pcm6240_analog_gain_ctl),
+ .get = pcmdevice_get_volsw,
+ .put = pcmdevice_put_volsw,
+ .pcmdev_ctrl_name_id = 0,
+ },
+ {
+ .gain = pcm6260_fgain_tlv,
+ .pcmdev_ctrl = pcm6240_digi_gain_ctl,
+ .ctrl_array_size = ARRAY_SIZE(pcm6240_digi_gain_ctl),
+ .get = pcmdevice_get_volsw,
+ .put = pcmdevice_put_volsw,
+ .pcmdev_ctrl_name_id = 1,
+ },
+ },
+ // PCM6260
+ {
+ {
+ .gain = pcm6260_chgain_tlv,
+ .pcmdev_ctrl = pcm6260_analog_gain_ctl,
+ .ctrl_array_size = ARRAY_SIZE(pcm6260_analog_gain_ctl),
+ .get = pcmdevice_get_volsw,
+ .put = pcmdevice_put_volsw,
+ .pcmdev_ctrl_name_id = 0,
+ },
+ {
+ .gain = pcm6260_fgain_tlv,
+ .pcmdev_ctrl = pcm6260_digi_gain_ctl,
+ .ctrl_array_size = ARRAY_SIZE(pcm6260_digi_gain_ctl),
+ .get = pcmdevice_get_volsw,
+ .put = pcmdevice_put_volsw,
+ .pcmdev_ctrl_name_id = 1,
+ },
+ },
+ // PCM9211
+ {
+ {
+ .ctrl_array_size = 0,
+ },
+ {
+ .gain = pcm9211_dig_gain_tlv,
+ .pcmdev_ctrl = pcm9211_digi_gain_ctl,
+ .ctrl_array_size = ARRAY_SIZE(pcm9211_digi_gain_ctl),
+ .get = pcmdevice_get_volsw,
+ .put = pcmdevice_put_volsw,
+ .pcmdev_ctrl_name_id = 1,
+ },
+
+ },
+ // PCMD3140
+ {
+ {
+ .ctrl_array_size = 0,
+ },
+ {
+ .gain = pcmd3140_dig_gain_tlv,
+ .pcmdev_ctrl = pcmd3140_digi_gain_ctl,
+ .ctrl_array_size = ARRAY_SIZE(pcmd3140_digi_gain_ctl),
+ .get = pcmdevice_get_volsw,
+ .put = pcmdevice_put_volsw,
+ .pcmdev_ctrl_name_id = 1,
+ },
+ },
+ // PCMD3180
+ {
+ {
+ .ctrl_array_size = 0,
+ },
+ {
+ .gain = pcmd3140_dig_gain_tlv,
+ .pcmdev_ctrl = pcmd3180_digi_gain_ctl,
+ .ctrl_array_size = ARRAY_SIZE(pcmd3180_digi_gain_ctl),
+ .get = pcmdevice_get_volsw,
+ .put = pcmdevice_put_volsw,
+ .pcmdev_ctrl_name_id = 1,
+ },
+ },
+ // PCMD512X
+ {
+ {
+ .ctrl_array_size = 0,
+ },
+ {
+ .ctrl_array_size = 0,
+ },
+ },
+ // TAA5212
+ {
+ {
+ .gain = taa5412_fine_gain_tlv,
+ .pcmdev_ctrl = taa5412_fine_gain_ctl,
+ .ctrl_array_size = ARRAY_SIZE(taa5412_fine_gain_ctl),
+ .get = pcmdevice_get_volsw,
+ .put = pcmdevice_put_volsw,
+ .pcmdev_ctrl_name_id = 2,
+ },
+ {
+ .gain = taa5412_dig_vol_tlv,
+ .pcmdev_ctrl = taa5412_digi_vol_ctl,
+ .ctrl_array_size = ARRAY_SIZE(taa5412_digi_vol_ctl),
+ .get = pcmdevice_get_volsw,
+ .put = pcmdevice_put_volsw,
+ .pcmdev_ctrl_name_id = 1,
+ },
+ },
+ // TAA5412
+ {
+ {
+ .gain = taa5412_fine_gain_tlv,
+ .pcmdev_ctrl = taa5412_fine_gain_ctl,
+ .ctrl_array_size = ARRAY_SIZE(taa5412_fine_gain_ctl),
+ .get = pcmdevice_get_volsw,
+ .put = pcmdevice_put_volsw,
+ .pcmdev_ctrl_name_id = 2,
+ },
+ {
+ .gain = taa5412_dig_vol_tlv,
+ .pcmdev_ctrl = taa5412_digi_vol_ctl,
+ .ctrl_array_size = ARRAY_SIZE(taa5412_digi_vol_ctl),
+ .get = pcmdevice_get_volsw,
+ .put = pcmdevice_put_volsw,
+ .pcmdev_ctrl_name_id = 1,
+ },
+ },
+ // TAD5212
+ {
+ {
+ .ctrl_array_size = 0,
+ },
+ {
+ .ctrl_array_size = 0,
+ },
+ },
+ // TAD5412
+ {
+ {
+ .ctrl_array_size = 0,
+ },
+ {
+ .ctrl_array_size = 0,
+ },
+ },
+};
+
+static int pcmdev_dev_bulk_write(struct pcmdevice_priv *pcm_dev,
+ unsigned int dev_no, unsigned int reg, unsigned char *data,
+ unsigned int len)
+{
+ struct regmap *map = pcm_dev->regmap;
+ int ret;
+
+ if (dev_no >= pcm_dev->ndev) {
+ dev_err(pcm_dev->dev, "%s: no such channel(%d)\n", __func__,
+ dev_no);
+ return -EINVAL;
+ }
+
+ ret = pcmdev_change_dev(pcm_dev, dev_no);
+ if (ret < 0) {
+ dev_err(pcm_dev->dev, "%s: chg dev err = %d\n", __func__, ret);
+ return ret;
+ }
+
+ ret = regmap_bulk_write(map, reg, data, len);
+ if (ret < 0)
+ dev_err(pcm_dev->dev, "%s: bulk_write err = %d\n", __func__,
+ ret);
+
+ return ret;
+}
+
+static int pcmdev_dev_write(struct pcmdevice_priv *pcm_dev,
+ unsigned int dev_no, unsigned int reg, unsigned int value)
+{
+ struct regmap *map = pcm_dev->regmap;
+ int ret;
+
+ if (dev_no >= pcm_dev->ndev) {
+ dev_err(pcm_dev->dev, "%s: no such channel(%d)\n", __func__,
+ dev_no);
+ return -EINVAL;
+ }
+
+ ret = pcmdev_change_dev(pcm_dev, dev_no);
+ if (ret < 0) {
+ dev_err(pcm_dev->dev, "%s: chg dev err = %d\n", __func__, ret);
+ return ret;
+ }
+
+ ret = regmap_write(map, reg, value);
+ if (ret < 0)
+ dev_err(pcm_dev->dev, "%s: err = %d\n", __func__, ret);
+
+ return ret;
+}
+
+static int pcmdevice_info_profile(
+ struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *uinfo)
+{
+ struct snd_soc_component *codec
+ = snd_soc_kcontrol_component(kcontrol);
+ struct pcmdevice_priv *pcm_dev =
+ snd_soc_component_get_drvdata(codec);
+
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+ uinfo->count = 1;
+ uinfo->value.integer.min = 0;
+ uinfo->value.integer.max = max(0, pcm_dev->regbin.ncfgs - 1);
+
+ return 0;
+}
+
+static int pcmdevice_get_profile_id(
+ struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *codec
+ = snd_soc_kcontrol_component(kcontrol);
+ struct pcmdevice_priv *pcm_dev =
+ snd_soc_component_get_drvdata(codec);
+
+ ucontrol->value.integer.value[0] = pcm_dev->cur_conf;
+
+ return 0;
+}
+
+static int pcmdevice_set_profile_id(
+ struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *codec
+ = snd_soc_kcontrol_component(kcontrol);
+ struct pcmdevice_priv *pcm_dev =
+ snd_soc_component_get_drvdata(codec);
+ int nr_profile = ucontrol->value.integer.value[0];
+ int max = pcm_dev->regbin.ncfgs - 1;
+ int ret = 0;
+
+ nr_profile = clamp(nr_profile, 0, max);
+
+ if (pcm_dev->cur_conf != nr_profile) {
+ pcm_dev->cur_conf = nr_profile;
+ ret = 1;
+ }
+
+ return ret;
+}
+
+static int pcmdevice_info_volsw(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *uinfo)
+{
+ struct pcmdevice_mixer_control *mc =
+ (struct pcmdevice_mixer_control *)kcontrol->private_value;
+
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+ uinfo->count = 1;
+ uinfo->value.integer.min = 0;
+ uinfo->value.integer.max = mc->max;
+ return 0;
+}
+
+static void pcm9211_sw_rst(struct pcmdevice_priv *pcm_dev)
+{
+ int ret, i;
+
+ for (i = 0; i < pcm_dev->ndev; i++) {
+ ret = pcmdev_dev_update_bits(pcm_dev, i,
+ PCM9211_REG_SW_CTRL, PCM9211_REG_SW_CTRL_MRST_MSK,
+ PCM9211_REG_SW_CTRL_MRST);
+ if (ret < 0)
+ dev_err(pcm_dev->dev, "%s: dev %d swreset fail %d\n",
+ __func__, i, ret);
+ }
+}
+
+static void pcmdevice_sw_rst(struct pcmdevice_priv *pcm_dev)
+{
+ int ret, i;
+
+ for (i = 0; i < pcm_dev->ndev; i++) {
+ ret = pcmdev_dev_write(pcm_dev, i, PCMDEVICE_REG_SWRESET,
+ PCMDEVICE_REG_SWRESET_RESET);
+ if (ret < 0)
+ dev_err(pcm_dev->dev, "%s: dev %d swreset fail %d\n",
+ __func__, i, ret);
+ }
+}
+
+static struct pcmdevice_config_info *pcmdevice_add_config(void *ctxt,
+ const unsigned char *config_data, unsigned int config_size,
+ int *status)
+{
+ struct pcmdevice_priv *pcm_dev = (struct pcmdevice_priv *)ctxt;
+ struct pcmdevice_config_info *cfg_info;
+ struct pcmdevice_block_data **bk_da;
+ unsigned int config_offset = 0, i;
+
+ cfg_info = kzalloc(sizeof(struct pcmdevice_config_info), GFP_KERNEL);
+ if (!cfg_info) {
+ *status = -ENOMEM;
+ goto out;
+ }
+
+ if (pcm_dev->regbin.fw_hdr.binary_version_num >= 0x105) {
+ if (config_offset + 64 > (int)config_size) {
+ *status = -EINVAL;
+ dev_err(pcm_dev->dev,
+ "%s: cfg_name out of boundary\n", __func__);
+ goto out;
+ }
+ memcpy(cfg_info->cfg_name, &config_data[config_offset], 64);
+ config_offset += 64;
+ }
+
+ if (config_offset + 4 > config_size) {
+ *status = -EINVAL;
+ dev_err(pcm_dev->dev, "%s: nblocks out of boundary\n",
+ __func__);
+ goto out;
+ }
+ cfg_info->nblocks =
+ get_unaligned_be32(&config_data[config_offset]);
+ config_offset += 4;
+
+ bk_da = cfg_info->blk_data = kcalloc(cfg_info->nblocks,
+ sizeof(struct pcmdevice_block_data *), GFP_KERNEL);
+ if (!bk_da) {
+ *status = -ENOMEM;
+ goto out;
+ }
+ cfg_info->real_nblocks = 0;
+ for (i = 0; i < cfg_info->nblocks; i++) {
+ if (config_offset + 12 > config_size) {
+ *status = -EINVAL;
+ dev_err(pcm_dev->dev,
+ "%s: out of boundary i = %d nblocks = %u\n",
+ __func__, i, cfg_info->nblocks);
+ break;
+ }
+ bk_da[i] = kzalloc(sizeof(struct pcmdevice_block_data),
+ GFP_KERNEL);
+ if (!bk_da[i]) {
+ *status = -ENOMEM;
+ break;
+ }
+ bk_da[i]->dev_idx = config_data[config_offset];
+ config_offset++;
+
+ bk_da[i]->block_type = config_data[config_offset];
+ config_offset++;
+
+ if (bk_da[i]->block_type == PCMDEVICE_BIN_BLK_PRE_POWER_UP) {
+ if (bk_da[i]->dev_idx == 0)
+ cfg_info->active_dev =
+ (1 << pcm_dev->ndev) - 1;
+ else
+ cfg_info->active_dev =
+ 1 << (bk_da[i]->dev_idx - 1);
+ }
+
+ bk_da[i]->yram_checksum =
+ get_unaligned_be16(&config_data[config_offset]);
+ config_offset += 2;
+ bk_da[i]->block_size =
+ get_unaligned_be32(&config_data[config_offset]);
+ config_offset += 4;
+
+ bk_da[i]->n_subblks =
+ get_unaligned_be32(&config_data[config_offset]);
+
+ config_offset += 4;
+
+ if (config_offset + bk_da[i]->block_size > config_size) {
+ *status = -EINVAL;
+ dev_err(pcm_dev->dev,
+ "%s: out of boundary: i = %d blks = %u\n",
+ __func__, i, cfg_info->nblocks);
+ break;
+ }
+
+ bk_da[i]->regdata = kmemdup(&config_data[config_offset],
+ bk_da[i]->block_size, GFP_KERNEL);
+ if (!bk_da[i]->regdata) {
+ *status = -ENOMEM;
+ goto out;
+ }
+ config_offset += bk_da[i]->block_size;
+ cfg_info->real_nblocks += 1;
+ }
+out:
+ return cfg_info;
+}
+
+static int pcmdev_gain_ctrl_add(struct pcmdevice_priv *pcm_dev,
+ int dev_no, int ctl_id)
+{
+ struct i2c_adapter *adap = pcm_dev->client->adapter;
+ struct snd_soc_component *comp = pcm_dev->component;
+ struct pcmdevice_mixer_control *pcmdev_ctrl;
+ struct snd_kcontrol_new *pcmdev_controls;
+ int ret, mix_index = 0, name_id, chn;
+ unsigned int id = pcm_dev->chip_id;
+ const int nr_chn =
+ pcmdev_gain_ctl_info[id][ctl_id].ctrl_array_size;
+ const char *ctrl_name;
+ char *name;
+
+ if (!nr_chn) {
+ dev_dbg(pcm_dev->dev, "%s: no gain ctrl for %s\n", __func__,
+ pcm_dev->dev_name);
+ return 0;
+ }
+
+ pcmdev_controls = devm_kzalloc(pcm_dev->dev,
+ nr_chn * sizeof(struct snd_kcontrol_new), GFP_KERNEL);
+ if (!pcmdev_controls)
+ return -ENOMEM;
+
+ name_id = pcmdev_gain_ctl_info[id][ctl_id].pcmdev_ctrl_name_id;
+
+ if (comp->name_prefix)
+ ctrl_name = pcmdev_ctrl_name_with_prefix[name_id];
+ else
+ ctrl_name = pcmdev_ctrl_name[name_id];
+
+ for (chn = 1; chn <= nr_chn; chn++) {
+ name = devm_kzalloc(pcm_dev->dev,
+ SNDRV_CTL_ELEM_ID_NAME_MAXLEN, GFP_KERNEL);
+ if (!name) {
+ ret = -ENOMEM;
+ goto out;
+ }
+ if (comp->name_prefix)
+ scnprintf(name, SNDRV_CTL_ELEM_ID_NAME_MAXLEN,
+ ctrl_name, comp->name_prefix, dev_no, chn);
+ else
+ scnprintf(name, SNDRV_CTL_ELEM_ID_NAME_MAXLEN,
+ ctrl_name, pcm_dev->dev_name, adap->nr,
+ dev_no, chn);
+ pcmdev_controls[mix_index].tlv.p =
+ pcmdev_gain_ctl_info[id][ctl_id].gain;
+ pcmdev_ctrl = devm_kmemdup(pcm_dev->dev,
+ &pcmdev_gain_ctl_info[id][ctl_id].pcmdev_ctrl[chn - 1],
+ sizeof(*pcmdev_ctrl), GFP_KERNEL);
+ if (!pcmdev_ctrl) {
+ ret = -ENOMEM;
+ goto out;
+ }
+ pcmdev_ctrl->dev_no = dev_no;
+ pcmdev_controls[mix_index].private_value =
+ (unsigned long)pcmdev_ctrl;
+ pcmdev_controls[mix_index].name = name;
+ pcmdev_controls[mix_index].access =
+ SNDRV_CTL_ELEM_ACCESS_TLV_READ |
+ SNDRV_CTL_ELEM_ACCESS_READWRITE;
+ pcmdev_controls[mix_index].iface =
+ SNDRV_CTL_ELEM_IFACE_MIXER;
+ pcmdev_controls[mix_index].info = pcmdevice_info_volsw;
+ pcmdev_controls[mix_index].get =
+ pcmdev_gain_ctl_info[id][ctl_id].get;
+ pcmdev_controls[mix_index].put =
+ pcmdev_gain_ctl_info[id][ctl_id].put;
+ mix_index++;
+ }
+
+ ret = snd_soc_add_component_controls(comp, pcmdev_controls, mix_index);
+ if (ret)
+ dev_err(pcm_dev->dev, "%s: add_controls err = %d\n",
+ __func__, ret);
+out:
+ return ret;
+}
+
+static int pcmdev_profile_ctrl_add(struct pcmdevice_priv *pcm_dev)
+{
+ struct snd_soc_component *comp = pcm_dev->component;
+ struct i2c_adapter *adap = pcm_dev->client->adapter;
+ struct snd_kcontrol_new *pcmdev_ctrl;
+ char *name;
+ int ret;
+
+ pcmdev_ctrl = devm_kzalloc(pcm_dev->dev,
+ sizeof(struct snd_kcontrol_new), GFP_KERNEL);
+ if (!pcmdev_ctrl)
+ return -ENOMEM;
+
+ /* Create a mixer item for selecting the active profile */
+ name = devm_kzalloc(pcm_dev->dev, SNDRV_CTL_ELEM_ID_NAME_MAXLEN,
+ GFP_KERNEL);
+ if (!name)
+ return -ENOMEM;
+
+ if (comp->name_prefix)
+ scnprintf(name, SNDRV_CTL_ELEM_ID_NAME_MAXLEN,
+ "%s Profile id", comp->name_prefix);
+ else
+ scnprintf(name, SNDRV_CTL_ELEM_ID_NAME_MAXLEN,
+ "%s-i2c-%d Profile id", pcm_dev->dev_name, adap->nr);
+ pcmdev_ctrl->name = name;
+ pcmdev_ctrl->iface = SNDRV_CTL_ELEM_IFACE_MIXER;
+ pcmdev_ctrl->info = pcmdevice_info_profile;
+ pcmdev_ctrl->get = pcmdevice_get_profile_id;
+ pcmdev_ctrl->put = pcmdevice_set_profile_id;
+
+ ret = snd_soc_add_component_controls(comp, pcmdev_ctrl, 1);
+ if (ret)
+ dev_err(pcm_dev->dev, "%s: add_controls err = %d\n",
+ __func__, ret);
+
+ return ret;
+}
+
+static void pcmdevice_config_info_remove(void *ctxt)
+{
+ struct pcmdevice_priv *pcm_dev = (struct pcmdevice_priv *) ctxt;
+ struct pcmdevice_regbin *regbin = &(pcm_dev->regbin);
+ struct pcmdevice_config_info **cfg_info = regbin->cfg_info;
+ int i, j;
+
+ if (!cfg_info)
+ return;
+ for (i = 0; i < regbin->ncfgs; i++) {
+ if (!cfg_info[i])
+ continue;
+ if (cfg_info[i]->blk_data) {
+ for (j = 0; j < (int)cfg_info[i]->real_nblocks; j++) {
+ if (!cfg_info[i]->blk_data[j])
+ continue;
+ kfree(cfg_info[i]->blk_data[j]->regdata);
+ kfree(cfg_info[i]->blk_data[j]);
+ }
+ kfree(cfg_info[i]->blk_data);
+ }
+ kfree(cfg_info[i]);
+ }
+ kfree(cfg_info);
+}
+
+static int pcmdev_regbin_ready(const struct firmware *fmw, void *ctxt)
+{
+ struct pcmdevice_config_info **cfg_info;
+ struct pcmdevice_priv *pcm_dev = ctxt;
+ struct pcmdevice_regbin_hdr *fw_hdr;
+ struct pcmdevice_regbin *regbin;
+ unsigned int total_config_sz = 0;
+ int offset = 0, ret = 0, i;
+ unsigned char *buf;
+
+ regbin = &(pcm_dev->regbin);
+ fw_hdr = &(regbin->fw_hdr);
+ if (!fmw || !fmw->data) {
+ dev_err(pcm_dev->dev, "%s: failed to read %s\n",
+ __func__, pcm_dev->bin_name);
+ pcm_dev->fw_state = PCMDEVICE_FW_LOAD_FAILED;
+ ret = -EINVAL;
+ goto out;
+ }
+ buf = (unsigned char *)fmw->data;
+
+ fw_hdr->img_sz = get_unaligned_be32(&buf[offset]);
+ offset += 4;
+ if (fw_hdr->img_sz != fmw->size) {
+ dev_err(pcm_dev->dev, "%s: file size(%d) not match %u",
+ __func__, (int)fmw->size, fw_hdr->img_sz);
+ pcm_dev->fw_state = PCMDEVICE_FW_LOAD_FAILED;
+ ret = -EINVAL;
+ goto out;
+ }
+
+ fw_hdr->checksum = get_unaligned_be32(&buf[offset]);
+ offset += 4;
+ fw_hdr->binary_version_num = get_unaligned_be32(&buf[offset]);
+ if (fw_hdr->binary_version_num < 0x103) {
+ dev_err(pcm_dev->dev, "%s: bin version 0x%04x is out of date",
+ __func__, fw_hdr->binary_version_num);
+ pcm_dev->fw_state = PCMDEVICE_FW_LOAD_FAILED;
+ ret = -EINVAL;
+ goto out;
+ }
+ offset += 4;
+ fw_hdr->drv_fw_version = get_unaligned_be32(&buf[offset]);
+ offset += 8;
+ fw_hdr->plat_type = buf[offset];
+ offset += 1;
+ fw_hdr->dev_family = buf[offset];
+ offset += 1;
+ fw_hdr->reserve = buf[offset];
+ offset += 1;
+ fw_hdr->ndev = buf[offset];
+ offset += 1;
+ if (fw_hdr->ndev != pcm_dev->ndev) {
+ dev_err(pcm_dev->dev, "%s: invalid ndev(%u)\n", __func__,
+ fw_hdr->ndev);
+ pcm_dev->fw_state = PCMDEVICE_FW_LOAD_FAILED;
+ ret = -EINVAL;
+ goto out;
+ }
+
+ if (offset + PCMDEVICE_MAX_REGBIN_DEVICES > fw_hdr->img_sz) {
+ dev_err(pcm_dev->dev, "%s: devs out of boundary!\n", __func__);
+ pcm_dev->fw_state = PCMDEVICE_FW_LOAD_FAILED;
+ ret = -EINVAL;
+ goto out;
+ }
+
+ for (i = 0; i < PCMDEVICE_MAX_REGBIN_DEVICES; i++, offset++)
+ fw_hdr->devs[i] = buf[offset];
+
+ fw_hdr->nconfig = get_unaligned_be32(&buf[offset]);
+ offset += 4;
+
+ for (i = 0; i < PCMDEVICE_CONFIG_SUM; i++) {
+ fw_hdr->config_size[i] = get_unaligned_be32(&buf[offset]);
+ offset += 4;
+ total_config_sz += fw_hdr->config_size[i];
+ }
+
+ if (fw_hdr->img_sz - total_config_sz != (unsigned int)offset) {
+ dev_err(pcm_dev->dev, "%s: bin file error!\n", __func__);
+ pcm_dev->fw_state = PCMDEVICE_FW_LOAD_FAILED;
+ ret = -EINVAL;
+ goto out;
+ }
+ cfg_info = kcalloc(fw_hdr->nconfig, sizeof(*cfg_info), GFP_KERNEL);
+ if (!cfg_info) {
+ pcm_dev->fw_state = PCMDEVICE_FW_LOAD_FAILED;
+ ret = -ENOMEM;
+ goto out;
+ }
+ regbin->cfg_info = cfg_info;
+ regbin->ncfgs = 0;
+ for (i = 0; i < (int)fw_hdr->nconfig; i++) {
+ cfg_info[i] = pcmdevice_add_config(ctxt, &buf[offset],
+ fw_hdr->config_size[i], &ret);
+ if (ret) {
+ /* In case the bin file is partially destroyed. */
+ if (regbin->ncfgs == 0)
+ pcm_dev->fw_state = PCMDEVICE_FW_LOAD_FAILED;
+ break;
+ }
+ offset += (int)fw_hdr->config_size[i];
+ regbin->ncfgs += 1;
+ }
+
+out:
+ if (pcm_dev->fw_state == PCMDEVICE_FW_LOAD_FAILED) {
+ dev_err(pcm_dev->dev,
+ "%s: remove config due to fw load error!\n", __func__);
+ pcmdevice_config_info_remove(pcm_dev);
+ }
+
+ return ret;
+}
+
+static int pcmdevice_comp_probe(struct snd_soc_component *comp)
+{
+ struct pcmdevice_priv *pcm_dev = snd_soc_component_get_drvdata(comp);
+ struct i2c_adapter *adap = pcm_dev->client->adapter;
+ const struct firmware *fw_entry = NULL;
+ int ret, i, j;
+
+ mutex_lock(&pcm_dev->codec_lock);
+
+ pcm_dev->component = comp;
+
+ for (i = 0; i < pcm_dev->ndev; i++) {
+ for (j = 0; j < 2; j++) {
+ ret = pcmdev_gain_ctrl_add(pcm_dev, i, j);
+ if (ret < 0)
+ goto out;
+ }
+ }
+
+ if (comp->name_prefix) {
+ /* There's name_prefix defined in DTS. Bin file name will be
+ * name_prefix.bin stores the firmware including register setting and
+ * params for different filters inside chips, it must be copied into
+ * firmware folder. The same types of pcmdevices sitting on the same
+ * i2c bus will be aggregated as one single codec, all of them share
+ * the same bin file.
+ */
+ scnprintf(pcm_dev->bin_name, PCMDEVICE_BIN_FILENAME_LEN,
+ "%s.bin", comp->name_prefix);
+ } else {
+ /* There's NO name_prefix defined in DTS. Bin file name will be
+ * device-name[defined in pcmdevice_i2c_id]-i2c-bus_id[0,1,...,N]-
+ * sum[1,...,4]dev.bin stores the firmware including register setting
+ * and params for different filters inside chips, it must be copied
+ * into firmware folder. The same types of pcmdevices sitting on the
+ * same i2c bus will be aggregated as one single codec, all of them
+ * share the same bin file.
+ */
+ scnprintf(pcm_dev->bin_name, PCMDEVICE_BIN_FILENAME_LEN,
+ "%s-i2c-%d-%udev.bin", pcm_dev->dev_name, adap->nr,
+ pcm_dev->ndev);
+ }
+
+ ret = request_firmware(&fw_entry, pcm_dev->bin_name, pcm_dev->dev);
+ if (ret) {
+ dev_err(pcm_dev->dev, "%s: request %s err = %d\n", __func__,
+ pcm_dev->bin_name, ret);
+ goto out;
+ }
+
+ ret = pcmdev_regbin_ready(fw_entry, pcm_dev);
+ if (ret) {
+ dev_err(pcm_dev->dev, "%s: %s parse err = %d\n", __func__,
+ pcm_dev->bin_name, ret);
+ goto out;
+ }
+ ret = pcmdev_profile_ctrl_add(pcm_dev);
+out:
+ if (fw_entry)
+ release_firmware(fw_entry);
+
+ mutex_unlock(&pcm_dev->codec_lock);
+ return ret;
+}
+
+
+static void pcmdevice_comp_remove(struct snd_soc_component *codec)
+{
+ struct pcmdevice_priv *pcm_dev = snd_soc_component_get_drvdata(codec);
+
+ if (!pcm_dev)
+ return;
+ mutex_lock(&pcm_dev->codec_lock);
+ pcmdevice_config_info_remove(pcm_dev);
+ mutex_unlock(&pcm_dev->codec_lock);
+}
+
+static const struct snd_soc_dapm_widget pcmdevice_dapm_widgets[] = {
+ SND_SOC_DAPM_AIF_IN("ASI", "ASI Playback", 0, SND_SOC_NOPM, 0, 0),
+ SND_SOC_DAPM_AIF_OUT("ASI1 OUT", "ASI1 Capture",
+ 0, SND_SOC_NOPM, 0, 0),
+ SND_SOC_DAPM_OUTPUT("OUT"),
+ SND_SOC_DAPM_INPUT("MIC"),
+};
+
+static const struct snd_soc_dapm_route pcmdevice_audio_map[] = {
+ {"OUT", NULL, "ASI"},
+ {"ASI1 OUT", NULL, "MIC"},
+};
+
+static const struct snd_soc_component_driver
+ soc_codec_driver_pcmdevice = {
+ .probe = pcmdevice_comp_probe,
+ .remove = pcmdevice_comp_remove,
+ .dapm_widgets = pcmdevice_dapm_widgets,
+ .num_dapm_widgets = ARRAY_SIZE(pcmdevice_dapm_widgets),
+ .dapm_routes = pcmdevice_audio_map,
+ .num_dapm_routes = ARRAY_SIZE(pcmdevice_audio_map),
+ .suspend_bias_off = 1,
+ .idle_bias_on = 0,
+ .use_pmdown_time = 1,
+ .endianness = 1,
+};
+
+static int pcmdevice_process_block(void *ctxt, unsigned char *data,
+ unsigned char dev_idx, int sublocksize)
+{
+ struct pcmdevice_priv *pcm_dev = (struct pcmdevice_priv *)ctxt;
+ int subblk_offset = 2, chn, chnend, ret;
+ unsigned char subblk_typ = data[1];
+
+ if (dev_idx) {
+ chn = dev_idx - 1;
+ chnend = dev_idx;
+ } else {
+ chn = 0;
+ chnend = pcm_dev->ndev;
+ }
+
+ for (; chn < chnend; chn++) {
+ switch (subblk_typ) {
+ case PCMDEVICE_CMD_SING_W: {
+ unsigned short len = get_unaligned_be16(&data[2]);
+ int i = 0;
+
+ subblk_offset += 2;
+ if (subblk_offset + 4 * len > sublocksize) {
+ dev_err(pcm_dev->dev,
+ "%s: byt wr out of boundary\n",
+ __func__);
+ break;
+ }
+
+ for (i = 0; i < len; i++) {
+ ret = pcmdev_dev_write(pcm_dev, chn,
+ PCMDEVICE_REG(data[subblk_offset + 1],
+ data[subblk_offset + 2]),
+ data[subblk_offset + 3]);
+ if (ret < 0)
+ dev_err(pcm_dev->dev,
+ "%s: single write error\n",
+ __func__);
+
+ subblk_offset += 4;
+ }
+ }
+ break;
+ case PCMDEVICE_CMD_BURST: {
+ unsigned short len = get_unaligned_be16(&data[2]);
+
+ subblk_offset += 2;
+ if (subblk_offset + 4 + len > sublocksize) {
+ dev_err(pcm_dev->dev,
+ "%s: burst Out of boundary\n",
+ __func__);
+ break;
+ }
+ if (len % 4) {
+ dev_err(pcm_dev->dev,
+ "%s: burst-len(%u) not div by 4\n",
+ __func__, len);
+ break;
+ }
+ ret = pcmdev_dev_bulk_write(pcm_dev, chn,
+ PCMDEVICE_REG(data[subblk_offset + 1],
+ data[subblk_offset + 2]),
+ &(data[subblk_offset + 4]), len);
+ if (ret < 0)
+ dev_err(pcm_dev->dev,
+ "%s: bulk_write err = %d\n",
+ __func__, ret);
+
+ subblk_offset += (len + 4);
+ }
+ break;
+ case PCMDEVICE_CMD_DELAY: {
+ unsigned int delay_time = 0;
+
+ if (subblk_offset + 2 > sublocksize) {
+ dev_err(pcm_dev->dev,
+ "%s: deley out of boundary\n",
+ __func__);
+ break;
+ }
+ delay_time = get_unaligned_be16(&data[2]) * 1000;
+ usleep_range(delay_time, delay_time + 50);
+ subblk_offset += 2;
+ }
+ break;
+ case PCMDEVICE_CMD_FIELD_W:
+ if (subblk_offset + 6 > sublocksize) {
+ dev_err(pcm_dev->dev,
+ "%s: bit write out of memory\n", __func__);
+ break;
+ }
+ ret = pcmdev_dev_update_bits(pcm_dev, chn,
+ PCMDEVICE_REG(data[subblk_offset + 3],
+ data[subblk_offset + 4]), data[subblk_offset + 1],
+ data[subblk_offset + 5]);
+ if (ret < 0)
+ dev_err(pcm_dev->dev, "%s: update_bits err = %d\n",
+ __func__, ret);
+
+ subblk_offset += 6;
+ break;
+ default:
+ break;
+ }
+ }
+
+ return subblk_offset;
+}
+
+static void pcmdevice_select_cfg_blk(void *ctxt, int conf_no,
+ unsigned char block_type)
+{
+ struct pcmdevice_priv *pcm_dev = (struct pcmdevice_priv *)ctxt;
+ struct pcmdevice_regbin *regbin = &(pcm_dev->regbin);
+ struct pcmdevice_config_info **cfg_info = regbin->cfg_info;
+ struct pcmdevice_block_data **blk_data;
+ int j, k;
+
+ if (conf_no >= regbin->ncfgs || conf_no < 0 || NULL == cfg_info) {
+ dev_err(pcm_dev->dev, "%s: conf_no should be less than %u\n",
+ __func__, regbin->ncfgs);
+ goto out;
+ }
+ blk_data = cfg_info[conf_no]->blk_data;
+
+ for (j = 0; j < (int)cfg_info[conf_no]->real_nblocks; j++) {
+ unsigned int length = 0, ret;
+
+ if (block_type > 5 || block_type < 2) {
+ dev_err(pcm_dev->dev,
+ "%s: block_type should be out of range\n",
+ __func__);
+ goto out;
+ }
+ if (block_type != blk_data[j]->block_type)
+ continue;
+
+ for (k = 0; k < (int)blk_data[j]->n_subblks; k++) {
+ ret = pcmdevice_process_block(pcm_dev,
+ blk_data[j]->regdata + length,
+ blk_data[j]->dev_idx,
+ blk_data[j]->block_size - length);
+ length += ret;
+ if (blk_data[j]->block_size < length) {
+ dev_err(pcm_dev->dev,
+ "%s: %u %u out of boundary\n",
+ __func__, length,
+ blk_data[j]->block_size);
+ break;
+ }
+ }
+ if (length != blk_data[j]->block_size)
+ dev_err(pcm_dev->dev, "%s: %u %u size is not same\n",
+ __func__, length, blk_data[j]->block_size);
+ }
+
+out:
+ return;
+}
+
+static int pcmdevice_mute(struct snd_soc_dai *dai, int mute, int stream)
+{
+ struct snd_soc_component *codec = dai->component;
+ struct pcmdevice_priv *pcm_dev = snd_soc_component_get_drvdata(codec);
+ unsigned char block_type;
+
+ if (pcm_dev->fw_state == PCMDEVICE_FW_LOAD_FAILED) {
+ dev_err(pcm_dev->dev, "%s: bin file not loaded\n", __func__);
+ return -EINVAL;
+ }
+
+ if (mute)
+ block_type = PCMDEVICE_BIN_BLK_PRE_SHUTDOWN;
+ else
+ block_type = PCMDEVICE_BIN_BLK_PRE_POWER_UP;
+
+ mutex_lock(&pcm_dev->codec_lock);
+ pcmdevice_select_cfg_blk(pcm_dev, pcm_dev->cur_conf, block_type);
+ mutex_unlock(&pcm_dev->codec_lock);
+ return 0;
+}
+
+static int pcmdevice_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params, struct snd_soc_dai *dai)
+{
+ struct pcmdevice_priv *pcm_dev = snd_soc_dai_get_drvdata(dai);
+ unsigned int fsrate;
+ unsigned int slot_width;
+ int bclk_rate;
+ int ret = 0;
+
+ fsrate = params_rate(params);
+ switch (fsrate) {
+ case 48000:
+ break;
+ case 44100:
+ break;
+ default:
+ dev_err(pcm_dev->dev, "%s: incorrect sample rate = %u\n",
+ __func__, fsrate);
+ ret = -EINVAL;
+ goto out;
+ }
+
+ slot_width = params_width(params);
+ switch (slot_width) {
+ case 16:
+ break;
+ case 20:
+ break;
+ case 24:
+ break;
+ case 32:
+ break;
+ default:
+ dev_err(pcm_dev->dev, "%s: incorrect slot width = %u\n",
+ __func__, slot_width);
+ ret = -EINVAL;
+ goto out;
+ }
+
+ bclk_rate = snd_soc_params_to_bclk(params);
+ if (bclk_rate < 0) {
+ dev_err(pcm_dev->dev, "%s: incorrect bclk rate = %d\n",
+ __func__, bclk_rate);
+ ret = bclk_rate;
+ }
+
+out:
+ return ret;
+}
+
+static const struct snd_soc_dai_ops pcmdevice_dai_ops = {
+ .mute_stream = pcmdevice_mute,
+ .hw_params = pcmdevice_hw_params,
+};
+
+static struct snd_soc_dai_driver pcmdevice_dai_driver[] = {
+ {
+ .name = "pcmdevice-codec",
+ .capture = {
+ .stream_name = "Capture",
+ .channels_min = 2,
+ .channels_max = PCMDEVICE_MAX_CHANNELS,
+ .rates = PCMDEVICE_RATES,
+ .formats = PCMDEVICE_FORMATS,
+ },
+ .playback = {
+ .stream_name = "Playback",
+ .channels_min = 2,
+ .channels_max = PCMDEVICE_MAX_CHANNELS,
+ .rates = PCMDEVICE_RATES,
+ .formats = PCMDEVICE_FORMATS,
+ },
+ .ops = &pcmdevice_dai_ops,
+ .symmetric_rate = 1,
+ }
+};
+
+#ifdef CONFIG_OF
+static const struct of_device_id pcmdevice_of_match[] = {
+ { .compatible = "ti,adc3120" },
+ { .compatible = "ti,adc5120" },
+ { .compatible = "ti,adc6120" },
+ { .compatible = "ti,dix4192" },
+ { .compatible = "ti,pcm1690" },
+ { .compatible = "ti,pcm3120" },
+ { .compatible = "ti,pcm3140" },
+ { .compatible = "ti,pcm5120" },
+ { .compatible = "ti,pcm5140" },
+ { .compatible = "ti,pcm6120" },
+ { .compatible = "ti,pcm6140" },
+ { .compatible = "ti,pcm6240" },
+ { .compatible = "ti,pcm6260" },
+ { .compatible = "ti,pcm9211" },
+ { .compatible = "ti,pcmd3140" },
+ { .compatible = "ti,pcmd3180" },
+ { .compatible = "ti,pcmd512x" },
+ { .compatible = "ti,taa5212" },
+ { .compatible = "ti,taa5412" },
+ { .compatible = "ti,tad5212" },
+ { .compatible = "ti,tad5412" },
+ {},
+};
+MODULE_DEVICE_TABLE(of, pcmdevice_of_match);
+#endif
+
+static const struct regmap_range_cfg pcmdevice_ranges[] = {
+ {
+ .range_min = 0,
+ .range_max = 256 * 128,
+ .selector_reg = PCMDEVICE_PAGE_SELECT,
+ .selector_mask = 0xff,
+ .selector_shift = 0,
+ .window_start = 0,
+ .window_len = 128,
+ },
+};
+
+static const struct regmap_config pcmdevice_i2c_regmap = {
+ .reg_bits = 8,
+ .val_bits = 8,
+ .cache_type = REGCACHE_MAPLE,
+ .ranges = pcmdevice_ranges,
+ .num_ranges = ARRAY_SIZE(pcmdevice_ranges),
+ .max_register = 256 * 128,
+};
+
+static void pcmdevice_remove(struct pcmdevice_priv *pcm_dev)
+{
+ if (gpio_is_valid(pcm_dev->irq_info.gpio)) {
+ gpio_free(pcm_dev->irq_info.gpio);
+ free_irq(pcm_dev->irq_info.nmb, pcm_dev);
+ }
+ mutex_destroy(&pcm_dev->codec_lock);
+}
+
+static int pcmdevice_i2c_probe(struct i2c_client *i2c)
+{
+ const struct i2c_device_id *id = i2c_match_id(pcmdevice_i2c_id, i2c);
+ struct pcmdevice_priv *pcm_dev;
+ struct device_node *np;
+ unsigned int dev_addrs[PCMDEVICE_MAX_I2C_DEVICES];
+ int ret = 0, i = 0, ndev = 0;
+#ifdef CONFIG_OF
+ const __be32 *reg, *reg_end;
+ int len, sw, aw;
+#endif
+
+ pcm_dev = devm_kzalloc(&i2c->dev, sizeof(*pcm_dev), GFP_KERNEL);
+ if (!pcm_dev) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ pcm_dev->chip_id = (id != NULL) ? id->driver_data : 0;
+
+ pcm_dev->dev = &i2c->dev;
+ pcm_dev->client = i2c;
+
+ if (pcm_dev->chip_id >= MAX_DEVICE)
+ pcm_dev->chip_id = 0;
+
+ strscpy(pcm_dev->dev_name, pcmdevice_i2c_id[pcm_dev->chip_id].name,
+ sizeof(pcm_dev->dev_name));
+
+ pcm_dev->regmap = devm_regmap_init_i2c(i2c, &pcmdevice_i2c_regmap);
+ if (IS_ERR(pcm_dev->regmap)) {
+ ret = PTR_ERR(pcm_dev->regmap);
+ dev_err(&i2c->dev, "%s: failed to allocate register map: %d\n",
+ __func__, ret);
+ goto out;
+ }
+
+ i2c_set_clientdata(i2c, pcm_dev);
+ mutex_init(&pcm_dev->codec_lock);
+ np = pcm_dev->dev->of_node;
+#ifdef CONFIG_OF
+ aw = of_n_addr_cells(np);
+ sw = of_n_size_cells(np);
+ if (sw == 0) {
+ reg = (const __be32 *)of_get_property(np,
+ "reg", &len);
+ reg_end = reg + len/sizeof(*reg);
+ ndev = 0;
+ do {
+ dev_addrs[ndev] = of_read_number(reg, aw);
+ reg += aw;
+ ndev++;
+ } while (reg < reg_end);
+ } else {
+ ndev = 1;
+ dev_addrs[0] = i2c->addr;
+ }
+#else
+ ndev = 1;
+ dev_addrs[0] = i2c->addr;
+#endif
+ pcm_dev->irq_info.gpio = of_irq_get(np, 0);
+
+ for (i = 0; i < ndev; i++)
+ pcm_dev->addr[i] = dev_addrs[i];
+
+ pcm_dev->ndev = ndev;
+
+ pcm_dev->hw_rst = devm_gpiod_get_optional(&i2c->dev,
+ "reset-gpios", GPIOD_OUT_HIGH);
+ /* No reset GPIO, no side-effect */
+ if (IS_ERR(pcm_dev->hw_rst)) {
+ if (pcm_dev->chip_id == PCM9211 || pcm_dev->chip_id == PCM1690)
+ pcm9211_sw_rst(pcm_dev);
+ else
+ pcmdevice_sw_rst(pcm_dev);
+ } else {
+ gpiod_set_value_cansleep(pcm_dev->hw_rst, 0);
+ usleep_range(500, 1000);
+ gpiod_set_value_cansleep(pcm_dev->hw_rst, 1);
+ }
+
+ if (pcm_dev->chip_id == PCM1690)
+ goto skip_interrupt;
+ if (gpio_is_valid(pcm_dev->irq_info.gpio)) {
+ dev_dbg(pcm_dev->dev, "irq-gpio = %d", pcm_dev->irq_info.gpio);
+
+ ret = gpio_request(pcm_dev->irq_info.gpio, "PCMDEV-IRQ");
+ if (!ret) {
+ int gpio = pcm_dev->irq_info.gpio;
+
+ gpio_direction_input(gpio);
+ pcm_dev->irq_info.nmb = gpio_to_irq(gpio);
+
+ } else
+ dev_err(pcm_dev->dev, "%s: GPIO %d request error\n",
+ __func__, pcm_dev->irq_info.gpio);
+ } else
+ dev_err(pcm_dev->dev, "Looking up irq-gpio failed %d\n",
+ pcm_dev->irq_info.gpio);
+
+skip_interrupt:
+ ret = devm_snd_soc_register_component(&i2c->dev,
+ &soc_codec_driver_pcmdevice, pcmdevice_dai_driver,
+ ARRAY_SIZE(pcmdevice_dai_driver));
+ if (ret < 0)
+ dev_err(&i2c->dev, "probe register comp failed %d\n", ret);
+
+out:
+ if (ret < 0)
+ pcmdevice_remove(pcm_dev);
+ return ret;
+}
+
+static void pcmdevice_i2c_remove(struct i2c_client *i2c)
+{
+ struct pcmdevice_priv *pcm_dev = i2c_get_clientdata(i2c);
+
+ pcmdevice_remove(pcm_dev);
+}
+
+static struct i2c_driver pcmdevice_i2c_driver = {
+ .driver = {
+ .name = "pcmdevice-codec",
+ .of_match_table = of_match_ptr(pcmdevice_of_match),
+ },
+ .probe = pcmdevice_i2c_probe,
+ .remove = pcmdevice_i2c_remove,
+ .id_table = pcmdevice_i2c_id,
+};
+module_i2c_driver(pcmdevice_i2c_driver);
+
+MODULE_AUTHOR("Shenghao Ding <shenghao-ding@ti.com>");
+MODULE_DESCRIPTION("ASoC PCM6240 Family Audio ADC/DAC Driver");
+MODULE_LICENSE("GPL");
--
2.34.1
^ permalink raw reply related
* [PATCH v8 3/4] ASoc: PCM6240: Add compile item for PCM6240 Family driver
From: Shenghao Ding @ 2024-04-03 0:31 UTC (permalink / raw)
To: linux-kernel
Cc: lgirdwood, broonie, robh+dt, krzysztof.kozlowski+dt, conor+dt,
linux-sound, devicetree, perex, tiwai, 13916275206, mohit.chawla,
soyer, jkhuang3, tiwai, pdjuandi, manisha.agrawal, aviel,
hnagalla, praneeth, Baojun.Xu, Shenghao Ding
In-Reply-To: <20240403003159.389-1-shenghao-ding@ti.com>
PCM6240 driver implements a flexible and configurable setting for register
and filter coefficients, to one, two or even multiple PCM6240 Family Audio
chips.
Signed-off-by: Shenghao Ding <shenghao-ding@ti.com>
---
v8:
- use some reasonable format of changelog.
- Link to v2: https://lore.kernel.org/all/20240126035855.1785-3-shenghao-ding@ti.com/
---
sound/soc/codecs/Kconfig | 10 ++++++++++
sound/soc/codecs/Makefile | 2 ++
2 files changed, 12 insertions(+)
diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig
index f78ea2f86fa6..0c35cdfd4a47 100644
--- a/sound/soc/codecs/Kconfig
+++ b/sound/soc/codecs/Kconfig
@@ -179,6 +179,7 @@ config SND_SOC_ALL_CODECS
imply SND_SOC_PCM5102A
imply SND_SOC_PCM512x_I2C
imply SND_SOC_PCM512x_SPI
+ imply SND_SOC_PCM6240
imply SND_SOC_PEB2466
imply SND_SOC_RK3328
imply SND_SOC_RK817
@@ -1422,6 +1423,15 @@ config SND_SOC_PCM512x_SPI
select SND_SOC_PCM512x
select REGMAP_SPI
+config SND_SOC_PCM6240
+ tristate "Texas Instruments PCM6240 Family Audio chips based on I2C"
+ depends on I2C
+ help
+ Enable support for Texas Instruments PCM6240 Family Audio chips.
+ Note the PCM6240 driver implements a flexible and configurable
+ setting for register and filter coefficients, to one, two or
+ even multiple PCM6240 Family Audio chips.
+
config SND_SOC_PEB2466
tristate "Infineon PEB2466 quad PCM codec"
depends on SPI
diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile
index 7c075539dc47..5553155b843b 100644
--- a/sound/soc/codecs/Makefile
+++ b/sound/soc/codecs/Makefile
@@ -204,6 +204,7 @@ snd-soc-pcm5102a-objs := pcm5102a.o
snd-soc-pcm512x-objs := pcm512x.o
snd-soc-pcm512x-i2c-objs := pcm512x-i2c.o
snd-soc-pcm512x-spi-objs := pcm512x-spi.o
+snd-soc-pcm6240-objs := pcm6240.o
snd-soc-peb2466-objs := peb2466.o
snd-soc-rk3328-objs := rk3328_codec.o
snd-soc-rk817-objs := rk817_codec.o
@@ -594,6 +595,7 @@ obj-$(CONFIG_SND_SOC_PCM5102A) += snd-soc-pcm5102a.o
obj-$(CONFIG_SND_SOC_PCM512x) += snd-soc-pcm512x.o
obj-$(CONFIG_SND_SOC_PCM512x_I2C) += snd-soc-pcm512x-i2c.o
obj-$(CONFIG_SND_SOC_PCM512x_SPI) += snd-soc-pcm512x-spi.o
+obj-$(CONFIG_SND_SOC_PCM6240) += snd-soc-pcm6240.o
obj-$(CONFIG_SND_SOC_PEB2466) += snd-soc-peb2466.o
obj-$(CONFIG_SND_SOC_RK3328) += snd-soc-rk3328.o
obj-$(CONFIG_SND_SOC_RK817) += snd-soc-rk817.o
--
2.34.1
^ permalink raw reply related
* [PATCH v8 4/4] ASoc: dt-bindings: PCM6240: Add initial DT binding
From: Shenghao Ding @ 2024-04-03 0:31 UTC (permalink / raw)
To: linux-kernel
Cc: lgirdwood, broonie, robh+dt, krzysztof.kozlowski+dt, conor+dt,
linux-sound, devicetree, perex, tiwai, 13916275206, mohit.chawla,
soyer, jkhuang3, tiwai, pdjuandi, manisha.agrawal, aviel,
hnagalla, praneeth, Baojun.Xu, Shenghao Ding, Rob Herring
In-Reply-To: <20240403003159.389-1-shenghao-ding@ti.com>
PCM6240 family chips are popular among audio customers, in spite of only a
portion of the functionality of codec, such as ADC or DAC, and so on, for
different Specifications, range from Personal Electric to Automotive
Electric, even some professional fields. Yet their audio performance is far
superior to the codec's, and cost is lower than codec, and much easier to
program than codec.
Reviewed-by: Rob Herring <robh@kernel.org>
Signed-off-by: Shenghao Ding <shenghao-ding@ti.com>
---
v8:
- use some reasonable format of changelog.
- Link to v5: https://lore.kernel.org/all/20240221051501.627-4-shenghao-ding@ti.com/
---
.../devicetree/bindings/sound/ti,pcm6240.yaml | 177 ++++++++++++++++++
1 file changed, 177 insertions(+)
create mode 100644 Documentation/devicetree/bindings/sound/ti,pcm6240.yaml
diff --git a/Documentation/devicetree/bindings/sound/ti,pcm6240.yaml b/Documentation/devicetree/bindings/sound/ti,pcm6240.yaml
new file mode 100644
index 000000000000..dd5b08e3d7a1
--- /dev/null
+++ b/Documentation/devicetree/bindings/sound/ti,pcm6240.yaml
@@ -0,0 +1,177 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+# Copyright (C) 2022 - 2024 Texas Instruments Incorporated
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/sound/ti,pcm6240.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Texas Instruments PCM6240 Family Audio ADC/DAC
+
+maintainers:
+ - Shenghao Ding <shenghao-ding@ti.com>
+
+description: |
+ The PCM6240 Family is a big family of Audio ADC/DAC for
+ different Specifications, range from Personal Electric
+ to Automotive Electric, even some professional fields.
+
+ Specifications about the audio chip can be found at:
+ https://www.ti.com/lit/gpn/tlv320adc3120
+ https://www.ti.com/lit/gpn/tlv320adc5120
+ https://www.ti.com/lit/gpn/tlv320adc6120
+ https://www.ti.com/lit/gpn/dix4192
+ https://www.ti.com/lit/gpn/pcm1690
+ https://www.ti.com/lit/gpn/pcm3120-q1
+ https://www.ti.com/lit/gpn/pcm3140-q1
+ https://www.ti.com/lit/gpn/pcm5120-q1
+ https://www.ti.com/lit/gpn/pcm6120-q1
+ https://www.ti.com/lit/gpn/pcm6260-q1
+ https://www.ti.com/lit/gpn/pcm9211
+ https://www.ti.com/lit/gpn/pcmd3140
+ https://www.ti.com/lit/gpn/pcmd3180
+ https://www.ti.com/lit/gpn/taa5212
+ https://www.ti.com/lit/gpn/tad5212
+
+properties:
+ compatible:
+ description: |
+ ti,adc3120: Stereo-channel, 768-kHz, Burr-Brown™ audio analog-to-
+ digital converter (ADC) with 106-dB SNR.
+
+ ti,adc5120: 2-Channel, 768-kHz, Burr-Brown™ Audio ADC with 120-dB SNR.
+
+ ti,adc6120: Stereo-channel, 768-kHz, Burr-Brown™ audio analog-to-
+ digital converter (ADC) with 123-dB SNR.
+
+ ti,dix4192: 216-kHz digital audio converter with Quad-Channel In
+ and One-Channel Out.
+
+ ti,pcm1690: Automotive Catalog 113dB SNR 8-Channel Audio DAC with
+ Differential Outputs.
+
+ ti,pcm3120: Automotive, stereo, 106-dB SNR, 768-kHz, low-power
+ software-controlled audio ADC.
+
+ ti,pcm3140: Automotive, Quad-Channel, 768-kHz, Burr-Brown™ Audio ADC
+ with 106-dB SNR.
+
+ ti,pcm5120: Automotive, stereo, 120-dB SNR, 768-kHz, low-power
+ software-controlled audio ADC.
+
+ ti,pcm5140: Automotive, Quad-Channel, 768-kHz, Burr-Brown™ Audio ADC
+ with 120-dB SNR.
+
+ ti,pcm6120: Automotive, stereo, 123-dB SNR, 768-kHz, low-power
+ software-controlled audio ADC.
+
+ ti,pcm6140: Automotive, Quad-Channel, 768-kHz, Burr-Brown™ Audio ADC
+ with 123-dB SNR.
+
+ ti,pcm6240: Automotive 4-ch audio ADC with integrated programmable mic
+ bias, boost and input diagnostics.
+
+ ti,pcm6260: Automotive 6-ch audio ADC with integrated programmable mic
+ bias, boost and input diagnostics.
+
+ ti,pcm9211: 216-kHz digital audio converter With Stereo ADC and
+ Routing.
+
+ ti,pcmd3140: Four-channel PDM-input to TDM or I2S output converter.
+
+ ti,pcmd3180: Eight-channel pulse-density-modulation input to TDM or
+ I2S output converter.
+
+ ti,taa5212: Low-power high-performance stereo audio ADC with 118-dB
+ dynamic range.
+
+ ti,tad5212: Low-power stereo audio DAC with 120-dB dynamic range.
+ oneOf:
+ - items:
+ - enum:
+ - ti,adc3120
+ - ti,adc5120
+ - ti,pcm3120
+ - ti,pcm5120
+ - ti,pcm6120
+ - const: ti,adc6120
+ - items:
+ - enum:
+ - ti,pcmd512x
+ - ti,pcm9211
+ - ti,taa5212
+ - ti,tad5212
+ - const: ti,adc6120
+ - items:
+ - enum:
+ - ti,pcm3140
+ - ti,pcm5140
+ - ti,dix4192
+ - ti,pcm6140
+ - ti,pcm6260
+ - const: ti,pcm6240
+ - items:
+ - enum:
+ - ti,pcmd3140
+ - ti,pcmd3180
+ - ti,pcm1690
+ - ti,taa5412
+ - ti,tad5412
+ - const: ti,pcm6240
+ - enum:
+ - ti,adc6120
+ - ti,pcm6240
+
+ reg:
+ description:
+ I2C address, in multiple pcmdevices case, all the i2c address
+ aggregate as one Audio Device to support multiple audio slots.
+ minItems: 1
+ maxItems: 4
+
+ reset-gpios:
+ maxItems: 1
+
+ interrupts:
+ maxItems: 1
+ description:
+ Invalid only for ti,pcm1690 because of no INT pin.
+
+ '#sound-dai-cells':
+ const: 0
+
+required:
+ - compatible
+ - reg
+
+allOf:
+ - $ref: dai-common.yaml#
+ - if:
+ properties:
+ compatible:
+ contains:
+ enum:
+ - ti,pcm1690
+ then:
+ properties:
+ interrupts: false
+
+additionalProperties: false
+
+examples:
+ - |
+ #include <dt-bindings/gpio/gpio.h>
+ i2c {
+ /* example for two devices with interrupt support */
+ #address-cells = <1>;
+ #size-cells = <0>;
+ pcm6240: audio-codec@48 {
+ compatible = "ti,pcm6240";
+ reg = <0x48>, /* primary-device */
+ <0x4b>; /* secondary-device */
+ #sound-dai-cells = <0>;
+ reset-gpios = <&gpio1 10 GPIO_ACTIVE_HIGH>;
+ interrupt-parent = <&gpio1>;
+ interrupts = <15>;
+ };
+ };
+...
--
2.34.1
^ permalink raw reply related
* Re: [PATCH 3/3] drm: panel: Add LG sw43408 panel driver
From: Dmitry Baryshkov @ 2024-04-03 0:36 UTC (permalink / raw)
To: Marijn Suijten
Cc: Sumit Semwal, Caleb Connolly, Neil Armstrong, Jessica Zhang,
Sam Ravnborg, David Airlie, Daniel Vetter, Maarten Lankhorst,
Maxime Ripard, Thomas Zimmermann, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, dri-devel, devicetree,
linux-kernel, linux-arm-msm, Vinod Koul, Caleb Connolly
In-Reply-To: <rdvcvkofafpdovldlibvobsxlk7nt3cc4kysm4aiafux7bmai6@nsqs7ofgr3ol>
On Tue, 2 Apr 2024 at 23:57, Marijn Suijten
<marijn.suijten@somainline.org> wrote:
>
> On 2024-04-01 22:11:48, Dmitry Baryshkov wrote:
> > On Mon, 1 Apr 2024 at 13:29, Marijn Suijten
> > <marijn.suijten@somainline.org> wrote:
> > >
> > > On 2024-03-30 16:37:08, Dmitry Baryshkov wrote:
> > > > On Sat, 30 Mar 2024 at 12:27, Marijn Suijten
> > > > <marijn.suijten@somainline.org> wrote:
> > > > >
> > > > > On 2024-03-30 05:59:30, Dmitry Baryshkov wrote:
> > > > > > From: Sumit Semwal <sumit.semwal@linaro.org>
> > > > > >
> > > > > > LG SW43408 is 1080x2160, 4-lane MIPI-DSI panel, used in some Pixel3
> > > > > > phones.
> > > > > >
> > > > > > Whatever init sequence we have for this panel isn't capable of
> > > > > > initialising it completely, toggling the reset gpio ever causes the
> > > > > > panel to die. Until this is resolved we avoid resetting the panel. The
> > > > >
> > > > > Are you sure it is avoided? This patch seems to be toggling reset_gpio in
> > > > > sw43408_prepare()?
> > > > >
> > > > > > disable/unprepare functions only put the panel to sleep mode and
> > > > > > disable the backlight.
> > > > > >
> > > > > > Signed-off-by: Sumit Semwal <sumit.semwal@linaro.org>
> > > > > > [vinod: Add DSC support]
> > > > > > Signed-off-by: Vinod Koul <vkoul@kernel.org>
> > > > > > [caleb: cleanup and support turning off the panel]
> > > > > > Signed-off-by: Caleb Connolly <caleb@connolly.tech>
> > > > > > [DB: partially rewrote the driver and fixed DSC programming]
> > > > > > Signed-off-by: Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
> > > > > > ---
> > > > > > MAINTAINERS | 8 +
> > > > > > drivers/gpu/drm/panel/Kconfig | 11 ++
> > > > > > drivers/gpu/drm/panel/Makefile | 1 +
> > > > > > drivers/gpu/drm/panel/panel-lg-sw43408.c | 322 +++++++++++++++++++++++++++++++
> > > > > > 4 files changed, 342 insertions(+)
> > > > > >
> > > > > > diff --git a/MAINTAINERS b/MAINTAINERS
> > > > > > index 4b511a55101c..f4cf7ee97376 100644
> > > > > > --- a/MAINTAINERS
> > > > > > +++ b/MAINTAINERS
> > > > > > @@ -6755,6 +6755,14 @@ S: Maintained
> > > > > > F: Documentation/devicetree/bindings/display/panel/jadard,jd9365da-h3.yaml
> > > > > > F: drivers/gpu/drm/panel/panel-jadard-jd9365da-h3.c
> > > > > >
> > > > > > +DRM DRIVER FOR LG SW43408 PANELS
> > > > > > +M: Sumit Semwal <sumit.semwal@linaro.org>
> > > > > > +M: Caleb Connolly <caleb.connolly@linaro.org>
> > > > > > +S: Maintained
> > > > > > +T: git git://anongit.freedesktop.org/drm/drm-misc
> > > > > > +F: Documentation/devicetree/bindings/display/panel/lg,sw43408.yaml
> > > > > > +F: drivers/gpu/drm/panel/panel-lg-sw43408.c
> > > > > > +
> > > > > > DRM DRIVER FOR LOGICVC DISPLAY CONTROLLER
> > > > > > M: Paul Kocialkowski <paul.kocialkowski@bootlin.com>
> > > > > > S: Supported
> > > > > > diff --git a/drivers/gpu/drm/panel/Kconfig b/drivers/gpu/drm/panel/Kconfig
> > > > > > index d037b3b8b999..f94c702735cb 100644
> > > > > > --- a/drivers/gpu/drm/panel/Kconfig
> > > > > > +++ b/drivers/gpu/drm/panel/Kconfig
> > > > > > @@ -335,6 +335,17 @@ config DRM_PANEL_LG_LG4573
> > > > > > Say Y here if you want to enable support for LG4573 RGB panel.
> > > > > > To compile this driver as a module, choose M here.
> > > > > >
> > > > > > +config DRM_PANEL_LG_SW43408
> > > > > > + tristate "LG SW43408 panel"
> > > > > > + depends on OF
> > > > > > + depends on DRM_MIPI_DSI
> > > > > > + depends on BACKLIGHT_CLASS_DEVICE
> > > > > > + help
> > > > > > + Say Y here if you want to enable support for LG sw43408 panel.
> > > > > > + The panel has a 1080x2160 resolution and uses
> > > > > > + 24 bit RGB per pixel. It provides a MIPI DSI interface to
> > > > > > + the host and has a built-in LED backlight.
> > > > > > +
> > > > > > config DRM_PANEL_MAGNACHIP_D53E6EA8966
> > > > > > tristate "Magnachip D53E6EA8966 DSI panel"
> > > > > > depends on OF && SPI
> > > > > > diff --git a/drivers/gpu/drm/panel/Makefile b/drivers/gpu/drm/panel/Makefile
> > > > > > index f156d7fa0bcc..a75687d13caf 100644
> > > > > > --- a/drivers/gpu/drm/panel/Makefile
> > > > > > +++ b/drivers/gpu/drm/panel/Makefile
> > > > > > @@ -34,6 +34,7 @@ obj-$(CONFIG_DRM_PANEL_LEADTEK_LTK050H3146W) += panel-leadtek-ltk050h3146w.o
> > > > > > obj-$(CONFIG_DRM_PANEL_LEADTEK_LTK500HD1829) += panel-leadtek-ltk500hd1829.o
> > > > > > obj-$(CONFIG_DRM_PANEL_LG_LB035Q02) += panel-lg-lb035q02.o
> > > > > > obj-$(CONFIG_DRM_PANEL_LG_LG4573) += panel-lg-lg4573.o
> > > > > > +obj-$(CONFIG_DRM_PANEL_LG_SW43408) += panel-lg-sw43408.o
> > > > > > obj-$(CONFIG_DRM_PANEL_MAGNACHIP_D53E6EA8966) += panel-magnachip-d53e6ea8966.o
> > > > > > obj-$(CONFIG_DRM_PANEL_NEC_NL8048HL11) += panel-nec-nl8048hl11.o
> > > > > > obj-$(CONFIG_DRM_PANEL_NEWVISION_NV3051D) += panel-newvision-nv3051d.o
> > > > > > diff --git a/drivers/gpu/drm/panel/panel-lg-sw43408.c b/drivers/gpu/drm/panel/panel-lg-sw43408.c
> > > > > > new file mode 100644
> > > > > > index 000000000000..365d25e14d54
> > > > > > --- /dev/null
> > > > > > +++ b/drivers/gpu/drm/panel/panel-lg-sw43408.c
> > > > > > @@ -0,0 +1,322 @@
> > > > > > +// SPDX-License-Identifier: GPL-2.0+
> > > > > > +/*
> > > > > > + * Copyright (C) 2019-2024 Linaro Ltd
> > > > > > + * Author: Sumit Semwal <sumit.semwal@linaro.org>
> > > > > > + * Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
> > > > > > + */
> > > > > > +
> > > > > > +#include <linux/backlight.h>
> > > > > > +#include <linux/delay.h>
> > > > > > +#include <linux/gpio/consumer.h>
> > > > > > +#include <linux/module.h>
> > > > > > +#include <linux/of.h>
> > > > > > +#include <linux/regulator/consumer.h>
> > > > > > +
> > > > > > +#include <video/mipi_display.h>
> > > > > > +
> > > > > > +#include <drm/drm_mipi_dsi.h>
> > > > > > +#include <drm/drm_panel.h>
> > > > > > +#include <drm/drm_probe_helper.h>
> > > > > > +#include <drm/display/drm_dsc.h>
> > > > > > +#include <drm/display/drm_dsc_helper.h>
> > > > > > +
> > > > > > +#define NUM_SUPPLIES 2
> > > > > > +
> > > > > > +struct sw43408_panel {
> > > > > > + struct drm_panel base;
> > > > > > + struct mipi_dsi_device *link;
> > > > > > +
> > > > > > + const struct drm_display_mode *mode;
> > > > > > +
> > > > > > + struct regulator_bulk_data supplies[NUM_SUPPLIES];
> > > > > > +
> > > > > > + struct gpio_desc *reset_gpio;
> > > > > > +};
> > > > > > +
> > > > > > +static inline struct sw43408_panel *to_panel_info(struct drm_panel *panel)
> > > > > > +{
> > > > > > + return container_of(panel, struct sw43408_panel, base);
> > > > > > +}
> > > > > > +
> > > > > > +static int sw43408_unprepare(struct drm_panel *panel)
> > > > > > +{
> > > > > > + struct sw43408_panel *ctx = to_panel_info(panel);
> > > > > > + int ret;
> > > > > > +
> > > > > > + ret = mipi_dsi_dcs_set_display_off(ctx->link);
> > > > > > + if (ret < 0)
> > > > > > + dev_err(panel->dev, "set_display_off cmd failed ret = %d\n", ret);
> > > > > > +
> > > > > > + ret = mipi_dsi_dcs_enter_sleep_mode(ctx->link);
> > > > > > + if (ret < 0)
> > > > > > + dev_err(panel->dev, "enter_sleep cmd failed ret = %d\n", ret);
> > > > > > +
> > > > > > + msleep(100);
> > > > > > +
> > > > > > + gpiod_set_value(ctx->reset_gpio, 1);
> > > > > > +
> > > > > > + return regulator_bulk_disable(ARRAY_SIZE(ctx->supplies), ctx->supplies);
> > > > > > +}
> > > > > > +
> > > > > > +static int sw43408_program(struct drm_panel *panel)
> > > > > > +{
> > > > > > + struct sw43408_panel *ctx = to_panel_info(panel);
> > > > > > + struct drm_dsc_picture_parameter_set pps;
> > > > > > + u8 dsc_en = 0x11;
> > > > >
> > > > > Yeah, this is completely strange. Bit 0, 0x1, is to enable DSC which is
> > > > > normal. 0x10 however, which is bit 4, selects PPS table 2. Do you ever set
> > > > > pps_identifier in struct drm_dsc_picture_parameter_set to 2? Or is the table
> > > > > that you send below bogus and/or not used? Maybe the Driver IC on the other
> > > > > end of the DSI link has a default PPS table with identifier 2 that works out of
> > > > > the box?
> > > >
> > > > Note, MIPI standard also requires two bytes argument. I suspect that
> > > > LG didn't fully follow the standard here.
> > >
> > > Have you read this command from downstream DTS, or have you tried sending 2
> > > bytes and seen the panel breaking? The second byte is marked as reserved and
> > > should be equal to 0; if the Driver IC is okay with sending either 1 or 2 bytes
> > > I'd strive to stick with the defined length of 2 bytes for this DCS.
> > >
> > > Have you played around with the PPS table? What if you change
> > > drm_dsc_picture_paremeter_set::pps_identifier to the second table, will the
> > > panel stop working as expected again? This could indicate that the PPS that is
> > > sent is incorrect (even though the information in the original DSC config was
> > > enough to set up the DPU and DSI correctly).
> > >
> > > According to the DSI spec it is allowed to have a pre-stored/pre-programmed
> > > PPS table, which could be used here making the current call to
> > > mipi_dsi_picture_parameter_set() useless and "confusing"?
> >
> > Ok, some short summary of my tests.
> >
> > Skipping PPS doesn't work at all, so there is no default.
> >
> > Adding a second zero byte doesn't seem to change anything. Dropping
> > the 0x1 bit ('enable') doesn't seem to change anything.
> >
> > If I send COMPRESSION_MODE before sending the PPS, various combinations work.
> > If I send COMPRESSION_MODE after sending the PPS, the follow combos work:
> >
> > pps_identifier = 0x0, COMPRESSION_MODE = 0x11
> > pps_identifier = 0x1, COMPRESSION_MODE = 0x21
>
> Thanks, this must really be an off-by-one table identifier. I presume you've
> tested pps_identifier=0x2 with COMPRESSION_MODE=0x31, and that there are only 2
> tables and not 3 or 4?
I was not able to get either pps_identifier = 0x2 or
COMPRESSION_MODE=0x31 to work.
>
> From this we can also assume that sending a new PPS will automatically switch
> the compression mode to the pps_identifier in that PPS, COMPRESSION_MODE doesn't
> seem to affect it when sent too early.
No. Omitting COMPRESSION_MODE packet breaks the display. Actually,
this was one of the issues: we were sending an incorrect packet. So
both are required.
>
> > > > Basically that's the reason why I went for the _raw function instead
> > > > of adding PPS and codec arguments to the existing function.
> > > >
> > > > >
> > > > > > + mipi_dsi_dcs_write_seq(ctx->link, MIPI_DCS_SET_GAMMA_CURVE, 0x02);
> > > > > > +
> > > > > > + mipi_dsi_dcs_set_tear_on(ctx->link, MIPI_DSI_DCS_TEAR_MODE_VBLANK);
> > > > > > +
> > > > > > + mipi_dsi_dcs_write_seq(ctx->link, 0x53, 0x0c, 0x30);
> > > > > > + mipi_dsi_dcs_write_seq(ctx->link, 0x55, 0x00, 0x70, 0xdf, 0x00, 0x70, 0xdf);
> > > > > > + mipi_dsi_dcs_write_seq(ctx->link, 0xf7, 0x01, 0x49, 0x0c);
> > > > > > +
> > > > > > + mipi_dsi_dcs_exit_sleep_mode(ctx->link);
> > > > > > +
> > > > > > + msleep(135);
> > > > > > +
> > > > > > + mipi_dsi_compression_mode_raw(ctx->link, &dsc_en, 1);
> > > > >
> > > > > Even though I think we should change this function to describe the known
> > > > > bit layout of command 0x7 per the VESA DSI spec, for now replace 1 with
> > > > > sizeof(dsc_en)?
> > > >
> > > > If dsc_en were an array, it would have been a proper thing. Maybe I
> > > > should change it to the array to remove confusion.
> > >
> > > It should work even with a single byte, just to clarify to readers that the 3rd
> > > argument is the byte-size of the input.
> > >
> > > > > > + mipi_dsi_dcs_write_seq(ctx->link, 0xb0, 0xac);
> > > > > > + mipi_dsi_dcs_write_seq(ctx->link, 0xe5,
> > > > > > + 0x00, 0x3a, 0x00, 0x3a, 0x00, 0x0e, 0x10);
> > > > > > + mipi_dsi_dcs_write_seq(ctx->link, 0xb5,
> > > > > > + 0x75, 0x60, 0x2d, 0x5d, 0x80, 0x00, 0x0a, 0x0b,
> > > > > > + 0x00, 0x05, 0x0b, 0x00, 0x80, 0x0d, 0x0e, 0x40,
> > > > > > + 0x00, 0x0c, 0x00, 0x16, 0x00, 0xb8, 0x00, 0x80,
> > > > > > + 0x0d, 0x0e, 0x40, 0x00, 0x0c, 0x00, 0x16, 0x00,
> > > > > > + 0xb8, 0x00, 0x81, 0x00, 0x03, 0x03, 0x03, 0x01,
> > > > > > + 0x01);
> > > > > > + msleep(85);
> > > > > > + mipi_dsi_dcs_write_seq(ctx->link, 0xcd,
> > > > > > + 0x00, 0x00, 0x00, 0x19, 0x19, 0x19, 0x19, 0x19,
> > > > > > + 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19,
> > > > > > + 0x16, 0x16);
> > > > > > + mipi_dsi_dcs_write_seq(ctx->link, 0xcb, 0x80, 0x5c, 0x07, 0x03, 0x28);
> > > > > > + mipi_dsi_dcs_write_seq(ctx->link, 0xc0, 0x02, 0x02, 0x0f);
> > > > > > + mipi_dsi_dcs_write_seq(ctx->link, 0x55, 0x04, 0x61, 0xdb, 0x04, 0x70, 0xdb);
> > > > > > + mipi_dsi_dcs_write_seq(ctx->link, 0xb0, 0xca);
> > > > > > +
> > > > > > + mipi_dsi_dcs_set_display_on(ctx->link);
> > > > >
> > > > > Any specific reason to not have the (un)blanking sequence in the enable/disable
> > > > > callbacks and leaving display configuration in (un)prepare?
> > > >
> > > > We are back to the question on when it's fine to send the commands. I
> > > > think the current agreement is to send everything in the
> > > > prepare/unprepare, because of some strange hosts.
> > >
> > > For my panel drivers I'm sticking with having `post-on` commands (from
> > > downstream) in `enable/disable`, which is typically only `set_display_on`. In
> > > hopes of proposing a `prepare_atomic()` some time to allow mode selection.
> > >
> > > In a short test on recent -next I am once again allowed to send DSI commands in
> > > both .disable and .unprepare, making both functions a "clean" inverse of .enable
> > > and .prepare respectively.
> >
> > The world isn't limited to the MSM hosts.
>
> If I'm not mistaken this was an ordering issue in the drm_bridge implementation.
No. I think sunxi didn't support sending DSI commands after starting
the video stream.
>
> But you are right that some hosts might not be all too happy with sending
> commands (like unblanking?) after the cmd/video stream started, and before the
> stream stops. Which, as far as I know, are what .enable and .disable do. On
> the other hand, I was under the impression that this split mainly existed to do
> all the heavy/required lifting up-front, and only unblank when there's a video
> signal to combat any possible observed corruption?
In the ideal world that would be true. But we are not living in the
ideal world. I still have hopes to get back to the idea of reworling
this part of the DSI framework.
> In the end I'm just curious if there's a specific reason - that I need
> to take into account when resending all my panel patches - to /not/
> use .enable/.disable?
I have bookmarked this email as a main reference for the topic:
https://lore.kernel.org/dri-devel/CAPY8ntBrhYAmsraDqJGuTrSL6VjGXBAMVoN7xweV7E4qZv+v3Q@mail.gmail.com/
>
> - Marijn
>
> > > > > > + msleep(50);
> > > > > > +
> > > > > > + ctx->link->mode_flags &= ~MIPI_DSI_MODE_LPM;
> > > > > > +
> > > > > > + drm_dsc_pps_payload_pack(&pps, ctx->link->dsc);
> > > > > > + mipi_dsi_picture_parameter_set(ctx->link, &pps);
> > > > >
> > > > > I'm always surprised why this is sent _after_ turning the display on (unblanking
> > > > > it). Wouldn't that cause unnecessary corruption?
> > > >
> > > > No idea. I followed the dowsntream command sequences here. Most likely
> > > > the panel is not fully on until it receives the full frame to be
> > > > displayed.
> > >
> > > According to the DSI spec a PPS update is allowed to happen every frame, and
> > > (for cmdmode panels) will take effect after the next TE trigger. Unsure if a TE
> > > event happens before the first frame, otherwise this may start taking effect
> > > on the second frame onwards only.
> > >
> > > If there's no corruption on the first frame there might be a pre-programmed PPS
> > > table in slot 2, supporting the theory above.
> >
> >
> >
> > --
> > With best wishes
> > Dmitry
--
With best wishes
Dmitry
^ permalink raw reply
* Re: [PATCH] arm64: dts: lx2160a: add pinmux and i2c gpio to support bus recovery
From: Shawn Guo @ 2024-04-03 0:43 UTC (permalink / raw)
To: carlos.song
Cc: shawnguo, robh, krzysztof.kozlowski+dt, conor+dt, frank.li,
linux-arm-kernel, devicetree, linux-kernel
In-Reply-To: <20240328061419.1956329-1-carlos.song@nxp.com>
On Thu, Mar 28, 2024 at 02:14:19PM +0800, carlos.song@nxp.com wrote:
> From: Carlos Song <carlos.song@nxp.com>
>
> I2C bus recovery need a pinmux and gpio. So i2c driver can switch
> gpio mode to toggle scl to recovery bus.
>
> Add pinctrl-single node to every i2c bus on fsl-ls2160 layerscape
> platform.
>
> Signed-off-by: Carlos Song <carlos.song@nxp.com>
> Reviewed-by: Frank Li <frank.li@nxp.com>
Applied, thanks!
^ permalink raw reply
* Re: Fixing the devicetree of Rock 5 Model B (and possibly others)
From: Saravana Kannan @ 2024-04-03 0:46 UTC (permalink / raw)
To: Pratham Patel
Cc: Dragan Simic, sebastian.reichel, devicetree, linux-arm-kernel,
linux-rockchip, linux-kernel, regressions, stable
In-Reply-To: <D0A122WK7CB9.33B2TP6UCMJBJ@thefossguy.com>
On Tue, Apr 2, 2024 at 4:32 PM Pratham Patel
<prathampatel@thefossguy.com> wrote:
>
> On Tue Apr 2, 2024 at 4:54 AM IST, Saravana Kannan wrote:
> > On Sat, Mar 23, 2024 at 10:10 AM Dragan Simic <dsimic@manjaro.org> wrote:
> > >
> > > Hello Pratham,
> > >
> > > On 2024-03-23 18:02, Pratham Patel wrote:
> > > > I looked at the patch and tried several things, neither resulted in
> > > > anything that would point me to the core issue. Then I tried this:
> > >
> > > Could you, please, clarify a bit what's the actual issue you're
> > > experiencing on your Rock 5B?
> >
> > Pratham, can you reply to this please? I don't really understand what
> > your issue is for me to be able to help.
>
> Hi,
>
> I apologize for not replying. Somehow, I did not notice the reply from
> Dragan. :(
>
> Since this patch was applied, an issue in the Rock 5B's DT has been
> unearthed which now results in the kernel being unable to boot properly.
>
> Following is the relevant call trace from the UART capture:
>
> [ 21.595068] Call trace:
> [ 21.595288] smp_call_function_many_cond+0x174/0x5f8
> [ 21.595728] on_each_cpu_cond_mask+0x2c/0x40
> [ 21.596109] cpuidle_register_driver+0x294/0x318
> [ 21.596524] cpuidle_register+0x24/0x100
> [ 21.596875] psci_cpuidle_probe+0x2e4/0x490
> [ 21.597247] platform_probe+0x70/0xd0
> [ 21.597575] really_probe+0x18c/0x3d8
> [ 21.597905] __driver_probe_device+0x84/0x180
> [ 21.598294] driver_probe_device+0x44/0x120
> [ 21.598669] __device_attach_driver+0xc4/0x168
> [ 21.599063] bus_for_each_drv+0x8c/0xf0
> [ 21.599408] __device_attach+0xa4/0x1c0
> [ 21.599748] device_initial_probe+0x1c/0x30
> [ 21.600118] bus_probe_device+0xb4/0xc0
> [ 21.600462] device_add+0x68c/0x888
> [ 21.600775] platform_device_add+0x19c/0x270
> [ 21.601154] platform_device_register_full+0xdc/0x178
> [ 21.601602] psci_idle_init+0xa0/0xc8
> [ 21.601934] do_one_initcall+0x60/0x290
> [ 21.602275] kernel_init_freeable+0x20c/0x3e0
> [ 21.602664] kernel_init+0x2c/0x1f8
> [ 21.602979] ret_from_fork+0x10/0x20
This doesn't make a lot of sense. "remote-endpoint" shouldn't be
related to anything to do with psci cpuidle. I'm guessing something
else is failing much earlier in boot that's indirectly causing this
somehow? Can you please take a look at what's failing earlier and let
us know? Or see what driver probe is failing up to this point but used
to work in the good case.
Also, where is the dts file that corresponds to this board in upstream? Is it
arch/arm64/boot/dts/rockchip/rk3588-rock-5b.dts
>
> > Also, can you give the output of <debugfs>/devices_deferred for the
> > good vs bad case?
>
> I can't provide you with requested output from the bad case, since the
> kernel never moves past this to an initramfs rescue shell, but following
> is the output from v6.8.1 (**with aforementioned patch reverted**).
>
> # cat /sys/kernel/debug/devices_deferred
> fc400000.usb platform: wait for supplier /phy@fed90000/usb3-port
> 1-0022 typec_fusb302: cannot register tcpm port
> fc000000.usb platform: wait for supplier /phy@fed80000/usb3-port
>
> It seems that v6.8.2 works _without needing to revert the patch_. I will
> have to look into this sometime this week but it seems like
> a8037ceb8964 (arm64: dts: rockchip: drop rockchip,trcm-sync-tx-only from rk3588 i2s)
> seems to be the one that fixed the root issue. I will have to test it
> sometime later this week.
Ok, once you find the patch that fixes things, let me know too.
-Saravana
^ permalink raw reply
* Re: [PATCH v8 4/5] arm64: dts: imx8: fix audio lpcg index
From: Shawn Guo @ 2024-04-03 0:46 UTC (permalink / raw)
To: Frank Li
Cc: Liam Girdwood, Mark Brown, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Shawn Guo, Sascha Hauer, Pengutronix Kernel Team,
Fabio Estevam, Shengjiu Wang, linux-sound, devicetree, imx,
linux-arm-kernel, linux-kernel
In-Reply-To: <20240328-asrc_8qxp-v8-4-801cd6bb5be2@nxp.com>
On Thu, Mar 28, 2024 at 10:51:36AM -0400, Frank Li wrote:
> lpcg cell0 should be clock's 'indices' instead of 'index'.
>
> imx_lpcg_of_clk_src_get(struct of_phandle_args *clkspec, void *data)
> {
> struct clk_hw_onecell_data *hw_data = data;
> unsigned int idx = clkspec->args[0] / 4;
>
> ....
> }
>
> <@sai0_lpcg 1> will be the same as <@sai_lpcg 0>.
>
> Replace 0 with IMX_LPCG_CLK_0 and replace 1 with IMX_LPCG_CLK_4.
>
> It can work at iMX8QXP because IMX_LPCG_CLK_4 is ipg clock, which already
> enabled. But for iMX8QM IMX_LPCG_CLK_4 is mclk, which trigger issue.
>
> Fixes: 0a9279e9ae88 ("arm64: dts: imx8qxp: Add audio SAI nodes")
> Signed-off-by: Frank Li <Frank.Li@nxp.com>
Applied, thanks!
^ permalink raw reply
* Re: [PATCH v8 5/5] arm64: dts: imx8qxp: add asrc[0,1], esai0, spdif0 and sai[4,5]
From: Shawn Guo @ 2024-04-03 0:46 UTC (permalink / raw)
To: Frank Li
Cc: Liam Girdwood, Mark Brown, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Shawn Guo, Sascha Hauer, Pengutronix Kernel Team,
Fabio Estevam, Shengjiu Wang, linux-sound, devicetree, imx,
linux-arm-kernel, linux-kernel
In-Reply-To: <20240328-asrc_8qxp-v8-5-801cd6bb5be2@nxp.com>
On Thu, Mar 28, 2024 at 10:51:37AM -0400, Frank Li wrote:
> Add asrc[0,1], esai0, spdif0, sai[4,5] and related lpcg node for
> imx8 audio subsystem.
>
> Signed-off-by: Frank Li <Frank.Li@nxp.com>
Applied, thanks!
^ permalink raw reply
* Re: [PATCH v3 1/4] dt-bindings: panel: Add LG SW43408 MIPI-DSI panel
From: Dmitry Baryshkov @ 2024-04-03 0:51 UTC (permalink / raw)
To: Marijn Suijten
Cc: Krzysztof Kozlowski, Sumit Semwal, Caleb Connolly, Neil Armstrong,
Jessica Zhang, Sam Ravnborg, David Airlie, Daniel Vetter,
Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, dri-devel, devicetree,
linux-kernel, linux-arm-msm, Vinod Koul, Caleb Connolly
In-Reply-To: <t3cx5qxiteer27vsvysizbrxkbamxgrcbn2oafisodjopwas5z@nxlasb4rlnml>
On Tue, Apr 02, 2024 at 10:59:11PM +0200, Marijn Suijten wrote:
> On 2024-04-02 10:23:22, Dmitry Baryshkov wrote:
> > On Tue, 2 Apr 2024 at 09:31, Krzysztof Kozlowski
> > <krzysztof.kozlowski@linaro.org> wrote:
> > >
> > > On 02/04/2024 01:51, Dmitry Baryshkov wrote:
> > > > From: Sumit Semwal <sumit.semwal@linaro.org>
> > > >
> > > > LG SW43408 is 1080x2160, 4-lane MIPI-DSI panel present on Google Pixel 3
> > > > phones.
> > > >
> > > > Signed-off-by: Vinod Koul <vkoul@kernel.org>
> > > > Signed-off-by: Sumit Semwal <sumit.semwal@linaro.org>
> > > > [caleb: convert to yaml]
> > > > Signed-off-by: Caleb Connolly <caleb@connolly.tech>
> > > > Signed-off-by: Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
> > > > ---
> > >
> > > Tags missing.
> > >
> > > `b4 trailers -u`
> >
> > Excuse me, I keep on forgetting it.
>
> Does a similar thing exist for adding Cc: tags for all reviewers/replyers to an
> earlier version, even if said reviewer didn't yet provide R-b/A-b or other tags?
>
> I'd like to have the next revisions in my inbox as well after leaving
> comments :)
Unfortunately I don't know such option.
>
> Thanks! - Marijn
--
With best wishes
Dmitry
^ permalink raw reply
* Re: [PATCH] ARM: dts: imx7s-warp: Pass OV2680 link-frequencies
From: Shawn Guo @ 2024-04-03 0:51 UTC (permalink / raw)
To: Fabio Estevam
Cc: shawnguo, sakari.ailus, hdegoede, robh, krzysztof.kozlowski+dt,
conor+dt, linux-arm-kernel, devicetree, Fabio Estevam, stable
In-Reply-To: <20240328151954.2517368-1-festevam@gmail.com>
On Thu, Mar 28, 2024 at 12:19:54PM -0300, Fabio Estevam wrote:
> From: Fabio Estevam <festevam@denx.de>
>
> Since commit 63b0cd30b78e ("media: ov2680: Add bus-cfg / endpoint
> property verification") the ov2680 no longer probes on a imx7s-warp7:
>
> ov2680 1-0036: error -EINVAL: supported link freq 330000000 not found
> ov2680 1-0036: probe with driver ov2680 failed with error -22
>
> Fix it by passing the required 'link-frequencies' property as
> recommended by:
>
> https://www.kernel.org/doc/html/v6.9-rc1/driver-api/media/camera-sensor.html#handling-clocks
>
> Cc: stable@vger.kernel.org
> Fixes: 63b0cd30b78e ("media: ov2680: Add bus-cfg / endpoint property verification")
> Signed-off-by: Fabio Estevam <festevam@denx.de>
Applied, thanks!
^ permalink raw reply
* Re: [PATCH] ARM: dts: imx7s-warp: Pass OV2680 link-frequencies
From: Shawn Guo @ 2024-04-03 0:52 UTC (permalink / raw)
To: Rob Herring
Cc: Fabio Estevam, Fabio Estevam, linux-arm-kernel, sakari.ailus,
stable, hdegoede, devicetree, shawnguo, conor+dt,
krzysztof.kozlowski+dt
In-Reply-To: <171165955888.338117.15736314486472326706.robh@kernel.org>
On Thu, Mar 28, 2024 at 04:01:02PM -0500, Rob Herring wrote:
>
> On Thu, 28 Mar 2024 12:19:54 -0300, Fabio Estevam wrote:
> > From: Fabio Estevam <festevam@denx.de>
> >
> > Since commit 63b0cd30b78e ("media: ov2680: Add bus-cfg / endpoint
> > property verification") the ov2680 no longer probes on a imx7s-warp7:
> >
> > ov2680 1-0036: error -EINVAL: supported link freq 330000000 not found
> > ov2680 1-0036: probe with driver ov2680 failed with error -22
> >
> > Fix it by passing the required 'link-frequencies' property as
> > recommended by:
> >
> > https://www.kernel.org/doc/html/v6.9-rc1/driver-api/media/camera-sensor.html#handling-clocks
> >
> > Cc: stable@vger.kernel.org
> > Fixes: 63b0cd30b78e ("media: ov2680: Add bus-cfg / endpoint property verification")
> > Signed-off-by: Fabio Estevam <festevam@denx.de>
> > ---
> > arch/arm/boot/dts/nxp/imx/imx7s-warp.dts | 1 +
> > 1 file changed, 1 insertion(+)
> >
>
>
> My bot found new DTB warnings on the .dts files added or changed in this
> series.
>
> Some warnings may be from an existing SoC .dtsi. Or perhaps the warnings
> are fixed by another series. Ultimately, it is up to the platform
> maintainer whether these warnings are acceptable or not. No need to reply
> unless the platform maintainer has comments.
>
> If you already ran DT checks and didn't see these error(s), then
> make sure dt-schema is up to date:
>
> pip3 install dtschema --upgrade
>
>
> New warnings running 'make CHECK_DTBS=y nxp/imx/imx7s-warp.dtb' for 20240328151954.2517368-1-festevam@gmail.com:
>
> arch/arm/boot/dts/nxp/imx/imx7s-warp.dtb: camera@36: port:endpoint: Unevaluated properties are not allowed ('clock-lanes', 'data-lanes', 'link-frequencies' were unexpected)
> from schema $id: http://devicetree.org/schemas/media/i2c/ovti,ov2680.yaml#
So it sounds like that the bindings doc needs an update to include
'link-frequencies'?
Shawn
^ permalink raw reply
* Re: [PATCH] ARM: dts: imx7s-warp: Pass OV2680 link-frequencies
From: Fabio Estevam @ 2024-04-03 0:56 UTC (permalink / raw)
To: Shawn Guo
Cc: Rob Herring, Fabio Estevam, linux-arm-kernel, sakari.ailus,
stable, hdegoede, devicetree, shawnguo, conor+dt,
krzysztof.kozlowski+dt
In-Reply-To: <ZgyoX55PJD0LDSPf@dragon>
Hi Shawn,
On Tue, Apr 2, 2024 at 9:53 PM Shawn Guo <shawnguo2@yeah.net> wrote:
> So it sounds like that the bindings doc needs an update to include
> 'link-frequencies'?
Correct. I have already submitted the binding patch:
https://lore.kernel.org/linux-devicetree/20240402174028.205434-2-festevam@gmail.com/
^ permalink raw reply
* Re: Fixing the devicetree of Rock 5 Model B (and possibly others)
From: Pratham Patel @ 2024-04-03 1:03 UTC (permalink / raw)
To: Saravana Kannan
Cc: Dragan Simic, sebastian.reichel, devicetree, linux-arm-kernel,
linux-rockchip, linux-kernel, regressions, stable
In-Reply-To: <CAGETcx_ToHsp_c+Yt0qqST4Zd-GC7dPn_j=PpB1n1xpZtOnMfg@mail.gmail.com>
On Wed Apr 3, 2024 at 6:16 AM IST, Saravana Kannan wrote:
> On Tue, Apr 2, 2024 at 4:32 PM Pratham Patel
> <prathampatel@thefossguy.com> wrote:
> >
> > On Tue Apr 2, 2024 at 4:54 AM IST, Saravana Kannan wrote:
> > > On Sat, Mar 23, 2024 at 10:10 AM Dragan Simic <dsimic@manjaro.org> wrote:
> > > >
> > > > Hello Pratham,
> > > >
> > > > On 2024-03-23 18:02, Pratham Patel wrote:
> > > > > I looked at the patch and tried several things, neither resulted in
> > > > > anything that would point me to the core issue. Then I tried this:
> > > >
> > > > Could you, please, clarify a bit what's the actual issue you're
> > > > experiencing on your Rock 5B?
> > >
> > > Pratham, can you reply to this please? I don't really understand what
> > > your issue is for me to be able to help.
> >
> > Hi,
> >
> > I apologize for not replying. Somehow, I did not notice the reply from
> > Dragan. :(
> >
> > Since this patch was applied, an issue in the Rock 5B's DT has been
> > unearthed which now results in the kernel being unable to boot properly.
> >
> > Following is the relevant call trace from the UART capture:
> >
> > [ 21.595068] Call trace:
> > [ 21.595288] smp_call_function_many_cond+0x174/0x5f8
> > [ 21.595728] on_each_cpu_cond_mask+0x2c/0x40
> > [ 21.596109] cpuidle_register_driver+0x294/0x318
> > [ 21.596524] cpuidle_register+0x24/0x100
> > [ 21.596875] psci_cpuidle_probe+0x2e4/0x490
> > [ 21.597247] platform_probe+0x70/0xd0
> > [ 21.597575] really_probe+0x18c/0x3d8
> > [ 21.597905] __driver_probe_device+0x84/0x180
> > [ 21.598294] driver_probe_device+0x44/0x120
> > [ 21.598669] __device_attach_driver+0xc4/0x168
> > [ 21.599063] bus_for_each_drv+0x8c/0xf0
> > [ 21.599408] __device_attach+0xa4/0x1c0
> > [ 21.599748] device_initial_probe+0x1c/0x30
> > [ 21.600118] bus_probe_device+0xb4/0xc0
> > [ 21.600462] device_add+0x68c/0x888
> > [ 21.600775] platform_device_add+0x19c/0x270
> > [ 21.601154] platform_device_register_full+0xdc/0x178
> > [ 21.601602] psci_idle_init+0xa0/0xc8
> > [ 21.601934] do_one_initcall+0x60/0x290
> > [ 21.602275] kernel_init_freeable+0x20c/0x3e0
> > [ 21.602664] kernel_init+0x2c/0x1f8
> > [ 21.602979] ret_from_fork+0x10/0x20
>
> This doesn't make a lot of sense. "remote-endpoint" shouldn't be
> related to anything to do with psci cpuidle. I'm guessing something
> else is failing much earlier in boot that's indirectly causing this
> somehow? Can you please take a look at what's failing earlier and let
> us know? Or see what driver probe is failing up to this point but used
> to work in the good case.
I'm pretty new to this, "just starting". I'm not sure how to do that,
since the kernel doesn't really "move forward". I will verify if
a8037ceb8964 fixes it or not and get back by the end of this week.
> Also, where is the dts file that corresponds to this board in upstream? Is it
> arch/arm64/boot/dts/rockchip/rk3588-rock-5b.dts
Yes.
> >
> > > Also, can you give the output of <debugfs>/devices_deferred for the
> > > good vs bad case?
> >
> > I can't provide you with requested output from the bad case, since the
> > kernel never moves past this to an initramfs rescue shell, but following
> > is the output from v6.8.1 (**with aforementioned patch reverted**).
> >
> > # cat /sys/kernel/debug/devices_deferred
> > fc400000.usb platform: wait for supplier /phy@fed90000/usb3-port
> > 1-0022 typec_fusb302: cannot register tcpm port
> > fc000000.usb platform: wait for supplier /phy@fed80000/usb3-port
> >
> > It seems that v6.8.2 works _without needing to revert the patch_. I will
> > have to look into this sometime this week but it seems like
> > a8037ceb8964 (arm64: dts: rockchip: drop rockchip,trcm-sync-tx-only from rk3588 i2s)
> > seems to be the one that fixed the root issue. I will have to test it
> > sometime later this week.
>
> Ok, once you find the patch that fixes things, let me know too.
Will do!
-- Pratham Patel
^ permalink raw reply
* Re: [PATCH] arm64: dts: imx8m*-venice-gw7: Fix TPM schema violations
From: Fabio Estevam @ 2024-04-03 1:11 UTC (permalink / raw)
To: Tim Harvey
Cc: Rob Herring, Krzysztof Kozlowski, Conor Dooley, Shawn Guo,
Sascha Hauer, Pengutronix Kernel Team, devicetree, imx,
linux-arm-kernel, linux-kernel, Lukas Wunner
In-Reply-To: <20240402193355.2333597-1-tharvey@gateworks.com>
Hi Tim,
On Tue, Apr 2, 2024 at 4:34 PM Tim Harvey <tharvey@gateworks.com> wrote:
>
> Since commit 26c9d152ebf3 ("dt-bindings: tpm: Consolidate TCG TIS
> bindings"), several issues are reported by "make dtbs_check" for arm64
> devicetrees:
>
> The compatible property needs to contain the chip's name in addition to
> the generic "tcg,tpm_tis-spi".
>
> tpm@1: compatible: ['tcg,tpm_tis-spi'] is too short
> from schema $id:
> http://devicetree.org/schemas/tpm/tcg,tpm_tis-spi.yaml#
>
> Fix these schema violations.
>
> Gateworks Venice uses an Atmel ATTPM20P:
> https://trac.gateworks.com/wiki/tpm
Thanks for the fix.
Reviewed-by: Fabio Estevam <festevam@gmail.com>
^ permalink raw reply
* Re: [PATCH v2 0/3] Add support for Emcraft Systems NavQ+ kit
From: Shawn Guo @ 2024-04-03 1:15 UTC (permalink / raw)
To: Gilles Talis
Cc: devicetree, imx, linux-arm-kernel, conor+dt,
krzysztof.kozlowski+dt, robh, shawnguo, festevam, alex, andrew
In-Reply-To: <20240330133410.41408-1-gilles.talis@gmail.com>
On Sat, Mar 30, 2024 at 09:34:07AM -0400, Gilles Talis wrote:
> Hello
>
> This series adds a device tree file for the Emcraft Systems NavQ+ kit [1]
>
> The first patch adds a new vendor prefix for Emcraft Systems
> The second one adds the board to the arm/fsl.yaml DT bindings.
> Last patch adds device tree file for the kit.
>
> [1] https://www.emcraft.com/products/1222
>
> Changes in v2:
> - Add Acked-by review tags
> - Fixed device tree warnings reported by dtbs_check
> - Reworked leds node
> - Remove unused i2c6 pinctrl entry
> - Removed unused regulator node in Ethernet entry
> - Link to v1: https://lore.kernel.org/imx/20240328202320.187596-1-gilles.talis@gmail.com/
> ---
> Gilles Talis (3):
> dt-bindings: vendor-prefixes: Add Emcraft Systems
> dt-bindings: arm: Add Emcraft Systems i.MX8M Plus NavQ+ Kit
> arm64: dts: freescale: Add device tree for Emcraft Systems NavQ+ Kit
Applied all, thanks!
^ permalink raw reply
* Re: [PATCH v2 1/2] ARM: dts: imx6sx-nitrogen6sx: drop incorrect cpu-dai property
From: Shawn Guo @ 2024-04-03 1:18 UTC (permalink / raw)
To: Shengjiu Wang
Cc: lgirdwood, broonie, robh+dt, krzysztof.kozlowski+dt, conor+dt,
shengjiu.wang, linux-sound, devicetree, linux-kernel, shawnguo,
s.hauer, kernel, festevam, imx, linux-arm-kernel
In-Reply-To: <1711976056-19884-2-git-send-email-shengjiu.wang@nxp.com>
On Mon, Apr 01, 2024 at 08:54:15PM +0800, Shengjiu Wang wrote:
> drop incorrect cpu-dai property, change it to ssi-controller
>
> Signed-off-by: Shengjiu Wang <shengjiu.wang@nxp.com>
Applied, thanks!
^ permalink raw reply
* Re: [PATCH] arm64: dts: imx8m*-venice-gw7: Fix TPM schema violations
From: Shawn Guo @ 2024-04-03 1:20 UTC (permalink / raw)
To: Tim Harvey
Cc: Rob Herring, Krzysztof Kozlowski, Conor Dooley, Shawn Guo,
Sascha Hauer, Pengutronix Kernel Team, Fabio Estevam, devicetree,
imx, linux-arm-kernel, linux-kernel, Lukas Wunner
In-Reply-To: <20240402193355.2333597-1-tharvey@gateworks.com>
On Tue, Apr 02, 2024 at 12:33:55PM -0700, Tim Harvey wrote:
> Since commit 26c9d152ebf3 ("dt-bindings: tpm: Consolidate TCG TIS
> bindings"), several issues are reported by "make dtbs_check" for arm64
> devicetrees:
>
> The compatible property needs to contain the chip's name in addition to
> the generic "tcg,tpm_tis-spi".
>
> tpm@1: compatible: ['tcg,tpm_tis-spi'] is too short
> from schema $id:
> http://devicetree.org/schemas/tpm/tcg,tpm_tis-spi.yaml#
>
> Fix these schema violations.
>
> Gateworks Venice uses an Atmel ATTPM20P:
> https://trac.gateworks.com/wiki/tpm
>
> Cc: Lukas Wunner <lukas@wunner.de>
> Signed-off-by: Tim Harvey <tharvey@gateworks.com>
Applied, thanks!
^ permalink raw reply
* Re: [net-next,v2] dt-bindings: net: renesas,ethertsn: Create child-node for MDIO bus
From: patchwork-bot+netdevbpf @ 2024-04-03 1:40 UTC (permalink / raw)
To: =?utf-8?q?Niklas_S=C3=B6derlund_=3Cniklas=2Esoderlund+renesas=40ragnatech=2E?=,
=?utf-8?q?se=3E?=
Cc: s.shtylyov, davem, edumazet, kuba, pabeni, robh+dt,
krzysztof.kozlowski+dt, conor+dt, geert+renesas, netdev,
devicetree, linux-renesas-soc, robh
In-Reply-To: <20240330131228.1541227-1-niklas.soderlund+renesas@ragnatech.se>
Hello:
This patch was applied to netdev/net-next.git (main)
by Jakub Kicinski <kuba@kernel.org>:
On Sat, 30 Mar 2024 14:12:28 +0100 you wrote:
> The bindings for Renesas Ethernet TSN was just merged in v6.9 and the
> design for the bindings followed that of other Renesas Ethernet drivers
> and thus did not force a child-node for the MDIO bus. As there
> are no upstream drivers or users of this binding yet take the
> opportunity to correct this and force the usage of a child-node for the
> MDIO bus.
>
> [...]
Here is the summary with links:
- [net-next,v2] dt-bindings: net: renesas,ethertsn: Create child-node for MDIO bus
https://git.kernel.org/netdev/net-next/c/8da891720cd4
You are awesome, thank you!
--
Deet-doot-dot, I am a bot.
https://korg.docs.kernel.org/patchwork/pwbot.html
^ permalink raw reply
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox