* Re: [PATCH v5 2/4] drm/bridge: add lvds controller support for sam9x7
From: Hari.PrasathGE @ 2024-04-07 6:28 UTC (permalink / raw)
To: Dharma.B, andrzej.hajda, neil.armstrong, rfoss, Laurent.pinchart,
jonas, jernej.skrabec, maarten.lankhorst, mripard, tzimmermann,
airlied, daniel, robh+dt, krzysztof.kozlowski+dt, conor+dt, linux,
Nicolas.Ferre, alexandre.belloni, claudiu.beznea, Manikandan.M,
arnd, geert+renesas, Jason, mpe, gerg, rdunlap, vbabka, dri-devel,
devicetree, linux-kernel, linux-arm-kernel, akpm, deller
In-Reply-To: <20240405043536.274220-3-dharma.b@microchip.com>
On 4/5/24 10:05 AM, Dharma Balasubiramani wrote:
> Add a new LVDS controller driver for sam9x7 which does the following:
> - Prepares and enables the LVDS Peripheral clock
> - Defines its connector type as DRM_MODE_CONNECTOR_LVDS and adds itself
> to the global bridge list.
> - Identifies its output endpoint as panel and adds it to the encoder
> display pipeline
> - Enables the LVDS serializer
Acked-by: Hari Prasath Gujulan Elango <hari.prasathge@microchip.com>
>
> Signed-off-by: Manikandan Muralidharan <manikandan.m@microchip.com>
> Signed-off-by: Dharma Balasubiramani <dharma.b@microchip.com>
> ---
> Changelog
> v4 -> v5
> - Drop the unused variable 'format'.
> - Use DRM wrapper for dev_err() to maintain uniformity.
> - return -ENODEV instead of -EINVAL to maintain consistency with other DRM
> bridge drivers.
> v3 -> v4
> - No changes.
> v2 ->v3
> - Correct Typo error "serializer".
> - Consolidate get() and prepare() functions and use devm_clk_get_prepared().
> - Remove unused variable 'ret' in probe().
> - Use devm_pm_runtime_enable() and drop the mchp_lvds_remove().
> v1 -> v2
> - Drop 'res' variable and combine two lines into one.
> - Handle deferred probe properly, use dev_err_probe().
> - Don't print anything on deferred probe. Dropped print.
> - Remove the MODULE_ALIAS and add MODULE_DEVICE_TABLE().
> - symbol 'mchp_lvds_driver' was not declared. It should be static.
> ---
> drivers/gpu/drm/bridge/Kconfig | 7 +
> drivers/gpu/drm/bridge/Makefile | 1 +
> drivers/gpu/drm/bridge/microchip-lvds.c | 228 ++++++++++++++++++++++++
> 3 files changed, 236 insertions(+)
> create mode 100644 drivers/gpu/drm/bridge/microchip-lvds.c
>
> diff --git a/drivers/gpu/drm/bridge/Kconfig b/drivers/gpu/drm/bridge/Kconfig
> index efd996f6c138..889098e2d65f 100644
> --- a/drivers/gpu/drm/bridge/Kconfig
> +++ b/drivers/gpu/drm/bridge/Kconfig
> @@ -190,6 +190,13 @@ config DRM_MEGACHIPS_STDPXXXX_GE_B850V3_FW
> to DP++. This is used with the i.MX6 imx-ldb
> driver. You are likely to say N here.
>
> +config DRM_MICROCHIP_LVDS_SERIALIZER
> + tristate "Microchip LVDS serializer support"
> + depends on OF
> + depends on DRM_ATMEL_HLCDC
> + help
> + Support for Microchip's LVDS serializer.
> +
> config DRM_NWL_MIPI_DSI
> tristate "Northwest Logic MIPI DSI Host controller"
> depends on DRM
> diff --git a/drivers/gpu/drm/bridge/Makefile b/drivers/gpu/drm/bridge/Makefile
> index 017b5832733b..7df87b582dca 100644
> --- a/drivers/gpu/drm/bridge/Makefile
> +++ b/drivers/gpu/drm/bridge/Makefile
> @@ -13,6 +13,7 @@ obj-$(CONFIG_DRM_LONTIUM_LT9611) += lontium-lt9611.o
> obj-$(CONFIG_DRM_LONTIUM_LT9611UXC) += lontium-lt9611uxc.o
> obj-$(CONFIG_DRM_LVDS_CODEC) += lvds-codec.o
> obj-$(CONFIG_DRM_MEGACHIPS_STDPXXXX_GE_B850V3_FW) += megachips-stdpxxxx-ge-b850v3-fw.o
> +obj-$(CONFIG_DRM_MICROCHIP_LVDS_SERIALIZER) += microchip-lvds.o
> obj-$(CONFIG_DRM_NXP_PTN3460) += nxp-ptn3460.o
> obj-$(CONFIG_DRM_PARADE_PS8622) += parade-ps8622.o
> obj-$(CONFIG_DRM_PARADE_PS8640) += parade-ps8640.o
> diff --git a/drivers/gpu/drm/bridge/microchip-lvds.c b/drivers/gpu/drm/bridge/microchip-lvds.c
> new file mode 100644
> index 000000000000..149704f498a6
> --- /dev/null
> +++ b/drivers/gpu/drm/bridge/microchip-lvds.c
> @@ -0,0 +1,228 @@
> +// SPDX-License-Identifier: GPL-2.0-only
> +/*
> + * Copyright (C) 2023 Microchip Technology Inc. and its subsidiaries
> + *
> + * Author: Manikandan Muralidharan <manikandan.m@microchip.com>
> + * Author: Dharma Balasubiramani <dharma.b@microchip.com>
> + *
> + */
> +
> +#include <linux/clk.h>
> +#include <linux/component.h>
> +#include <linux/delay.h>
> +#include <linux/jiffies.h>
> +#include <linux/mfd/syscon.h>
> +#include <linux/of_graph.h>
> +#include <linux/pinctrl/devinfo.h>
> +#include <linux/phy/phy.h>
> +#include <linux/platform_device.h>
> +#include <linux/pm_runtime.h>
> +#include <linux/regmap.h>
> +#include <linux/reset.h>
> +
> +#include <drm/drm_atomic_helper.h>
> +#include <drm/drm_bridge.h>
> +#include <drm/drm_of.h>
> +#include <drm/drm_panel.h>
> +#include <drm/drm_print.h>
> +#include <drm/drm_probe_helper.h>
> +#include <drm/drm_simple_kms_helper.h>
> +
> +#define LVDS_POLL_TIMEOUT_MS 1000
> +
> +/* LVDSC register offsets */
> +#define LVDSC_CR 0x00
> +#define LVDSC_CFGR 0x04
> +#define LVDSC_SR 0x0C
> +#define LVDSC_WPMR 0xE4
> +
> +/* Bitfields in LVDSC_CR (Control Register) */
> +#define LVDSC_CR_SER_EN BIT(0)
> +
> +/* Bitfields in LVDSC_CFGR (Configuration Register) */
> +#define LVDSC_CFGR_PIXSIZE_24BITS 0
> +#define LVDSC_CFGR_DEN_POL_HIGH 0
> +#define LVDSC_CFGR_DC_UNBALANCED 0
> +#define LVDSC_CFGR_MAPPING_JEIDA BIT(6)
> +
> +/*Bitfields in LVDSC_SR */
> +#define LVDSC_SR_CS BIT(0)
> +
> +/* Bitfields in LVDSC_WPMR (Write Protection Mode Register) */
> +#define LVDSC_WPMR_WPKEY_MASK GENMASK(31, 8)
> +#define LVDSC_WPMR_WPKEY_PSSWD 0x4C5644
> +
> +struct mchp_lvds {
> + struct device *dev;
> + void __iomem *regs;
> + struct clk *pclk;
> + struct drm_panel *panel;
> + struct drm_bridge bridge;
> + struct drm_bridge *panel_bridge;
> +};
> +
> +static inline struct mchp_lvds *bridge_to_lvds(struct drm_bridge *bridge)
> +{
> + return container_of(bridge, struct mchp_lvds, bridge);
> +}
> +
> +static inline u32 lvds_readl(struct mchp_lvds *lvds, u32 offset)
> +{
> + return readl_relaxed(lvds->regs + offset);
> +}
> +
> +static inline void lvds_writel(struct mchp_lvds *lvds, u32 offset, u32 val)
> +{
> + writel_relaxed(val, lvds->regs + offset);
> +}
> +
> +static void lvds_serialiser_on(struct mchp_lvds *lvds)
> +{
> + unsigned long timeout = jiffies + msecs_to_jiffies(LVDS_POLL_TIMEOUT_MS);
> +
> + /* The LVDSC registers can only be written if WPEN is cleared */
> + lvds_writel(lvds, LVDSC_WPMR, (LVDSC_WPMR_WPKEY_PSSWD &
> + LVDSC_WPMR_WPKEY_MASK));
> +
> + /* Wait for the status of configuration registers to be changed */
> + while (lvds_readl(lvds, LVDSC_SR) & LVDSC_SR_CS) {
> + if (time_after(jiffies, timeout)) {
> + DRM_DEV_ERROR(lvds->dev, "%s: timeout error\n",
> + __func__);
> + return;
> + }
> + usleep_range(1000, 2000);
> + }
> +
> + /* Configure the LVDSC */
> + lvds_writel(lvds, LVDSC_CFGR, (LVDSC_CFGR_MAPPING_JEIDA |
> + LVDSC_CFGR_DC_UNBALANCED |
> + LVDSC_CFGR_DEN_POL_HIGH |
> + LVDSC_CFGR_PIXSIZE_24BITS));
> +
> + /* Enable the LVDS serializer */
> + lvds_writel(lvds, LVDSC_CR, LVDSC_CR_SER_EN);
> +}
> +
> +static int mchp_lvds_attach(struct drm_bridge *bridge,
> + enum drm_bridge_attach_flags flags)
> +{
> + struct mchp_lvds *lvds = bridge_to_lvds(bridge);
> +
> + bridge->encoder->encoder_type = DRM_MODE_ENCODER_LVDS;
> +
> + return drm_bridge_attach(bridge->encoder, lvds->panel_bridge,
> + bridge, flags);
> +}
> +
> +static void mchp_lvds_enable(struct drm_bridge *bridge)
> +{
> + struct mchp_lvds *lvds = bridge_to_lvds(bridge);
> + int ret;
> +
> + ret = clk_enable(lvds->pclk);
> + if (ret < 0) {
> + DRM_DEV_ERROR(lvds->dev, "failed to enable lvds pclk %d\n", ret);
> + return;
> + }
> +
> + ret = pm_runtime_get_sync(lvds->dev);
> + if (ret < 0) {
> + DRM_DEV_ERROR(lvds->dev, "failed to get pm runtime: %d\n", ret);
> + clk_disable(lvds->pclk);
> + return;
> + }
> +
> + lvds_serialiser_on(lvds);
> +}
> +
> +static void mchp_lvds_disable(struct drm_bridge *bridge)
> +{
> + struct mchp_lvds *lvds = bridge_to_lvds(bridge);
> +
> + pm_runtime_put(lvds->dev);
> + clk_disable(lvds->pclk);
> +}
> +
> +static const struct drm_bridge_funcs mchp_lvds_bridge_funcs = {
> + .attach = mchp_lvds_attach,
> + .enable = mchp_lvds_enable,
> + .disable = mchp_lvds_disable,
> +};
> +
> +static int mchp_lvds_probe(struct platform_device *pdev)
> +{
> + struct device *dev = &pdev->dev;
> + struct mchp_lvds *lvds;
> + struct device_node *port;
> +
> + if (!dev->of_node)
> + return -ENODEV;
> +
> + lvds = devm_kzalloc(&pdev->dev, sizeof(*lvds), GFP_KERNEL);
> + if (!lvds)
> + return -ENOMEM;
> +
> + lvds->dev = dev;
> +
> + lvds->regs = devm_ioremap_resource(lvds->dev,
> + platform_get_resource(pdev, IORESOURCE_MEM, 0));
> + if (IS_ERR(lvds->regs))
> + return PTR_ERR(lvds->regs);
> +
> + lvds->pclk = devm_clk_get_prepared(lvds->dev, "pclk");
> + if (IS_ERR(lvds->pclk))
> + return dev_err_probe(lvds->dev, PTR_ERR(lvds->pclk),
> + "could not get pclk_lvds prepared\n");
> +
> + port = of_graph_get_remote_node(dev->of_node, 1, 0);
> + if (!port) {
> + DRM_DEV_ERROR(dev,
> + "can't find port point, please init lvds panel port!\n");
> + return -ENODEV;
> + }
> +
> + lvds->panel = of_drm_find_panel(port);
> + of_node_put(port);
> +
> + if (IS_ERR(lvds->panel))
> + return -EPROBE_DEFER;
> +
> + lvds->panel_bridge = devm_drm_panel_bridge_add(dev, lvds->panel);
> +
> + if (IS_ERR(lvds->panel_bridge))
> + return PTR_ERR(lvds->panel_bridge);
> +
> + lvds->bridge.of_node = dev->of_node;
> + lvds->bridge.type = DRM_MODE_CONNECTOR_LVDS;
> + lvds->bridge.funcs = &mchp_lvds_bridge_funcs;
> +
> + dev_set_drvdata(dev, lvds);
> + devm_pm_runtime_enable(dev);
> +
> + drm_bridge_add(&lvds->bridge);
> +
> + return 0;
> +}
> +
> +static const struct of_device_id mchp_lvds_dt_ids[] = {
> + {
> + .compatible = "microchip,sam9x75-lvds",
> + },
> + {},
> +};
> +MODULE_DEVICE_TABLE(of, mchp_lvds_dt_ids);
> +
> +static struct platform_driver mchp_lvds_driver = {
> + .probe = mchp_lvds_probe,
> + .driver = {
> + .name = "microchip-lvds",
> + .of_match_table = mchp_lvds_dt_ids,
> + },
> +};
> +module_platform_driver(mchp_lvds_driver);
> +
> +MODULE_AUTHOR("Manikandan Muralidharan <manikandan.m@microchip.com>");
> +MODULE_AUTHOR("Dharma Balasubiramani <dharma.b@microchip.com>");
> +MODULE_DESCRIPTION("Low Voltage Differential Signaling Controller Driver");
> +MODULE_LICENSE("GPL");
^ permalink raw reply
* Re: [PATCH v2] dt-bindings: omap-mcpdm: Convert to DT schema
From: Mithil @ 2024-04-07 7:11 UTC (permalink / raw)
To: Krzysztof Kozlowski
Cc: Liam Girdwood, Mark Brown, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, alsa-devel, devicetree, linux-kernel
In-Reply-To: <352672fc-b6e1-458e-b4f9-840a8ba07c7e@linaro.org>
On Fri, Apr 5, 2024 at 11:49 PM Krzysztof Kozlowski
<krzysztof.kozlowski@linaro.org> wrote:
>
> On 05/04/2024 19:21, Mithil wrote:
> > On Fri, Apr 5, 2024 at 10:38 PM Krzysztof Kozlowski
> > <krzysztof.kozlowski@linaro.org> wrote:
> >>
> >> On 05/04/2024 18:29, Mithil wrote:
> >>> On Fri, Apr 5, 2024 at 9:27 PM Krzysztof Kozlowski
> >>> <krzysztof.kozlowski@linaro.org> wrote:
> >>>>
> >>>> On 05/04/2024 16:48, Mithil wrote:
> >>>>> So sorry about the 2nd patch being sent as a new mail, here is a new
> >>>>> patch with the changes as suggested
> >>>>>
> >>>>>> Please use subject prefixes matching the subsystem
> >>>>> Changed the patch name to match the folder history.
> >>>>
> >>>> Nothing improved. What the history tells you?
> >>>>
> >>>
> >>> Referred to "ASoC: dt-bindings: rt1015: Convert to dtschema"
> >>> Not really sure what else I should change.
> >>
> >> But the subject you wrote here is "dt-bindings: omap-mcpdm: Convert to
> >> DT schema"?
> >>
> >> Where is the ASoC?
> >>
> > I did change it, will send the patch again.
> >
> >>
> >> reg is not correct. Please point me to files doing that way, so I can
> >> fix them.
> >>
> >> You need items with description.
> >>
> > Documentation/devicetree/bindings/sound/fsl,imx-asrc.yaml
> > I referred here for the description, but will add items for the 2 regs
>
> I don't see at all the code you are using. It's entirely different!
> Where in this file is that type of "reg" property?
>
Changed it to use items and description. Was not aware about this
format apologies.
> >
> >>> Interrupts and hwmods use maxItems now.
> >>
> >> hwmods lost description, why?
> > Seems self explanatory.
>
> Really? Not to me. I have no clue what this is. Also, you need
> description for (almost) every non-standard, vendor property.
>
Re-added it as it was previously.
> >
> >>> Changed nodename to be generic in example as well.
> >>
> >> "mcpdm" does not feel generic. What is mcpdm? Google finds nothing.
> >> Maybe just "pdm"?
> >>
> > Multichannel PDM Controller. Kept it like that since the node is also
>
> You said you "changed nodename". So from what did you change to what?
>
> > called as mcpdm in the devicetree. Calling it pdm might cause
>
> Poor DTS is not the example...
>
> > confusion.
>
> So far I am confused. Often name of SoC block is specific, not generic.
> Anyway, that's not important part, so if you claim mcpdm is generic name
> of a class of devices, I am fine.
>
Changed to pdm.
Here's the patch,
From 9fb94e551da1ff06d489f60d52335001a9de9976 Mon Sep 17 00:00:00 2001
From: Mithil Bavishi <bavishimithil@gmail.com>
Date: Mon, 1 Apr 2024 21:10:15 +0530
Subject: [PATCH] ASoC: dt-bindings: omap-mcpdm: Convert to DT schema
Convert the OMAP4+ McPDM bindings to DT schema.
Signed-off-by: Mithil Bavishi <bavishimithil@gmail.com>
---
.../devicetree/bindings/sound/omap-mcpdm.txt | 30 ----------
.../bindings/sound/ti,omap4-mcpdm.yaml | 58 +++++++++++++++++++
2 files changed, 58 insertions(+), 30 deletions(-)
delete mode 100644 Documentation/devicetree/bindings/sound/omap-mcpdm.txt
create mode 100644 Documentation/devicetree/bindings/sound/ti,omap4-mcpdm.yaml
diff --git a/Documentation/devicetree/bindings/sound/omap-mcpdm.txt
b/Documentation/devicetree/bindings/sound/omap-mcpdm.txt
deleted file mode 100644
index ff98a0cb5..000000000
--- a/Documentation/devicetree/bindings/sound/omap-mcpdm.txt
+++ /dev/null
@@ -1,30 +0,0 @@
-* Texas Instruments OMAP4+ McPDM
-
-Required properties:
-- compatible: "ti,omap4-mcpdm"
-- reg: Register location and size as an array:
- <MPU access base address, size>,
- <L3 interconnect address, size>;
-- interrupts: Interrupt number for McPDM
-- ti,hwmods: Name of the hwmod associated to the McPDM
-- clocks: phandle for the pdmclk provider, likely <&twl6040>
-- clock-names: Must be "pdmclk"
-
-Example:
-
-mcpdm: mcpdm@40132000 {
- compatible = "ti,omap4-mcpdm";
- reg = <0x40132000 0x7f>, /* MPU private access */
- <0x49032000 0x7f>; /* L3 Interconnect */
- interrupts = <0 112 0x4>;
- interrupt-parent = <&gic>;
- ti,hwmods = "mcpdm";
-};
-
-In board DTS file the pdmclk needs to be added:
-
-&mcpdm {
- clocks = <&twl6040>;
- clock-names = "pdmclk";
- status = "okay";
-};
diff --git a/Documentation/devicetree/bindings/sound/ti,omap4-mcpdm.yaml
b/Documentation/devicetree/bindings/sound/ti,omap4-mcpdm.yaml
new file mode 100644
index 000000000..73fcfaf6e
--- /dev/null
+++ b/Documentation/devicetree/bindings/sound/ti,omap4-mcpdm.yaml
@@ -0,0 +1,58 @@
+# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/sound/ti,omap4-mcpdm.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: OMAP McPDM
+
+maintainers:
+ - Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org>
+
+description:
+ OMAP ALSA SoC DAI driver using McPDM port used by TWL6040
+
+properties:
+ compatible:
+ const: ti,omap4-mcpdm
+
+ reg:
+ items:
+ - description: MPU access base address
+ - description: L3 interconnect address
+
+ interrupts:
+ maxItems: 1
+
+ ti,hwmods:
+ description: Name of the hwmod associated to the McPDM, likely "mcpdm"
+
+ clocks:
+ description: phandle for the pdmclk provider, likely <&twl6040>
+
+ clock-names:
+ description: Must be "pdmclk"
+
+
+required:
+ - compatible
+ - reg
+ - interrupts
+ - ti,hwmods
+ - clocks
+ - clock-names
+
+additionalProperties: false
+
+examples:
+ - |
+ pdm@0 {
+ compatible = "ti,omap4-mcpdm";
+ reg = <0x40132000 0x7f>, /* MPU private access */
+ <0x49032000 0x7f>; /* L3 Interconnect */
+ interrupts = <0 112 0x4>;
+ interrupt-parent = <&gic>;
+ ti,hwmods = "mcpdm";
+ clocks = <&twl6040>;
+ clock-names = "pdmclk";
+ };
--
2.34.1
Best regards,
Mithil
^ permalink raw reply related
* Re: [PATCH v2 0/2] Enable JPEG encoding on rk3588
From: Nicolas Dufresne @ 2024-04-07 8:08 UTC (permalink / raw)
To: Link Mauve
Cc: linux-kernel, Ezequiel Garcia, Philipp Zabel,
Mauro Carvalho Chehab, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Heiko Stuebner, Joerg Roedel, Will Deacon,
Robin Murphy, Sebastian Reichel, Cristian Ciocaltea, Dragan Simic,
Shreeya Patel, Chris Morgan, Andy Yan, Nicolas Frattaroli,
linux-media, linux-rockchip, devicetree, linux-arm-kernel, iommu
In-Reply-To: <ZhAI6tQZTD7BTosI@desktop>
Le vendredi 05 avril 2024 à 16:21 +0200, Link Mauve a écrit :
> On Thu, Apr 04, 2024 at 01:41:15PM -0400, Nicolas Dufresne wrote:
> > Hi,
>
> Hi,
>
> >
> > Le mercredi 27 mars 2024 à 14:41 +0100, Emmanuel Gil Peyrot a écrit :
> > > Only the JPEG encoder is available for now, although there are patches
> > > for the undocumented VP8 encoder floating around[0].
> >
> > [0] seems like a broken link. The VP8 encoder RFC is for RK3399 (and Hantro H1
> > posted by ST more recently). The TRM says "VEPU121(JPEG encoder only)", which
> > suggest that the H.264 and VP8 encoders usually found on the VEPU121 are
> > removed. As Rockchip have remove the synthesize register while modifying the H1
> > IP, it is difficult to verify. Confusingly the H.264 specific registers are
> > documented in the TRM around VEPU121.
>
> Ah, the link became, and was indeed ST’s series:
> https://patchwork.kernel.org/project/linux-rockchip/list/?series=789885&archive=both
>
> But the TRM part 1 says the VEPU121 supports H.264 encoding (page 367),
> and it’s likely they didn’t remove just VP8 support since the codec
> features are pretty close to H.264’s.
>
> >
> > >
> > > This has been tested on a rock-5b, resulting in four /dev/video*
> > > encoders. The userspace program I’ve been using to test them is
> > > Onix[1], using the jpeg-encoder example, it will pick one of these four
> > > at random (but displays the one it picked):
> > > % ffmpeg -i <input image> -pix_fmt yuvj420p temp.yuv
> > > % jpeg-encoder temp.yuv <width> <height> NV12 <quality> output.jpeg
> >
> > I don't like that we exposing each identical cores a separate video nodes. I
> > think we should aim for 1 device, and then multi-plex and schedule de cores from
> > inside the Linux kernel.
>
> I agree, but this should be handled in the driver not in the device
> tree, and it can be done later.
As the behaviour we want is that these cores becomes a group and get schedule
together, its certainly a good time to slow down and evaluate if that part needs
to be improve in the DT too.
Hantro G1/H1 and VEPU/VDPU121 combos originally shared the same sram region. Its
not clear if any of these cores have this limitation and if this should be
expressed in the DT / driver.
>
> >
> > Not doing this now means we'll never have an optimal hardware usage
> > distribution. Just consider two userspace software wanting to do jpeg encoding.
> > If they both take a guess, they may endup using a single core. Where with proper
> > scheduling in V4L2, the kernel will be able to properly distribute the load. I
> > insist on this, since if we merge you changes it becomes an ABI and we can't
> > change it anymore.
>
> Will it really become ABI just like that? Userspace should always
> discover the video nodes and their capabilities and not hardcode e.g. a
> specific /dev/videoN file for a specific codec. I would argue that this
> series would let userspace do JPEG encoding right away, even if in a
> less optimal way than if the driver would round-robin them through a
> single video node, but that can always be added in a future version.
Might be on the gray side, but there is good chances software written for your
specific board can stop working after te grouping is done.
>
> >
> > I understand that this impose a rework of the mem2mem framework so that we can
> > run multiple jobs, but this will be needed anyway on RK3588, since the rkvdec2,
> > which we don't have a driver yet is also multi-core, but you need to use 2 cores
> > when the resolution is close to 8K.
>
> I think the mediatek JPEG driver already supports that, would it be ok
> to do it the same way?
I don't know for JPEG, the MTK vcoder do support cascading cores. This is
different from concurrent cores. In MTK architecture, for some of the codec,
there is LAT (entropy decoder) and CORE (the reconstruction block) that are
split.
Nicolas
^ permalink raw reply
* Re: [PATCH v3 09/25] media: i2c: imx258: Add support for running on 2 CSI data lanes
From: Kieran Bingham @ 2024-04-07 8:51 UTC (permalink / raw)
To: Luis Garcia, Pavel Machek
Cc: linux-media, dave.stevenson, jacopo.mondi, mchehab, robh,
krzysztof.kozlowski+dt, conor+dt, shawnguo, s.hauer, kernel,
festevam, sakari.ailus, devicetree, imx, linux-arm-kernel,
linux-kernel, phone-devel
In-Reply-To: <803b0bd3-e615-41c1-888e-69b6ecca0b8a@luigi311.com>
Quoting Luis Garcia (2024-04-06 06:25:41)
> On 4/3/24 12:45, Pavel Machek wrote:
> > Hi!
> >
> >> +/*
> >> + * 4208x3120 @ 30 fps needs 1267Mbps/lane, 4 lanes.
> >> + * To avoid further computation of clock settings, adopt the same per
> >> + * lane data rate when using 2 lanes, thus allowing a maximum of 15fps.
> >> + */
> >> +static const struct imx258_reg mipi_1267mbps_19_2mhz_2l[] = {
> >> + { 0x0136, 0x13 },
> >> + { 0x0137, 0x33 },
> >> + { 0x0301, 0x0A },
> >> + { 0x0303, 0x02 },
> >> + { 0x0305, 0x03 },
> >> + { 0x0306, 0x00 },
> >> + { 0x0307, 0xC6 },
> >> + { 0x0309, 0x0A },
> >> + { 0x030B, 0x01 },
> >> + { 0x030D, 0x02 },
> >> + { 0x030E, 0x00 },
> >> + { 0x030F, 0xD8 },
> >> + { 0x0310, 0x00 },
> >> +
> >> + { 0x0114, 0x01 },
> >> + { 0x0820, 0x09 },
> >> + { 0x0821, 0xa6 },
> >> + { 0x0822, 0x66 },
> >> + { 0x0823, 0x66 },
> >> +};
> >> +
> >> +static const struct imx258_reg mipi_1267mbps_19_2mhz_4l[] = {
> >> { 0x0136, 0x13 },
> >> { 0x0137, 0x33 },
> >> { 0x0301, 0x05 },
> >
> > I wish we did not have to copy all the magic values like this.
> >
> > Best regards,
> > Pavel
> >
>
> no kidding, magic values everywhere.... it makes it annoying
> for me to move things around because they all start to look
> similar. Down the line we added in more defined names so its
> not as bad but still its bad lol.
This series converts the defines to names, which is great. It would have
been nicer if the series converted first, but I know the history here
means you have done the register naming on top of existing patches - so
I don't think there's a requirement to change the ordering now.
But I see new drivers coming in with register tables. I hope we can
start to apply more pressure to driver submitters to use higher quality
named register sets in the future, now that we have a greater precendent
of sensor drivers 'doing the right thing'.
Sets of tables like we have are basically a binary blob stored as ascii
and make maintainance far more difficult IMO.
Maybe I should hit send on my comments on the latest GalaxyCore driver
coming in that I hesitated on ...
--
Kieran
^ permalink raw reply
* Re: [PATCH v2 1/6] dt-bindings: firmware: arm,scmi: set additionalProperties to true
From: Krzysztof Kozlowski @ 2024-04-07 8:55 UTC (permalink / raw)
To: Peng Fan, Peng Fan (OSS), Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Shawn Guo, Sascha Hauer, Pengutronix Kernel Team,
Fabio Estevam, Sudeep Holla, Cristian Marussi
Cc: devicetree@vger.kernel.org, imx@lists.linux.dev,
linux-arm-kernel@lists.infradead.org,
linux-kernel@vger.kernel.org
In-Reply-To: <DU0PR04MB9417932A6208128FBBB22C4188012@DU0PR04MB9417.eurprd04.prod.outlook.com>
On 07/04/2024 02:37, Peng Fan wrote:
>> Subject: Re: [PATCH v2 1/6] dt-bindings: firmware: arm,scmi: set
>> additionalProperties to true
>>
>> On 05/04/2024 14:39, Peng Fan (OSS) wrote:
>>> From: Peng Fan <peng.fan@nxp.com>
>>>
>>> When adding vendor extension protocols, there is dt-schema warning:
>>> "
>>> imx,scmi.example.dtb: scmi: 'protocol@81', 'protocol@84' do not match
>>> any of the regexes: 'pinctrl-[0-9]+'
>>> "
>>>
>>> Set additionalProperties to true to address the issue.
>>
>> I do not see anything addressed here, except making the binding accepting
>> anything anywhere...
>
> I not wanna add vendor protocols in arm,scmi.yaml, so will introduce
> a new yaml imx.scmi.yaml which add i.MX SCMI protocol extension.
>
> With additionalProperties set to false, I not know how, please suggest.
First of all, you cannot affect negatively existing devices (their
bindings) and your patch does exactly that. This should make you thing
what is the correct approach...
Rob gave you the comment about missing compatible - you still did not
address that.
You need common schema referenced in arm,scmi and your device specific
schema, also using it.
Best regards,
Krzysztof
^ permalink raw reply
* Re: [PATCH v2 2/6] dt-bindings: firmware: add i.MX SCMI Extension protocol
From: Krzysztof Kozlowski @ 2024-04-07 8:57 UTC (permalink / raw)
To: Peng Fan, Peng Fan (OSS), Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Shawn Guo, Sascha Hauer, Pengutronix Kernel Team,
Fabio Estevam, Sudeep Holla, Cristian Marussi
Cc: devicetree@vger.kernel.org, imx@lists.linux.dev,
linux-arm-kernel@lists.infradead.org,
linux-kernel@vger.kernel.org
In-Reply-To: <DU0PR04MB941719A18C3F749E7D180FD888012@DU0PR04MB9417.eurprd04.prod.outlook.com>
On 07/04/2024 02:51, Peng Fan wrote:
>> Subject: Re: [PATCH v2 2/6] dt-bindings: firmware: add i.MX SCMI Extension
>> protocol
>>
>> On 05/04/2024 14:39, Peng Fan (OSS) wrote:
>>> From: Peng Fan <peng.fan@nxp.com>
>>>
>>> Add i.MX SCMI Extension protocols bindings for:
>>> - Battery Backed Secure Module(BBSM)
>>
>> Which is what?
>
> I should say BBM(BBSM + BBNSM), BBM has RTC and ON/OFF
> key features, but BBM is managed by SCMI firmware and exported
> to agent by BBM protocol. So add bindings for i.MX BBM protocol.
>
> Is this ok?
No, I still don't know what is BBSM, BBNSM and BBM.
>
>>
>>> - MISC settings such as General Purpose Registers settings.
>>>
>>> Signed-off-by: Peng Fan <peng.fan@nxp.com>
>>> ---
>>> .../devicetree/bindings/firmware/imx,scmi.yaml | 80
>> ++++++++++++++++++++++
>>> 1 file changed, 80 insertions(+)
>>>
>>> diff --git a/Documentation/devicetree/bindings/firmware/imx,scmi.yaml
>>> b/Documentation/devicetree/bindings/firmware/imx,scmi.yaml
>>> new file mode 100644
>>> index 000000000000..7ee19a661d83
>>> --- /dev/null
>>> +++ b/Documentation/devicetree/bindings/firmware/imx,scmi.yaml
>>> @@ -0,0 +1,80 @@
>>> +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) # Copyright 2024
>>> +NXP %YAML 1.2
>>> +---
>>> +$id:
>>> +https://eur01.safelinks.protection.outlook.com/?url=http%3A%2F%2Fdevi
>>>
>> +cetree.org%2Fschemas%2Ffirmware%2Fimx%2Cscmi.yaml%23&data=05%7
>> C02%7Cp
>>>
>> +eng.fan%40nxp.com%7C5d16781d3eca425a342508dc562910b7%7C686ea
>> 1d3bc2b4c
>>>
>> +6fa92cd99c5c301635%7C0%7C0%7C638479981570959816%7CUnknown%
>> 7CTWFpbGZsb
>>>
>> +3d8eyJWIjoiMC4wLjAwMDAiLCJQIjoiV2luMzIiLCJBTiI6Ik1haWwiLCJXVCI6Mn
>> 0%3D
>>>
>> +%7C0%7C%7C%7C&sdata=mWNwPvu2eyF18MroVOBHb%2Fjeo%2BIHfV5V
>> h%2F9ebdx65MM
>>> +%3D&reserved=0
>>> +$schema:
>>> +https://eur01.safelinks.protection.outlook.com/?url=http%3A%2F%2Fdevi
>>> +cetree.org%2Fmeta-
>> schemas%2Fcore.yaml%23&data=05%7C02%7Cpeng.fan%40nx
>>>
>> +p.com%7C5d16781d3eca425a342508dc562910b7%7C686ea1d3bc2b4c6fa
>> 92cd99c5c
>>>
>> +301635%7C0%7C0%7C638479981570971949%7CUnknown%7CTWFpbGZs
>> b3d8eyJWIjoiM
>>>
>> +C4wLjAwMDAiLCJQIjoiV2luMzIiLCJBTiI6Ik1haWwiLCJXVCI6Mn0%3D%7C0%7
>> C%7C%7
>>>
>> +C&sdata=v4XnGG00D4I8j5MJvDUVYMRTm7yRrvz0V3fUyc5KAAA%3D&reser
>> ved=0
>>> +
>>> +title: i.MX System Control and Management Interface(SCMI) Vendor
>>> +Protocols Extension
>>> +
>>> +maintainers:
>>> + - Peng Fan <peng.fan@nxp.com>
>>> +
>>> +allOf:
>>> + - $ref: arm,scmi.yaml#
>>
>> Sorry, but arm,scmi is a final schema. Is your plan to define some common
>> part?
>
> No. I just wanna add vendor extension per SCMI spec.
>
> 0x80-0xFF:
> Reserved for vendor or platform-specific extensions to this interface
>
> Each vendor may have different usage saying id 0x81, so I add
> i.MX dt-schema file.
>
>>
>>> +
>>> +properties:
>>> + protocol@81:
>>> + $ref: 'arm,scmi.yaml#/$defs/protocol-node'
>>> + unevaluatedProperties: false
>>> + description:
>>> + The BBM Protocol is for managing Battery Backed Secure Module
>> (BBSM) RTC
>>> + and the ON/OFF Key
>>> +
>>> + properties:
>>> + reg:
>>> + const: 0x81
>>> +
>>> + required:
>>> + - reg
>>> +
>>> + protocol@84:
>>> + $ref: 'arm,scmi.yaml#/$defs/protocol-node'
>>> + unevaluatedProperties: false
>>> + description:
>>> + The MISC Protocol is for managing SoC Misc settings, such as
>>> + GPR settings
>>
>> Genera register is not a setting... this is a pleonasm. Please be more specific
>> what is the GPR, MISC protocol etc.
>
> The MISC Protocol is for managing SoC Misc settings, such as SAI MCLK/MQS in
> Always On domain BLK CTRL, SAI_CLK_SEL in WAKEUP BLK CTRL, gpio
> expanders which is under control of SCMI firmware.
So like a bag for everything which you do not want to call something
specific?
No, be specific...
>
>>> +
>>> + properties:
>>> + reg:
>>> + const: 0x84
>>> +
>>> + wakeup-sources:
>>> + description:
>>> + Each entry consists of 2 integers, represents the source
>>> + and electric signal edge
>>
>> Can you answer questions from reviewers?
>
> Sorry. Is this ok?
> minItems: 1
> maxItems: 32
No. Does it answers Rob's question? I see zero correlation to his question.
Do not ignore emails from reviewers but respond to them.
>
>>
>>> + items:
>>> + items:
>>> + - description: the wakeup source
>>> + - description: the wakeup electric signal edge
>>> + $ref: /schemas/types.yaml#/definitions/uint32-matrix
>>> +
>>> + required:
>>> + - reg
>>> +
>>> +additionalProperties: false
>>> +
>>> +examples:
>>> + - |
>>> + firmware {
>>> + scmi {
>>> + compatible = "arm,scmi";
>>
>>> + mboxes = <&mu2 5 0>, <&mu2 3 0>, <&mu2 3 1>;
>>> + shmem = <&scmi_buf0>, <&scmi_buf1>;
>>> +
>>> + #address-cells = <1>;
>>> + #size-cells = <0>;
>>> +
>>> + protocol@81 {
>>> + reg = <0x81>;
>>> + };
>>> +
>>> + protocol@84 {
>>> + reg = <0x84>;
>>> + wakeup-sources = <0x8000 1
>>> + 0x8001 1
>>> + 0x8002 1
>>> + 0x8003 1
>>> + 0x8004 1>;
>>
>> Nothing improved... If you are going to ignore reviews, then you will only get
>> NAKed.
>
> Sorry, you mean the examples, or the whole dt-schema?
*Read comments and respond to them*. Regardless where they are.
Best regards,
Krzysztof
^ permalink raw reply
* Re: [PATCH v9 3/6] dt-bindings: pci: qcom: Add opp table
From: Krzysztof Kozlowski @ 2024-04-07 9:00 UTC (permalink / raw)
To: Krishna chaitanya chundru, Bjorn Andersson, Konrad Dybcio,
Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Manivannan Sadhasivam, Lorenzo Pieralisi,
Krzysztof Wilczyński, Bjorn Helgaas, johan+linaro, bmasney,
djakov
Cc: linux-arm-msm, devicetree, linux-kernel, linux-pci, vireshk,
quic_vbadigan, quic_skananth, quic_nitegupt, quic_parass
In-Reply-To: <20240407-opp_support-v9-3-496184dc45d7@quicinc.com>
On 07/04/2024 06:37, Krishna chaitanya chundru wrote:
> PCIe needs to choose the appropriate performance state of RPMH power
> domain based upon the PCIe gen speed.
>
> Adding the Operating Performance Points table allows to adjust power
> domain performance state and icc peak bw, depending on the PCIe gen
> speed and width.
>
> Signed-off-by: Krishna chaitanya chundru <quic_krichai@quicinc.com>
> ---
Reviewed-by: Krzysztof Kozlowski <krzk@kernel.org>
Best regards,
Krzysztof
^ permalink raw reply
* Re: [PATCH v4 1/2] dt-bindings: arm: qcom: Document the Samsung Galaxy Z Fold5
From: Krzysztof Kozlowski @ 2024-04-07 9:01 UTC (permalink / raw)
To: serdeliuk, Bjorn Andersson, Konrad Dybcio, Rob Herring,
Krzysztof Kozlowski, Conor Dooley
Cc: linux-arm-msm, devicetree, linux-kernel
In-Reply-To: <20240407-samsung-galaxy-zfold5-q5q-v4-1-8b67b1813653@yahoo.com>
On 07/04/2024 07:38, Alexandru Marc Serdeliuc via B4 Relay wrote:
> From: Alexandru Marc Serdeliuc <serdeliuk@yahoo.com>
>
> This documents Samsung Galaxy Z Fold5 (samsung,q5q)
> which is a foldable phone by Samsung based on the sm8550 SoC.
>
> Signed-off-by: Alexandru Marc Serdeliuc <serdeliuk@yahoo.com>
> ---
This is a friendly reminder during the review process.
It looks like you received a tag and forgot to add it.
If you do not know the process, here is a short explanation:
Please add Acked-by/Reviewed-by/Tested-by tags when posting new
versions, under or above your Signed-off-by tag. Tag is "received", when
provided in a message replied to you on the mailing list. Tools like b4
can help here. However, there's no need to repost patches *only* to add
the tags. The upstream maintainer will do that for tags received on the
version they apply.
https://elixir.bootlin.com/linux/v6.5-rc3/source/Documentation/process/submitting-patches.rst#L577
If a tag was not added on purpose, please state why and what changed.
Best regards,
Krzysztof
^ permalink raw reply
* Re: [PATCH v4 2/2] arm64: dts: qcom: sm8550: Add support for Samsung Galaxy Z Fold5
From: Krzysztof Kozlowski @ 2024-04-07 9:03 UTC (permalink / raw)
To: serdeliuk, Bjorn Andersson, Konrad Dybcio, Rob Herring,
Krzysztof Kozlowski, Conor Dooley
Cc: linux-arm-msm, devicetree, linux-kernel
In-Reply-To: <20240407-samsung-galaxy-zfold5-q5q-v4-2-8b67b1813653@yahoo.com>
On 07/04/2024 07:38, Alexandru Marc Serdeliuc via B4 Relay wrote:
> From: Alexandru Marc Serdeliuc <serdeliuk@yahoo.com>
>
> Add support for Samsung Galaxy Z Fold5 (q5q) foldable phone based on sm8550
>
> Currently working features:
> - Framebuffer
> - UFS
> - i2c
> - Buttons
>
> Signed-off-by: Alexandru Marc Serdeliuc <serdeliuk@yahoo.com>
> ---
> arch/arm64/boot/dts/qcom/Makefile | 1 +
Where is the changelog? This is v4 and nothing (neither here nor in
cover letter) explained what was happening with this patchset.
Tags were ignored, so maybe comments as well?
Please provide *full* and detailed changelog.
Best regards,
Krzysztof
^ permalink raw reply
* Re: [PATCH v1 1/1] arm64: dts: imx93-11x11-evk: add rtc PCF2131 support
From: Krzysztof Kozlowski @ 2024-04-07 9:04 UTC (permalink / raw)
To: Joy Zou, ping.bai, robh+dt, krzysztof.kozlowski+dt, conor+dt,
shawnguo, s.hauer
Cc: kernel, festevam, linux-imx, devicetree, imx, linux-arm-kernel,
linux-kernel
In-Reply-To: <20240407051913.1989364-2-joy.zou@nxp.com>
On 07/04/2024 07:19, Joy Zou wrote:
> Support rtc PCF2131 on imx93-11x11-evk.
>
> Signed-off-by: Joy Zou <joy.zou@nxp.com>
> ---
> .../boot/dts/freescale/imx93-11x11-evk.dts | 25 +++++++++++++++++++
> 1 file changed, 25 insertions(+)
>
> diff --git a/arch/arm64/boot/dts/freescale/imx93-11x11-evk.dts b/arch/arm64/boot/dts/freescale/imx93-11x11-evk.dts
> index 07e85a30a25f..065fa3390791 100644
> --- a/arch/arm64/boot/dts/freescale/imx93-11x11-evk.dts
> +++ b/arch/arm64/boot/dts/freescale/imx93-11x11-evk.dts
> @@ -281,6 +281,24 @@ ldo5: LDO5 {
> };
> };
>
> +&lpi2c3 {
> + #address-cells = <1>;
> + #size-cells = <0>;
> + clock-frequency = <400000>;
> + pinctrl-names = "default", "sleep";
> + pinctrl-0 = <&pinctrl_lpi2c3>;
> + pinctrl-1 = <&pinctrl_lpi2c3>;
> + status = "okay";
> +
> + pcf2131: rtc@53 {
> + compatible = "nxp,pcf2131";
> + reg = <0x53>;
> + interrupt-parent = <&pcal6524>;
> + interrupts = <1 IRQ_TYPE_EDGE_FALLING>;
> + status = "okay";
Really, just drop...
Best regards,
Krzysztof
^ permalink raw reply
* Re: [PATCH v4 4/5] dt-bindings: fsl-imx-sdma: Add I2C peripheral types ID
From: Krzysztof Kozlowski @ 2024-04-07 9:04 UTC (permalink / raw)
To: Frank Li, Vinod Koul, Shawn Guo, Sascha Hauer,
Pengutronix Kernel Team, Fabio Estevam, NXP Linux Team,
Rob Herring, Krzysztof Kozlowski, Conor Dooley, Joy Zou
Cc: dmaengine, linux-arm-kernel, linux-kernel, devicetree, imx
In-Reply-To: <20240329-sdma_upstream-v4-4-daeb3067dea7@nxp.com>
On 29/03/2024 15:34, Frank Li wrote:
> Add peripheral types ID 26 for I2C because sdma firmware (sdma-6q: v3.6,
> sdma-7d: v4.6) support I2C DMA transfer.
>
> Signed-off-by: Frank Li <Frank.Li@nxp.com>
This is a friendly reminder during the review process.
It looks like you received a tag and forgot to add it.
If you do not know the process, here is a short explanation:
Please add Acked-by/Reviewed-by/Tested-by tags when posting new
versions, under or above your Signed-off-by tag. Tag is "received", when
provided in a message replied to you on the mailing list. Tools like b4
can help here. However, there's no need to repost patches *only* to add
the tags. The upstream maintainer will do that for tags received on the
version they apply.
https://elixir.bootlin.com/linux/v6.5-rc3/source/Documentation/process/submitting-patches.rst#L577
If a tag was not added on purpose, please state why and what changed.
Best regards,
Krzysztof
^ permalink raw reply
* [PATCH v3 1/2] dt-bindings: arm: qcom: Add Motorola Moto G (2013)
From: Stanislav Jakubek @ 2024-04-07 9:05 UTC (permalink / raw)
To: Bjorn Andersson, Konrad Dybcio, Rob Herring, Krzysztof Kozlowski,
Conor Dooley
Cc: linux-arm-msm, devicetree, linux-arm-kernel, phone-devel,
linux-kernel
Document the Motorola Moto G (2013), which is a smartphone based
on the Qualcomm MSM8226 SoC.
Acked-by: Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org>
Signed-off-by: Stanislav Jakubek <stano.jakubek@gmail.com>
---
Changes in V3:
- no changes
Changes in V2:
- collect Krzysztof's A-b
Documentation/devicetree/bindings/arm/qcom.yaml | 1 +
1 file changed, 1 insertion(+)
diff --git a/Documentation/devicetree/bindings/arm/qcom.yaml b/Documentation/devicetree/bindings/arm/qcom.yaml
index 66beaac60e1d..d2910982ae86 100644
--- a/Documentation/devicetree/bindings/arm/qcom.yaml
+++ b/Documentation/devicetree/bindings/arm/qcom.yaml
@@ -137,6 +137,7 @@ properties:
- microsoft,dempsey
- microsoft,makepeace
- microsoft,moneypenny
+ - motorola,falcon
- samsung,s3ve3g
- const: qcom,msm8226
--
2.34.1
^ permalink raw reply related
* [PATCH v3 2/2] ARM: dts: qcom: Add support for Motorola Moto G (2013)
From: Stanislav Jakubek @ 2024-04-07 9:05 UTC (permalink / raw)
To: Bjorn Andersson, Konrad Dybcio, Rob Herring, Krzysztof Kozlowski,
Conor Dooley
Cc: linux-arm-msm, devicetree, linux-arm-kernel, phone-devel,
linux-kernel
In-Reply-To: <32c507337ab80c550fb1df08f7014d1e31eb4c32.1712480582.git.stano.jakubek@gmail.com>
Add a device tree for the Motorola Moto G (2013) smartphone based
on the Qualcomm MSM8226 SoC.
Initially supported features:
- Buttons (Volume Down/Up, Power)
- eMMC
- Hall Effect Sensor
- SimpleFB display
- TMP108 temperature sensor
- Vibrator
Note: the dhob and shob reserved-memory regions are seemingly a part of some
Motorola specific (firmware?) mechanism, see [1].
[1] https://github.com/LineageOS/android_kernel_motorola_msm8226/blob/cm-14.1/Documentation/devicetree/bindings/misc/hob_ram.txt
Reviewed-by: Konrad Dybcio <konrad.dybcio@linaro.org>
Signed-off-by: Stanislav Jakubek <stano.jakubek@gmail.com>
---
Changes in V3:
- collect Konrad's R-b
Changes in V2:
- split hob-ram reserved-memory region into dhob and shob
- add a note and a link to downstream documentation with more
information about these regions
arch/arm/boot/dts/qcom/Makefile | 1 +
.../boot/dts/qcom/msm8226-motorola-falcon.dts | 359 ++++++++++++++++++
2 files changed, 360 insertions(+)
create mode 100644 arch/arm/boot/dts/qcom/msm8226-motorola-falcon.dts
diff --git a/arch/arm/boot/dts/qcom/Makefile b/arch/arm/boot/dts/qcom/Makefile
index 6478a39b3be5..3eacbf5c0785 100644
--- a/arch/arm/boot/dts/qcom/Makefile
+++ b/arch/arm/boot/dts/qcom/Makefile
@@ -1,5 +1,6 @@
# SPDX-License-Identifier: GPL-2.0
dtb-$(CONFIG_ARCH_QCOM) += \
+ msm8226-motorola-falcon.dtb \
qcom-apq8016-sbc.dtb \
qcom-apq8026-asus-sparrow.dtb \
qcom-apq8026-huawei-sturgeon.dtb \
diff --git a/arch/arm/boot/dts/qcom/msm8226-motorola-falcon.dts b/arch/arm/boot/dts/qcom/msm8226-motorola-falcon.dts
new file mode 100644
index 000000000000..029e1b1659c9
--- /dev/null
+++ b/arch/arm/boot/dts/qcom/msm8226-motorola-falcon.dts
@@ -0,0 +1,359 @@
+// SPDX-License-Identifier: BSD-3-Clause
+
+/dts-v1/;
+
+#include "qcom-msm8226.dtsi"
+#include "pm8226.dtsi"
+
+/delete-node/ &smem_region;
+
+/ {
+ model = "Motorola Moto G (2013)";
+ compatible = "motorola,falcon", "qcom,msm8226";
+ chassis-type = "handset";
+
+ aliases {
+ mmc0 = &sdhc_1;
+ };
+
+ chosen {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ ranges;
+
+ framebuffer@3200000 {
+ compatible = "simple-framebuffer";
+ reg = <0x03200000 0x800000>;
+ width = <720>;
+ height = <1280>;
+ stride = <(720 * 3)>;
+ format = "r8g8b8";
+ vsp-supply = <®_lcd_pos>;
+ vsn-supply = <®_lcd_neg>;
+ vddio-supply = <&vddio_disp_vreg>;
+ };
+ };
+
+ gpio-keys {
+ compatible = "gpio-keys";
+
+ event-hall-sensor {
+ label = "Hall Effect Sensor";
+ gpios = <&tlmm 51 GPIO_ACTIVE_LOW>;
+ linux,input-type = <EV_SW>;
+ linux,code = <SW_LID>;
+ linux,can-disable;
+ };
+
+ key-volume-up {
+ label = "Volume Up";
+ gpios = <&tlmm 106 GPIO_ACTIVE_LOW>;
+ linux,code = <KEY_VOLUMEUP>;
+ debounce-interval = <15>;
+ };
+ };
+
+ vddio_disp_vreg: regulator-vddio-disp {
+ compatible = "regulator-fixed";
+ regulator-name = "vddio_disp";
+ gpio = <&tlmm 34 GPIO_ACTIVE_HIGH>;
+ vin-supply = <&pm8226_l8>;
+ startup-delay-us = <300>;
+ enable-active-high;
+ regulator-boot-on;
+ };
+
+ reserved-memory {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ ranges;
+
+ framebuffer@3200000 {
+ reg = <0x03200000 0x800000>;
+ no-map;
+ };
+
+ dhob@f500000 {
+ reg = <0x0f500000 0x40000>;
+ no-map;
+ };
+
+ shob@f540000 {
+ reg = <0x0f540000 0x2000>;
+ no-map;
+ };
+
+ smem_region: smem@fa00000 {
+ reg = <0x0fa00000 0x100000>;
+ no-map;
+ };
+
+ /* Actually <0x0fa00000 0x500000>, but first 100000 is smem */
+ reserved@fb00000 {
+ reg = <0x0fb00000 0x400000>;
+ no-map;
+ };
+ };
+};
+
+&blsp1_i2c3 {
+ status = "okay";
+
+ regulator@3e {
+ compatible = "ti,tps65132";
+ reg = <0x3e>;
+ pinctrl-0 = <®_lcd_default>;
+ pinctrl-names = "default";
+
+ reg_lcd_pos: outp {
+ regulator-name = "outp";
+ regulator-min-microvolt = <4000000>;
+ regulator-max-microvolt = <6000000>;
+ regulator-active-discharge = <1>;
+ regulator-boot-on;
+ enable-gpios = <&tlmm 31 GPIO_ACTIVE_HIGH>;
+ };
+
+ reg_lcd_neg: outn {
+ regulator-name = "outn";
+ regulator-min-microvolt = <4000000>;
+ regulator-max-microvolt = <6000000>;
+ regulator-active-discharge = <1>;
+ regulator-boot-on;
+ enable-gpios = <&tlmm 33 GPIO_ACTIVE_HIGH>;
+ };
+ };
+
+ temperature-sensor@48 {
+ compatible = "ti,tmp108";
+ reg = <0x48>;
+ interrupts-extended = <&tlmm 13 IRQ_TYPE_LEVEL_LOW>;
+ pinctrl-0 = <&temp_alert_default>;
+ pinctrl-names = "default";
+ #thermal-sensor-cells = <0>;
+ };
+};
+
+&pm8226_resin {
+ linux,code = <KEY_VOLUMEDOWN>;
+ status = "okay";
+};
+
+&pm8226_vib {
+ status = "okay";
+};
+
+&rpm_requests {
+ regulators {
+ compatible = "qcom,rpm-pm8226-regulators";
+
+ pm8226_s3: s3 {
+ regulator-min-microvolt = <1200000>;
+ regulator-max-microvolt = <1300000>;
+ };
+
+ pm8226_s4: s4 {
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <2200000>;
+ };
+
+ pm8226_s5: s5 {
+ regulator-min-microvolt = <1150000>;
+ regulator-max-microvolt = <1150000>;
+ };
+
+ pm8226_l1: l1 {
+ regulator-min-microvolt = <1225000>;
+ regulator-max-microvolt = <1225000>;
+ };
+
+ pm8226_l2: l2 {
+ regulator-min-microvolt = <1200000>;
+ regulator-max-microvolt = <1200000>;
+ };
+
+ pm8226_l3: l3 {
+ regulator-min-microvolt = <750000>;
+ regulator-max-microvolt = <1337500>;
+ };
+
+ pm8226_l4: l4 {
+ regulator-min-microvolt = <1200000>;
+ regulator-max-microvolt = <1200000>;
+ };
+
+ pm8226_l5: l5 {
+ regulator-min-microvolt = <1200000>;
+ regulator-max-microvolt = <1200000>;
+ };
+
+ pm8226_l6: l6 {
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ regulator-allow-set-load;
+ };
+
+ pm8226_l7: l7 {
+ regulator-min-microvolt = <1850000>;
+ regulator-max-microvolt = <1850000>;
+ };
+
+ pm8226_l8: l8 {
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ };
+
+ pm8226_l9: l9 {
+ regulator-min-microvolt = <2050000>;
+ regulator-max-microvolt = <2050000>;
+ };
+
+ pm8226_l10: l10 {
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ };
+
+ pm8226_l12: l12 {
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ };
+
+ pm8226_l14: l14 {
+ regulator-min-microvolt = <2750000>;
+ regulator-max-microvolt = <2750000>;
+ };
+
+ pm8226_l15: l15 {
+ regulator-min-microvolt = <2800000>;
+ regulator-max-microvolt = <2800000>;
+ };
+
+ pm8226_l16: l16 {
+ regulator-min-microvolt = <3000000>;
+ regulator-max-microvolt = <3350000>;
+ };
+
+ pm8226_l17: l17 {
+ regulator-min-microvolt = <2950000>;
+ regulator-max-microvolt = <2950000>;
+ };
+
+ pm8226_l18: l18 {
+ regulator-min-microvolt = <2950000>;
+ regulator-max-microvolt = <2950000>;
+ };
+
+ pm8226_l19: l19 {
+ regulator-min-microvolt = <2850000>;
+ regulator-max-microvolt = <2850000>;
+ };
+
+ pm8226_l20: l20 {
+ regulator-min-microvolt = <3075000>;
+ regulator-max-microvolt = <3075000>;
+ };
+
+ pm8226_l21: l21 {
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <2950000>;
+ regulator-allow-set-load;
+ };
+
+ pm8226_l22: l22 {
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <2950000>;
+ };
+
+ pm8226_l23: l23 {
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <2950000>;
+ };
+
+ pm8226_l24: l24 {
+ regulator-min-microvolt = <1300000>;
+ regulator-max-microvolt = <1350000>;
+ };
+
+ pm8226_l25: l25 {
+ regulator-min-microvolt = <1775000>;
+ regulator-max-microvolt = <2125000>;
+ };
+
+ pm8226_l26: l26 {
+ regulator-min-microvolt = <1225000>;
+ regulator-max-microvolt = <1225000>;
+ };
+
+ pm8226_l27: l27 {
+ regulator-min-microvolt = <2050000>;
+ regulator-max-microvolt = <2050000>;
+ };
+
+ pm8226_l28: l28 {
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <3400000>;
+ regulator-boot-on;
+ };
+
+ pm8226_lvs1: lvs1 {
+ regulator-always-on;
+ };
+ };
+};
+
+&sdhc_1 {
+ vmmc-supply = <&pm8226_l17>;
+ vqmmc-supply = <&pm8226_l6>;
+
+ bus-width = <8>;
+ non-removable;
+
+ status = "okay";
+};
+
+&smbb {
+ qcom,fast-charge-safe-current = <2000000>;
+ qcom,fast-charge-current-limit = <1900000>;
+ qcom,fast-charge-safe-voltage = <4400000>;
+ qcom,minimum-input-voltage = <4300000>;
+
+ status = "okay";
+};
+
+&tlmm {
+ reg_lcd_default: reg-lcd-default-state {
+ pins = "gpio31", "gpio33";
+ function = "gpio";
+ drive-strength = <2>;
+ bias-disable;
+ output-high;
+ };
+
+ reg_vddio_disp_default: reg-vddio-disp-default-state {
+ pins = "gpio34";
+ function = "gpio";
+ drive-strength = <2>;
+ bias-disable;
+ output-high;
+ };
+
+ temp_alert_default: temp-alert-default-state {
+ pins = "gpio13";
+ function = "gpio";
+ drive-strength = <2>;
+ bias-disable;
+ output-disable;
+ };
+};
+
+&usb {
+ extcon = <&smbb>;
+ dr_mode = "peripheral";
+ status = "okay";
+};
+
+&usb_hs_phy {
+ extcon = <&smbb>;
+ v1p8-supply = <&pm8226_l10>;
+ v3p3-supply = <&pm8226_l20>;
+};
--
2.34.1
^ permalink raw reply related
* Re: [PATCH v3 2/2] media: i2c: Add GC05A2 image sensor driver
From: Kieran Bingham @ 2024-04-07 9:08 UTC (permalink / raw)
To: Zhi Mao, krzysztof.kozlowski+dt, mchehab, robh+dt, sakari.ailus
Cc: laurent.pinchart, shengnan.wang, yaya.chang,
Project_Global_Chrome_Upstream_Group, yunkec, conor+dt,
matthias.bgg, angelogioacchino.delregno, jacopo.mondi, zhi.mao,
10572168, hverkuil-cisco, heiko, jernej.skrabec, macromorgan,
linus.walleij, hdegoede, tomi.valkeinen, gerald.loacker,
andy.shevchenko, bingbu.cao, dan.scally, linux-media, devicetree,
linux-kernel, linux-arm-kernel, linux-mediatek
In-Reply-To: <20240403033825.9072-3-zhi.mao@mediatek.com>
Hello,
Thanks for helping extending the kernels sensor driver support.
My comments below can likely be taken with a pinch of salt, as they are
mostly around the tabled register values ... but we have many drivers
which are binary blobs of sensor register values and I think it would be
far more beneficial to clean these up where possible...
So the first question is ... Can we ?
Quoting Zhi Mao (2024-04-03 04:38:25)
> Add a V4L2 sub-device driver for Galaxycore GC05A2 image sensor.
>
> Signed-off-by: Zhi Mao <zhi.mao@mediatek.com>
> ---
> drivers/media/i2c/Kconfig | 10 +
> drivers/media/i2c/Makefile | 1 +
> drivers/media/i2c/gc05a2.c | 1383 ++++++++++++++++++++++++++++++++++++
> 3 files changed, 1394 insertions(+)
> create mode 100644 drivers/media/i2c/gc05a2.c
>
> diff --git a/drivers/media/i2c/Kconfig b/drivers/media/i2c/Kconfig
> index 56f276b920ab..97993bf160f9 100644
> --- a/drivers/media/i2c/Kconfig
> +++ b/drivers/media/i2c/Kconfig
> @@ -70,6 +70,16 @@ config VIDEO_GC0308
> To compile this driver as a module, choose M here: the
> module will be called gc0308.
>
> +config VIDEO_GC05A2
> + tristate "GalaxyCore gc05a2 sensor support"
> + select V4L2_CCI_I2C
> + help
> + This is a Video4Linux2 sensor driver for the GalaxyCore gc05a2
> + camera.
> +
> + To compile this driver as a module, choose M here: the
> + module will be called gc05a2.
> +
> config VIDEO_GC2145
> select V4L2_CCI_I2C
> tristate "GalaxyCore GC2145 sensor support"
> diff --git a/drivers/media/i2c/Makefile b/drivers/media/i2c/Makefile
> index dfbe6448b549..8ed6faf0f854 100644
> --- a/drivers/media/i2c/Makefile
> +++ b/drivers/media/i2c/Makefile
> @@ -38,6 +38,7 @@ obj-$(CONFIG_VIDEO_DW9768) += dw9768.o
> obj-$(CONFIG_VIDEO_DW9807_VCM) += dw9807-vcm.o
> obj-$(CONFIG_VIDEO_ET8EK8) += et8ek8/
> obj-$(CONFIG_VIDEO_GC0308) += gc0308.o
> +obj-$(CONFIG_VIDEO_GC05A2) += gc05a2.o
> obj-$(CONFIG_VIDEO_GC2145) += gc2145.o
> obj-$(CONFIG_VIDEO_HI556) += hi556.o
> obj-$(CONFIG_VIDEO_HI846) += hi846.o
> diff --git a/drivers/media/i2c/gc05a2.c b/drivers/media/i2c/gc05a2.c
> new file mode 100644
> index 000000000000..461d33055a3b
> --- /dev/null
> +++ b/drivers/media/i2c/gc05a2.c
> @@ -0,0 +1,1383 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * Driver for GalaxyCore gc05a2 image sensor
> + *
> + * Copyright 2024 MediaTek
> + *
> + * Zhi Mao <zhi.mao@mediatek.com>
> + */
> +#include <linux/array_size.h>
> +#include <linux/bits.h>
> +#include <linux/clk.h>
> +#include <linux/container_of.h>
> +#include <linux/delay.h>
> +#include <linux/device.h>
> +#include <linux/err.h>
> +#include <linux/gpio/consumer.h>
> +#include <linux/math64.h>
> +#include <linux/mod_devicetable.h>
> +#include <linux/pm_runtime.h>
> +#include <linux/property.h>
> +#include <linux/regulator/consumer.h>
> +#include <linux/types.h>
> +#include <linux/units.h>
> +
> +#include <media/v4l2-cci.h>
> +#include <media/v4l2-ctrls.h>
> +#include <media/v4l2-event.h>
> +#include <media/v4l2-fwnode.h>
> +#include <media/v4l2-subdev.h>
> +
> +#define GC05A2_REG_TEST_PATTERN_EN CCI_REG8(0x008c)
> +#define GC05A2_REG_TEST_PATTERN_IDX CCI_REG8(0x008d)
> +#define GC05A2_TEST_PATTERN_EN 0x01
> +
> +#define GC05A2_STREAMING_REG CCI_REG8(0x0100)
> +
> +#define GC05A2_FLIP_REG CCI_REG8(0x0101)
> +#define GC05A2_FLIP_H_MASK BIT(0)
> +#define GC05A2_FLIP_V_MASK BIT(1)
> +
> +#define GC05A2_EXP_REG CCI_REG16(0x0202)
> +#define GC05A2_EXP_MARGIN 16
> +#define GC05A2_EXP_MIN 4
> +#define GC05A2_EXP_STEP 1
> +
> +#define GC05A2_AGAIN_REG CCI_REG16(0x0204)
> +#define GC05A2_AGAIN_MIN 1024
> +#define GC05A2_AGAIN_MAX (1024 * 16)
> +#define GC05A2_AGAIN_STEP 1
> +
> +#define GC05A2_FRAME_LENGTH_REG CCI_REG16(0x0340)
> +#define GC05A2_VTS_MAX 0xffff
> +
> +#define GC05A2_REG_CHIP_ID CCI_REG16(0x03f0)
> +#define GC05A2_CHIP_ID 0x05a2
> +
> +#define GC05A2_NATIVE_WIDTH 2592
> +#define GC05A2_NATIVE_HEIGHT 1944
> +
> +#define GC05A2_DEFAULT_CLK_FREQ (24 * HZ_PER_MHZ)
> +#define GC05A2_MBUS_CODE MEDIA_BUS_FMT_SGRBG10_1X10
> +#define GC05A2_DATA_LANES 2
> +#define GC05A2_RGB_DEPTH 10
> +#define GC05A2_SLEEP_US (2 * USEC_PER_MSEC)
> +
> +static const char *const gc05a2_test_pattern_menu[] = {
> + "No Pattern", "Fade_to_gray_Color Bar", "Color Bar",
> + "PN9", "Horizental_gradient", "Checkboard Pattern",
> + "Slant", "Resolution", "Solid Black",
> + "Solid White",
> +};
> +
> +static const s64 gc05a2_link_freq_menu_items[] = {
> + (448 * HZ_PER_MHZ),
> + (224 * HZ_PER_MHZ),
> +};
> +
> +static const char *const gc05a2_supply_name[] = {
> + "avdd",
> + "dvdd",
> + "dovdd",
> +};
> +
> +struct gc05a2 {
> + struct device *dev;
> + struct v4l2_subdev sd;
> + struct media_pad pad;
> +
> + struct clk *xclk;
> + struct regulator_bulk_data supplies[ARRAY_SIZE(gc05a2_supply_name)];
> + struct gpio_desc *reset_gpio;
> +
> + struct v4l2_ctrl_handler ctrls;
> + struct v4l2_ctrl *pixel_rate;
> + struct v4l2_ctrl *link_freq;
> + struct v4l2_ctrl *exposure;
> + struct v4l2_ctrl *vblank;
> + struct v4l2_ctrl *hblank;
> + struct v4l2_ctrl *hflip;
> + struct v4l2_ctrl *vflip;
> +
> + struct regmap *regmap;
> + unsigned long link_freq_bitmap;
> +
> + /* True if the device has been identified */
> + bool identified;
> + const struct gc05a2_mode *cur_mode;
> +};
> +
> +struct gc05a2_reg_list {
> + u32 num_of_regs;
> + const struct cci_reg_sequence *regs;
> +};
> +
> +static const struct cci_reg_sequence mode_2592x1944[] = {
> + /* system */
> + { CCI_REG8(0x0135), 0x01 },
> +
> + /* pre_setting */
> + { CCI_REG8(0x0084), 0x21 },
> + { CCI_REG8(0x0d05), 0xcc },
> + { CCI_REG8(0x0218), 0x00 },
> + { CCI_REG8(0x005e), 0x48 },
> + { CCI_REG8(0x0d06), 0x01 },
> + { CCI_REG8(0x0007), 0x16 },
> + { CCI_REG8(0x0101), 0x00 },
> +
> + /* analog */
> + { CCI_REG8(0x0342), 0x07 },
> + { CCI_REG8(0x0343), 0x28 },
> + { CCI_REG8(0x0220), 0x07 },
> + { CCI_REG8(0x0221), 0xd0 },
> + { CCI_REG8(0x0202), 0x07 },
> + { CCI_REG8(0x0203), 0x32 },
> + { CCI_REG8(0x0340), 0x07 },
> + { CCI_REG8(0x0341), 0xf0 },
> + { CCI_REG8(0x0219), 0x00 },
> + { CCI_REG8(0x0346), 0x00 },
> + { CCI_REG8(0x0347), 0x04 },
> + { CCI_REG8(0x0d14), 0x00 },
> + { CCI_REG8(0x0d13), 0x05 },
> + { CCI_REG8(0x0d16), 0x05 },
> + { CCI_REG8(0x0d15), 0x1d },
> + { CCI_REG8(0x00c0), 0x0a },
> + { CCI_REG8(0x00c1), 0x30 },
> + { CCI_REG8(0x034a), 0x07 },
> + { CCI_REG8(0x034b), 0xa8 },
> + { CCI_REG8(0x0e0a), 0x00 },
> + { CCI_REG8(0x0e0b), 0x00 },
> + { CCI_REG8(0x0e0e), 0x03 },
> + { CCI_REG8(0x0e0f), 0x00 },
> + { CCI_REG8(0x0e06), 0x0a },
> + { CCI_REG8(0x0e23), 0x15 },
> + { CCI_REG8(0x0e24), 0x15 },
> + { CCI_REG8(0x0e2a), 0x10 },
> + { CCI_REG8(0x0e2b), 0x10 },
> + { CCI_REG8(0x0e17), 0x49 },
> + { CCI_REG8(0x0e1b), 0x1c },
> + { CCI_REG8(0x0e3a), 0x36 },
> + { CCI_REG8(0x0d11), 0x84 },
> + { CCI_REG8(0x0e52), 0x14 },
> + { CCI_REG8(0x000b), 0x10 },
> + { CCI_REG8(0x0008), 0x08 },
> + { CCI_REG8(0x0223), 0x17 },
> + { CCI_REG8(0x0d27), 0x39 },
> + { CCI_REG8(0x0d22), 0x00 },
> + { CCI_REG8(0x03f6), 0x0d },
> + { CCI_REG8(0x0d04), 0x07 },
> + { CCI_REG8(0x03f3), 0x72 },
> + { CCI_REG8(0x03f4), 0xb8 },
> + { CCI_REG8(0x03f5), 0xbc },
> + { CCI_REG8(0x0d02), 0x73 },
> +
> + /* auto load start */
> + { CCI_REG8(0x00cb), 0x00 },
> +
> + /* OUT 2592*1944 */
> + { CCI_REG8(0x0350), 0x01 },
> + { CCI_REG8(0x0353), 0x00 },
> + { CCI_REG8(0x0354), 0x08 },
> + { CCI_REG8(0x034c), 0x0a },
> + { CCI_REG8(0x034d), 0x20 },
Should/Could this be
{ CCI_REG16(0x034c), 2592 }, /* Width */
> + { CCI_REG8(0x021f), 0x14 },
> +
> + /* MIPI */
> + { CCI_REG8(0x0107), 0x05 },
> + { CCI_REG8(0x0117), 0x01 },
> + { CCI_REG8(0x0d81), 0x00 },
> + { CCI_REG8(0x0d84), 0x0c },
> + { CCI_REG8(0x0d85), 0xa8 },
> + { CCI_REG8(0x0d86), 0x06 },
> + { CCI_REG8(0x0d87), 0x55 },
> + { CCI_REG8(0x0db3), 0x06 },
> + { CCI_REG8(0x0db4), 0x08 },
> + { CCI_REG8(0x0db5), 0x1e },
> + { CCI_REG8(0x0db6), 0x02 },
> + { CCI_REG8(0x0db8), 0x12 },
> + { CCI_REG8(0x0db9), 0x0a },
> + { CCI_REG8(0x0d93), 0x06 },
> + { CCI_REG8(0x0d94), 0x09 },
> + { CCI_REG8(0x0d95), 0x0d },
> + { CCI_REG8(0x0d99), 0x0b },
> + { CCI_REG8(0x0084), 0x01 },
> +
> + /* OUT */
> + { CCI_REG8(0x0110), 0x01 },
> +};
> +
> +static const struct cci_reg_sequence mode_1280x720[] = {
> + /* system */
> + { CCI_REG8(0x0135), 0x05 },
In 2592x1944 this is 0x01. Do you have a datasheet? Can you explain why
they are different? Can you add register definitions that have names to
make this more maintainable or extendable in the future?
There's discussion in the recent series improving the IMX258 which makes
me wonder if we should try harder to have sensor drivers with clearer
definitions.
> +
> + /*pre_setting*/
/* pre_setting */ ?
> + { CCI_REG8(0x0084), 0x21 },
> + { CCI_REG8(0x0d05), 0xcc },
> + { CCI_REG8(0x0218), 0x80 },
> + { CCI_REG8(0x005e), 0x49 },
> + { CCI_REG8(0x0d06), 0x81 },
> + { CCI_REG8(0x0007), 0x16 },
> + { CCI_REG8(0x0101), 0x00 },
In 2592x1944, only register 0x0218 differs. Why? What is that? Can it be
broken out to a function that applies the correct configuration at
startuup based on a parameter instead of duplicating this table set?
> +
> + /* analog */
> + { CCI_REG8(0x0342), 0x07 },
> + { CCI_REG8(0x0343), 0x10 },
> + { CCI_REG8(0x0220), 0x07 },
> + { CCI_REG8(0x0221), 0xd0 },
> + { CCI_REG8(0x0202), 0x03 },
> + { CCI_REG8(0x0203), 0x32 },
> + { CCI_REG8(0x0340), 0x04 },
> + { CCI_REG8(0x0341), 0x08 },
> + { CCI_REG8(0x0219), 0x00 },
> + { CCI_REG8(0x0346), 0x01 },
> + { CCI_REG8(0x0347), 0x00 },
> + { CCI_REG8(0x0d14), 0x00 },
> + { CCI_REG8(0x0d13), 0x05 },
> + { CCI_REG8(0x0d16), 0x05 },
> + { CCI_REG8(0x0d15), 0x1d },
> + { CCI_REG8(0x00c0), 0x0a },
> + { CCI_REG8(0x00c1), 0x30 },
> + { CCI_REG8(0x034a), 0x05 },
> + { CCI_REG8(0x034b), 0xb0 },
> + { CCI_REG8(0x0e0a), 0x00 },
> + { CCI_REG8(0x0e0b), 0x00 },
> + { CCI_REG8(0x0e0e), 0x03 },
> + { CCI_REG8(0x0e0f), 0x00 },
> + { CCI_REG8(0x0e06), 0x0a },
> + { CCI_REG8(0x0e23), 0x15 },
> + { CCI_REG8(0x0e24), 0x15 },
> + { CCI_REG8(0x0e2a), 0x10 },
> + { CCI_REG8(0x0e2b), 0x10 },
> + { CCI_REG8(0x0e17), 0x49 },
> + { CCI_REG8(0x0e1b), 0x1c },
> + { CCI_REG8(0x0e3a), 0x36 },
> + { CCI_REG8(0x0d11), 0x84 },
> + { CCI_REG8(0x0e52), 0x14 },
> + { CCI_REG8(0x000b), 0x0e },
> + { CCI_REG8(0x0008), 0x03 },
> + { CCI_REG8(0x0223), 0x16 },
> + { CCI_REG8(0x0d27), 0x39 },
> + { CCI_REG8(0x0d22), 0x00 },
> + { CCI_REG8(0x03f6), 0x0d },
> + { CCI_REG8(0x0d04), 0x07 },
> + { CCI_REG8(0x03f3), 0x72 },
> + { CCI_REG8(0x03f4), 0xb8 },
> + { CCI_REG8(0x03f5), 0xbc },
> + { CCI_REG8(0x0d02), 0x73 },
> +
Are any of those able to be broken out to named register to be more
clear in their intent?
> + /* auto load start */
> + { CCI_REG8(0x00cb), 0xfc },
> +
Why is this auto load start so different to the other modes 'auto load
start'? What do the bits refer to ?
> + /* OUT 1280x720 */
> + { CCI_REG8(0x0350), 0x01 },
> + { CCI_REG8(0x0353), 0x00 },
> + { CCI_REG8(0x0354), 0x0c },
> + { CCI_REG8(0x034c), 0x05 },
> + { CCI_REG8(0x034d), 0x00 },
Should/Could this be
{ CCI_REG16(0x034c), 1280 },
Are there any other register settings that would make more sense to be
in decimal units that match their actual context?
> + { CCI_REG8(0x021f), 0x14 },
I don't see a setting for 720/0x2d0. Do these registers only set the
width?
> +
> + /* MIPI */
> + { CCI_REG8(0x0107), 0x05 },
> + { CCI_REG8(0x0117), 0x01 },
> + { CCI_REG8(0x0d81), 0x00 },
> + { CCI_REG8(0x0d84), 0x06 },
> + { CCI_REG8(0x0d85), 0x40 },
> + { CCI_REG8(0x0d86), 0x03 },
> + { CCI_REG8(0x0d87), 0x21 },
> + { CCI_REG8(0x0db3), 0x03 },
> + { CCI_REG8(0x0db4), 0x04 },
> + { CCI_REG8(0x0db5), 0x0d },
> + { CCI_REG8(0x0db6), 0x01 },
> + { CCI_REG8(0x0db8), 0x04 },
> + { CCI_REG8(0x0db9), 0x06 },
> + { CCI_REG8(0x0d93), 0x03 },
> + { CCI_REG8(0x0d94), 0x04 },
> + { CCI_REG8(0x0d95), 0x05 },
> + { CCI_REG8(0x0d99), 0x06 },
> + { CCI_REG8(0x0084), 0x01 },
> +
> + /* OUT */
Out where? What is out?
> + { CCI_REG8(0x0110), 0x01 },
> +};
> +
> +static const struct cci_reg_sequence mode_table_common[] = {
> + { GC05A2_STREAMING_REG, 0x00 },
> + /* system */
> + { CCI_REG8(0x0315), 0xd4 },
> + { CCI_REG8(0x0d06), 0x01 },
> + { CCI_REG8(0x0a70), 0x80 },
> + { CCI_REG8(0x031a), 0x00 },
> + { CCI_REG8(0x0314), 0x00 },
> + { CCI_REG8(0x0130), 0x08 },
> + { CCI_REG8(0x0132), 0x01 },
> + { CCI_REG8(0x0136), 0x38 },
> + { CCI_REG8(0x0137), 0x03 },
> + { CCI_REG8(0x0134), 0x5b },
> + { CCI_REG8(0x031c), 0xe0 },
> + { CCI_REG8(0x0d82), 0x14 },
> + { CCI_REG8(0x0dd1), 0x56 },
> +
> + /* gate_mode */
> + { CCI_REG8(0x0af4), 0x01 },
> + { CCI_REG8(0x0002), 0x10 },
> + { CCI_REG8(0x00c3), 0x34 },
> +
> + /* auto load start */
The previous 'auto load start' referenced 0x00cb ?
> + { CCI_REG8(0x00c4), 0x00 },
> + { CCI_REG8(0x00c5), 0x01 },
> + { CCI_REG8(0x0af6), 0x00 },
> + { CCI_REG8(0x0ba0), 0x17 },
> + { CCI_REG8(0x0ba1), 0x00 },
> + { CCI_REG8(0x0ba2), 0x00 },
> + { CCI_REG8(0x0ba3), 0x00 },
> + { CCI_REG8(0x0ba4), 0x03 },
> + { CCI_REG8(0x0ba5), 0x00 },
> + { CCI_REG8(0x0ba6), 0x00 },
> + { CCI_REG8(0x0ba7), 0x00 },
> + { CCI_REG8(0x0ba8), 0x40 },
> + { CCI_REG8(0x0ba9), 0x00 },
> + { CCI_REG8(0x0baa), 0x00 },
> + { CCI_REG8(0x0bab), 0x00 },
> + { CCI_REG8(0x0bac), 0x40 },
> + { CCI_REG8(0x0bad), 0x00 },
> + { CCI_REG8(0x0bae), 0x00 },
> + { CCI_REG8(0x0baf), 0x00 },
> + { CCI_REG8(0x0bb0), 0x02 },
> + { CCI_REG8(0x0bb1), 0x00 },
> + { CCI_REG8(0x0bb2), 0x00 },
> + { CCI_REG8(0x0bb3), 0x00 },
> + { CCI_REG8(0x0bb8), 0x02 },
> + { CCI_REG8(0x0bb9), 0x00 },
> + { CCI_REG8(0x0bba), 0x00 },
> + { CCI_REG8(0x0bbb), 0x00 },
> + { CCI_REG8(0x0a70), 0x80 },
> + { CCI_REG8(0x0a71), 0x00 },
> + { CCI_REG8(0x0a72), 0x00 },
> + { CCI_REG8(0x0a66), 0x00 },
> + { CCI_REG8(0x0a67), 0x80 },
> + { CCI_REG8(0x0a4d), 0x4e },
> + { CCI_REG8(0x0a50), 0x00 },
> + { CCI_REG8(0x0a4f), 0x0c },
> + { CCI_REG8(0x0a66), 0x00 },
> + { CCI_REG8(0x00ca), 0x00 },
> + { CCI_REG8(0x00cc), 0x00 },
> + { CCI_REG8(0x00cd), 0x00 },
> + { CCI_REG8(0x0aa1), 0x00 },
> + { CCI_REG8(0x0aa2), 0xe0 },
> + { CCI_REG8(0x0aa3), 0x00 },
> + { CCI_REG8(0x0aa4), 0x40 },
> + { CCI_REG8(0x0a90), 0x03 },
> + { CCI_REG8(0x0a91), 0x0e },
> + { CCI_REG8(0x0a94), 0x80 },
> +
> + /* standby */
> + { CCI_REG8(0x0af6), 0x20 },
> + { CCI_REG8(0x0b00), 0x91 },
> + { CCI_REG8(0x0b01), 0x17 },
> + { CCI_REG8(0x0b02), 0x01 },
> + { CCI_REG8(0x0b03), 0x00 },
> + { CCI_REG8(0x0b04), 0x01 },
> + { CCI_REG8(0x0b05), 0x17 },
> + { CCI_REG8(0x0b06), 0x01 },
> + { CCI_REG8(0x0b07), 0x00 },
> + { CCI_REG8(0x0ae9), 0x01 },
> + { CCI_REG8(0x0aea), 0x02 },
> + { CCI_REG8(0x0ae8), 0x53 },
> + { CCI_REG8(0x0ae8), 0x43 },
> +
> + /* gain_partition */
> + { CCI_REG8(0x0af6), 0x30 },
> + { CCI_REG8(0x0b00), 0x08 },
> + { CCI_REG8(0x0b01), 0x0f },
> + { CCI_REG8(0x0b02), 0x00 },
> + { CCI_REG8(0x0b04), 0x1c },
> + { CCI_REG8(0x0b05), 0x24 },
> + { CCI_REG8(0x0b06), 0x00 },
> + { CCI_REG8(0x0b08), 0x30 },
> + { CCI_REG8(0x0b09), 0x40 },
> + { CCI_REG8(0x0b0a), 0x00 },
> + { CCI_REG8(0x0b0c), 0x0e },
> + { CCI_REG8(0x0b0d), 0x2a },
> + { CCI_REG8(0x0b0e), 0x00 },
> + { CCI_REG8(0x0b10), 0x0e },
> + { CCI_REG8(0x0b11), 0x2b },
> + { CCI_REG8(0x0b12), 0x00 },
> + { CCI_REG8(0x0b14), 0x0e },
> + { CCI_REG8(0x0b15), 0x23 },
> + { CCI_REG8(0x0b16), 0x00 },
> + { CCI_REG8(0x0b18), 0x0e },
> + { CCI_REG8(0x0b19), 0x24 },
> + { CCI_REG8(0x0b1a), 0x00 },
> + { CCI_REG8(0x0b1c), 0x0c },
> + { CCI_REG8(0x0b1d), 0x0c },
> + { CCI_REG8(0x0b1e), 0x00 },
> + { CCI_REG8(0x0b20), 0x03 },
> + { CCI_REG8(0x0b21), 0x03 },
> + { CCI_REG8(0x0b22), 0x00 },
> + { CCI_REG8(0x0b24), 0x0e },
> + { CCI_REG8(0x0b25), 0x0e },
> + { CCI_REG8(0x0b26), 0x00 },
> + { CCI_REG8(0x0b28), 0x03 },
> + { CCI_REG8(0x0b29), 0x03 },
> + { CCI_REG8(0x0b2a), 0x00 },
> + { CCI_REG8(0x0b2c), 0x12 },
> + { CCI_REG8(0x0b2d), 0x12 },
> + { CCI_REG8(0x0b2e), 0x00 },
> + { CCI_REG8(0x0b30), 0x08 },
> + { CCI_REG8(0x0b31), 0x08 },
> + { CCI_REG8(0x0b32), 0x00 },
> + { CCI_REG8(0x0b34), 0x14 },
> + { CCI_REG8(0x0b35), 0x14 },
> + { CCI_REG8(0x0b36), 0x00 },
> + { CCI_REG8(0x0b38), 0x10 },
> + { CCI_REG8(0x0b39), 0x10 },
> + { CCI_REG8(0x0b3a), 0x00 },
> + { CCI_REG8(0x0b3c), 0x16 },
> + { CCI_REG8(0x0b3d), 0x16 },
> + { CCI_REG8(0x0b3e), 0x00 },
> + { CCI_REG8(0x0b40), 0x10 },
> + { CCI_REG8(0x0b41), 0x10 },
> + { CCI_REG8(0x0b42), 0x00 },
> + { CCI_REG8(0x0b44), 0x19 },
> + { CCI_REG8(0x0b45), 0x19 },
> + { CCI_REG8(0x0b46), 0x00 },
> + { CCI_REG8(0x0b48), 0x16 },
> + { CCI_REG8(0x0b49), 0x16 },
> + { CCI_REG8(0x0b4a), 0x00 },
> + { CCI_REG8(0x0b4c), 0x19 },
> + { CCI_REG8(0x0b4d), 0x19 },
> + { CCI_REG8(0x0b4e), 0x00 },
> + { CCI_REG8(0x0b50), 0x16 },
> + { CCI_REG8(0x0b51), 0x16 },
> + { CCI_REG8(0x0b52), 0x00 },
> + { CCI_REG8(0x0b80), 0x01 },
> + { CCI_REG8(0x0b81), 0x00 },
> + { CCI_REG8(0x0b82), 0x00 },
> + { CCI_REG8(0x0b84), 0x00 },
> + { CCI_REG8(0x0b85), 0x00 },
> + { CCI_REG8(0x0b86), 0x00 },
> + { CCI_REG8(0x0b88), 0x01 },
> + { CCI_REG8(0x0b89), 0x6a },
> + { CCI_REG8(0x0b8a), 0x00 },
> + { CCI_REG8(0x0b8c), 0x00 },
> + { CCI_REG8(0x0b8d), 0x01 },
> + { CCI_REG8(0x0b8e), 0x00 },
> + { CCI_REG8(0x0b90), 0x01 },
> + { CCI_REG8(0x0b91), 0xf6 },
> + { CCI_REG8(0x0b92), 0x00 },
> + { CCI_REG8(0x0b94), 0x00 },
> + { CCI_REG8(0x0b95), 0x02 },
> + { CCI_REG8(0x0b96), 0x00 },
> + { CCI_REG8(0x0b98), 0x02 },
> + { CCI_REG8(0x0b99), 0xc4 },
> + { CCI_REG8(0x0b9a), 0x00 },
> + { CCI_REG8(0x0b9c), 0x00 },
> + { CCI_REG8(0x0b9d), 0x03 },
> + { CCI_REG8(0x0b9e), 0x00 },
> + { CCI_REG8(0x0ba0), 0x03 },
> + { CCI_REG8(0x0ba1), 0xd8 },
> + { CCI_REG8(0x0ba2), 0x00 },
> + { CCI_REG8(0x0ba4), 0x00 },
> + { CCI_REG8(0x0ba5), 0x04 },
> + { CCI_REG8(0x0ba6), 0x00 },
> + { CCI_REG8(0x0ba8), 0x05 },
> + { CCI_REG8(0x0ba9), 0x4d },
> + { CCI_REG8(0x0baa), 0x00 },
> + { CCI_REG8(0x0bac), 0x00 },
> + { CCI_REG8(0x0bad), 0x05 },
> + { CCI_REG8(0x0bae), 0x00 },
> + { CCI_REG8(0x0bb0), 0x07 },
> + { CCI_REG8(0x0bb1), 0x3e },
> + { CCI_REG8(0x0bb2), 0x00 },
> + { CCI_REG8(0x0bb4), 0x00 },
> + { CCI_REG8(0x0bb5), 0x06 },
> + { CCI_REG8(0x0bb6), 0x00 },
> + { CCI_REG8(0x0bb8), 0x0a },
> + { CCI_REG8(0x0bb9), 0x1a },
> + { CCI_REG8(0x0bba), 0x00 },
> + { CCI_REG8(0x0bbc), 0x09 },
> + { CCI_REG8(0x0bbd), 0x36 },
> + { CCI_REG8(0x0bbe), 0x00 },
> + { CCI_REG8(0x0bc0), 0x0e },
> + { CCI_REG8(0x0bc1), 0x66 },
> + { CCI_REG8(0x0bc2), 0x00 },
> + { CCI_REG8(0x0bc4), 0x10 },
> + { CCI_REG8(0x0bc5), 0x06 },
> + { CCI_REG8(0x0bc6), 0x00 },
> + { CCI_REG8(0x02c1), 0xe0 },
> + { CCI_REG8(0x0207), 0x04 },
> + { CCI_REG8(0x02c2), 0x10 },
> + { CCI_REG8(0x02c3), 0x74 },
> + { CCI_REG8(0x02c5), 0x09 },
> + { CCI_REG8(0x02c1), 0xe0 },
> + { CCI_REG8(0x0207), 0x04 },
> + { CCI_REG8(0x02c2), 0x10 },
> + { CCI_REG8(0x02c5), 0x09 },
> + { CCI_REG8(0x02c1), 0xe0 },
> + { CCI_REG8(0x0207), 0x04 },
> + { CCI_REG8(0x02c2), 0x10 },
> + { CCI_REG8(0x02c5), 0x09 },
> +
> + /* auto load CH_GAIN */
> + { CCI_REG8(0x0aa1), 0x15 },
> + { CCI_REG8(0x0aa2), 0x50 },
> + { CCI_REG8(0x0aa3), 0x00 },
> + { CCI_REG8(0x0aa4), 0x09 },
> + { CCI_REG8(0x0a90), 0x25 },
> + { CCI_REG8(0x0a91), 0x0e },
> + { CCI_REG8(0x0a94), 0x80 },
> +
> + /* ISP */
> + { CCI_REG8(0x0050), 0x00 },
> + { CCI_REG8(0x0089), 0x83 },
> + { CCI_REG8(0x005a), 0x40 },
> + { CCI_REG8(0x00c3), 0x35 },
> + { CCI_REG8(0x00c4), 0x80 },
> + { CCI_REG8(0x0080), 0x10 },
> + { CCI_REG8(0x0040), 0x12 },
> + { CCI_REG8(0x0053), 0x0a },
> + { CCI_REG8(0x0054), 0x44 },
> + { CCI_REG8(0x0055), 0x32 },
> + { CCI_REG8(0x0058), 0x89 },
> + { CCI_REG8(0x004a), 0x03 },
> + { CCI_REG8(0x0048), 0xf0 },
> + { CCI_REG8(0x0049), 0x0f },
> + { CCI_REG8(0x0041), 0x20 },
> + { CCI_REG8(0x0043), 0x0a },
> + { CCI_REG8(0x009d), 0x08 },
> + { CCI_REG8(0x0236), 0x40 },
> +
> + /* gain */
Is the gain configurable? Is this analogue gain? digital gain? or colour
balanace gains ?
> + { CCI_REG8(0x0204), 0x04 },
> + { CCI_REG8(0x0205), 0x00 },
> + { CCI_REG8(0x02b3), 0x00 },
> + { CCI_REG8(0x02b4), 0x00 },
> + { CCI_REG8(0x009e), 0x01 },
> + { CCI_REG8(0x009f), 0x94 },
> +
> + /* auto load REG */
> + { CCI_REG8(0x0aa1), 0x10 },
> + { CCI_REG8(0x0aa2), 0xf8 },
> + { CCI_REG8(0x0aa3), 0x00 },
> + { CCI_REG8(0x0aa4), 0x1f },
> + { CCI_REG8(0x0a90), 0x11 },
> + { CCI_REG8(0x0a91), 0x0e },
> + { CCI_REG8(0x0a94), 0x80 },
> + { CCI_REG8(0x03fe), 0x00 },
> + { CCI_REG8(0x0a90), 0x00 },
> + { CCI_REG8(0x0a70), 0x00 },
> + { CCI_REG8(0x0a67), 0x00 },
> + { CCI_REG8(0x0af4), 0x29 },
> +
> + /* DPHY */
> + { CCI_REG8(0x0d80), 0x07 },
> + { CCI_REG8(0x0dd3), 0x18 },
> +
> + /* CISCTL_Reset */
> + { CCI_REG8(0x031c), 0x80 },
> + { CCI_REG8(0x03fe), 0x30 },
> + { CCI_REG8(0x0d17), 0x06 },
> + { CCI_REG8(0x03fe), 0x00 },
> + { CCI_REG8(0x0d17), 0x00 },
> + { CCI_REG8(0x031c), 0x93 },
> + { CCI_REG8(0x03fe), 0x00 },
> + { CCI_REG8(0x031c), 0x80 },
> + { CCI_REG8(0x03fe), 0x30 },
> + { CCI_REG8(0x0d17), 0x06 },
> + { CCI_REG8(0x03fe), 0x00 },
> + { CCI_REG8(0x0d17), 0x00 },
> + { CCI_REG8(0x031c), 0x93 },
> +};
> +
> +struct gc05a2_mode {
> + u32 width;
> + u32 height;
> + const struct gc05a2_reg_list reg_list;
> +
> + u32 hts; /* Horizontal timining size */
> + u32 vts_def; /* Default vertical timining size */
> + u32 vts_min; /* Min vertical timining size */
> +};
> +
> +/* Declare modes in order, from biggest to smallest height. */
> +static const struct gc05a2_mode gc05a2_modes[] = {
> + {
> + /* 2592*1944@30fps */
> + .width = GC05A2_NATIVE_WIDTH,
> + .height = GC05A2_NATIVE_HEIGHT,
> + .reg_list = {
> + .num_of_regs = ARRAY_SIZE(mode_2592x1944),
> + .regs = mode_2592x1944,
> + },
> + .hts = 3664,
> + .vts_def = 2032,
> + .vts_min = 2032,
> + },
> + {
> + /* 1280*720@60fps */
> + .width = 1280,
> + .height = 720,
> + .reg_list = {
> + .num_of_regs = ARRAY_SIZE(mode_1280x720),
> + .regs = mode_1280x720,
> + },
> + .hts = 3616,
> + .vts_def = 1032,
> + .vts_min = 1032,
> + },
> +};
> +
> +static inline struct gc05a2 *to_gc05a2(struct v4l2_subdev *sd)
> +{
> + return container_of(sd, struct gc05a2, sd);
> +}
> +
> +static int gc05a2_power_on(struct device *dev)
> +{
> + struct v4l2_subdev *sd = dev_get_drvdata(dev);
> + struct gc05a2 *gc05a2 = to_gc05a2(sd);
> + int ret;
> +
> + ret = regulator_bulk_enable(ARRAY_SIZE(gc05a2_supply_name),
> + gc05a2->supplies);
> + if (ret < 0) {
> + dev_err(gc05a2->dev, "failed to enable regulators: %d\n", ret);
> + return ret;
> + }
> +
> + ret = clk_prepare_enable(gc05a2->xclk);
> + if (ret < 0) {
> + regulator_bulk_disable(ARRAY_SIZE(gc05a2_supply_name),
> + gc05a2->supplies);
> + dev_err(gc05a2->dev, "clk prepare enable failed\n");
> + return ret;
> + }
> +
> + fsleep(GC05A2_SLEEP_US);
> +
> + gpiod_set_value_cansleep(gc05a2->reset_gpio, 0);
> + fsleep(GC05A2_SLEEP_US);
> +
> + return 0;
> +}
> +
> +static int gc05a2_power_off(struct device *dev)
> +{
> + struct v4l2_subdev *sd = dev_get_drvdata(dev);
> + struct gc05a2 *gc05a2 = to_gc05a2(sd);
> +
> + clk_disable_unprepare(gc05a2->xclk);
> + gpiod_set_value_cansleep(gc05a2->reset_gpio, 1);
> + regulator_bulk_disable(ARRAY_SIZE(gc05a2_supply_name),
> + gc05a2->supplies);
> +
> + return 0;
> +}
> +
> +static int gc05a2_enum_mbus_code(struct v4l2_subdev *sd,
> + struct v4l2_subdev_state *sd_state,
> + struct v4l2_subdev_mbus_code_enum *code)
> +{
> + if (code->index > 0)
> + return -EINVAL;
> +
> + code->code = GC05A2_MBUS_CODE;
> +
> + return 0;
> +}
> +
> +static int gc05a2_enum_frame_size(struct v4l2_subdev *subdev,
> + struct v4l2_subdev_state *sd_state,
> + struct v4l2_subdev_frame_size_enum *fse)
> +{
> + if (fse->code != GC05A2_MBUS_CODE)
> + return -EINVAL;
> +
> + if (fse->index >= ARRAY_SIZE(gc05a2_modes))
> + return -EINVAL;
> +
> + fse->min_width = gc05a2_modes[fse->index].width;
> + fse->max_width = gc05a2_modes[fse->index].width;
> + fse->min_height = gc05a2_modes[fse->index].height;
> + fse->max_height = gc05a2_modes[fse->index].height;
> +
> + return 0;
> +}
> +
> +static int gc05a2_update_cur_mode_controls(struct gc05a2 *gc05a2,
> + const struct gc05a2_mode *mode)
> +{
> + s64 exposure_max, h_blank;
> + int ret;
> +
> + ret = __v4l2_ctrl_modify_range(gc05a2->vblank,
> + mode->vts_min - mode->height,
> + GC05A2_VTS_MAX - mode->height, 1,
> + mode->vts_def - mode->height);
> + if (ret) {
> + dev_err(gc05a2->dev, "VB ctrl range update failed\n");
> + return ret;
> + }
> +
> + h_blank = mode->hts - mode->width;
> + ret = __v4l2_ctrl_modify_range(gc05a2->hblank, h_blank, h_blank, 1,
> + h_blank);
> + if (ret) {
> + dev_err(gc05a2->dev, "HB ctrl range update failed\n");
> + return ret;
> + }
> +
> + exposure_max = mode->vts_def - GC05A2_EXP_MARGIN;
> + ret = __v4l2_ctrl_modify_range(gc05a2->exposure, GC05A2_EXP_MIN,
> + exposure_max, GC05A2_EXP_STEP,
> + exposure_max);
> + if (ret) {
> + dev_err(gc05a2->dev, "exposure ctrl range update failed\n");
> + return ret;
> + }
> +
> + return 0;
> +}
> +
> +static void gc05a2_update_pad_format(struct gc05a2 *gc08a3,
> + const struct gc05a2_mode *mode,
> + struct v4l2_mbus_framefmt *fmt)
> +{
> + fmt->width = mode->width;
> + fmt->height = mode->height;
> + fmt->code = GC05A2_MBUS_CODE;
> + fmt->field = V4L2_FIELD_NONE;
> + fmt->colorspace = V4L2_COLORSPACE_RAW;
> + fmt->ycbcr_enc = V4L2_MAP_YCBCR_ENC_DEFAULT(fmt->colorspace);
> + fmt->quantization = V4L2_QUANTIZATION_FULL_RANGE;
> + fmt->xfer_func = V4L2_XFER_FUNC_NONE;
> +}
> +
> +static int gc05a2_set_format(struct v4l2_subdev *sd,
> + struct v4l2_subdev_state *state,
> + struct v4l2_subdev_format *fmt)
> +{
> + struct gc05a2 *gc05a2 = to_gc05a2(sd);
> + struct v4l2_mbus_framefmt *mbus_fmt;
> + struct v4l2_rect *crop;
> + const struct gc05a2_mode *mode;
> +
> + mode = v4l2_find_nearest_size(gc05a2_modes, ARRAY_SIZE(gc05a2_modes),
> + width, height, fmt->format.width,
> + fmt->format.height);
> +
> + /* update crop info to subdev state */
> + crop = v4l2_subdev_state_get_crop(state, 0);
> + crop->width = mode->width;
> + crop->height = mode->height;
> +
> + /* update fmt info to subdev state */
> + gc05a2_update_pad_format(gc05a2, mode, &fmt->format);
> + mbus_fmt = v4l2_subdev_state_get_format(state, 0);
> + *mbus_fmt = fmt->format;
> +
> + if (fmt->which == V4L2_SUBDEV_FORMAT_TRY)
> + return 0;
> + gc05a2->cur_mode = mode;
> + gc05a2_update_cur_mode_controls(gc05a2, mode);
> +
> + return 0;
> +}
> +
> +static int gc05a2_get_selection(struct v4l2_subdev *sd,
> + struct v4l2_subdev_state *state,
> + struct v4l2_subdev_selection *sel)
> +{
> + switch (sel->target) {
> + case V4L2_SEL_TGT_CROP_DEFAULT:
> + case V4L2_SEL_TGT_CROP:
> + sel->r = *v4l2_subdev_state_get_crop(state, 0);
> + break;
> + case V4L2_SEL_TGT_CROP_BOUNDS:
> + sel->r.top = 0;
> + sel->r.left = 0;
> + sel->r.width = GC05A2_NATIVE_WIDTH;
> + sel->r.height = GC05A2_NATIVE_HEIGHT;
> + break;
> + default:
> + return -EINVAL;
> + }
> +
> + return 0;
> +}
> +
> +static int gc05a2_init_state(struct v4l2_subdev *sd,
> + struct v4l2_subdev_state *state)
> +{
> + struct v4l2_subdev_format fmt = {
> + .which = V4L2_SUBDEV_FORMAT_TRY,
> + .pad = 0,
> + .format = {
> + .code = GC05A2_MBUS_CODE,
> + .width = gc05a2_modes[0].width,
> + .height = gc05a2_modes[0].height,
> + },
> + };
> +
> + gc05a2_set_format(sd, state, &fmt);
> +
> + return 0;
> +}
> +
> +static int gc05a2_set_ctrl_hflip(struct gc05a2 *gc05a2, u32 ctrl_val)
> +{
> + int ret;
> + u64 val;
> +
> + ret = cci_read(gc05a2->regmap, GC05A2_FLIP_REG, &val, NULL);
> + if (ret) {
> + dev_err(gc05a2->dev, "read hflip register failed: %d\n", ret);
> + return ret;
> + }
> +
> + return cci_update_bits(gc05a2->regmap, GC05A2_FLIP_REG,
> + GC05A2_FLIP_H_MASK,
> + ctrl_val ? GC05A2_FLIP_H_MASK : 0, NULL);
> +}
> +
> +static int gc05a2_set_ctrl_vflip(struct gc05a2 *gc05a2, u32 ctrl_val)
> +{
> + int ret;
> + u64 val;
> +
> + ret = cci_read(gc05a2->regmap, GC05A2_FLIP_REG, &val, NULL);
> + if (ret) {
> + dev_err(gc05a2->dev, "read vflip register failed: %d\n", ret);
> + return ret;
> + }
> +
> + return cci_update_bits(gc05a2->regmap, GC05A2_FLIP_REG,
> + GC05A2_FLIP_V_MASK,
> + ctrl_val ? GC05A2_FLIP_V_MASK : 0, NULL);
> +}
> +
> +static int gc05a2_test_pattern(struct gc05a2 *gc05a2, u32 pattern_menu)
> +{
> + u32 pattern;
> + int ret;
> +
> + if (pattern_menu) {
> + switch (pattern_menu) {
> + case 1:
> + case 2:
> + case 3:
> + case 4:
> + case 5:
> + case 6:
> + case 7:
> + pattern = pattern_menu << 4;
> + break;
> +
> + case 8:
> + pattern = 0;
> + break;
> +
> + case 9:
> + pattern = 4;
> + break;
> +
> + default:
> + pattern = 0x00;
> + break;
> + }
This is fairly terse. Can we add comments, or definitions for the types
or such so that the above is easier to interpret?
> +
> + ret = cci_write(gc05a2->regmap, GC05A2_REG_TEST_PATTERN_IDX,
> + pattern, NULL);
> + if (ret)
> + return ret;
> +
> + return cci_write(gc05a2->regmap, GC05A2_REG_TEST_PATTERN_EN,
> + GC05A2_TEST_PATTERN_EN, NULL);
> + } else {
> + return cci_write(gc05a2->regmap, GC05A2_REG_TEST_PATTERN_EN,
> + 0x00, NULL);
> + }
> +}
> +
> +static int gc05a2_set_ctrl(struct v4l2_ctrl *ctrl)
> +{
> + struct gc05a2 *gc05a2 =
> + container_of(ctrl->handler, struct gc05a2, ctrls);
> + int ret = 0;
> + s64 exposure_max;
> + struct v4l2_subdev_state *state;
> + const struct v4l2_mbus_framefmt *format;
> +
> + state = v4l2_subdev_get_locked_active_state(&gc05a2->sd);
> + format = v4l2_subdev_state_get_format(state, 0);
> +
> + if (ctrl->id == V4L2_CID_VBLANK) {
> + /* Update max exposure while meeting expected vblanking */
> + exposure_max = format->height + ctrl->val - GC05A2_EXP_MARGIN;
> + __v4l2_ctrl_modify_range(gc05a2->exposure,
> + gc05a2->exposure->minimum,
> + exposure_max, gc05a2->exposure->step,
> + exposure_max);
> + }
> +
> + /*
> + * Applying V4L2 control value only happens
> + * when power is on for streaming.
> + */
> + if (!pm_runtime_get_if_active(gc05a2->dev))
> + return 0;
> +
> + switch (ctrl->id) {
> + case V4L2_CID_EXPOSURE:
> + ret = cci_write(gc05a2->regmap, GC05A2_EXP_REG,
> + ctrl->val, NULL);
> + break;
> +
> + case V4L2_CID_ANALOGUE_GAIN:
> + ret = cci_write(gc05a2->regmap, GC05A2_AGAIN_REG,
> + ctrl->val, NULL);
> + break;
> +
> + case V4L2_CID_VBLANK:
> + ret = cci_write(gc05a2->regmap, GC05A2_FRAME_LENGTH_REG,
> + gc05a2->cur_mode->height + ctrl->val, NULL);
> + break;
> +
> + case V4L2_CID_HFLIP:
> + ret = gc05a2_set_ctrl_hflip(gc05a2, ctrl->val);
> + break;
> +
> + case V4L2_CID_VFLIP:
> + ret = gc05a2_set_ctrl_vflip(gc05a2, ctrl->val);
> + break;
> +
> + case V4L2_CID_TEST_PATTERN:
> + ret = gc05a2_test_pattern(gc05a2, ctrl->val);
> + break;
> +
> + default:
> + break;
> + }
> +
> + pm_runtime_put(gc05a2->dev);
> +
> + return ret;
> +}
> +
> +static const struct v4l2_ctrl_ops gc05a2_ctrl_ops = {
> + .s_ctrl = gc05a2_set_ctrl,
> +};
> +
> +static int gc05a2_identify_module(struct gc05a2 *gc05a2)
> +{
> + u64 val;
> + int ret;
> +
> + if (gc05a2->identified)
> + return 0;
> +
> + ret = cci_read(gc05a2->regmap, GC05A2_REG_CHIP_ID, &val, NULL);
> + if (ret)
> + return ret;
> +
> + if (val != GC05A2_CHIP_ID) {
> + dev_err(gc05a2->dev, "chip id mismatch: 0x%x!=0x%llx",
> + GC05A2_CHIP_ID, val);
> + return -ENXIO;
> + }
> +
> + gc05a2->identified = true;
> +
> + return 0;
> +}
> +
> +static int gc05a2_start_streaming(struct gc05a2 *gc05a2)
> +{
> + const struct gc05a2_mode *mode;
> + const struct gc05a2_reg_list *reg_list;
> + int ret;
> +
> + ret = pm_runtime_resume_and_get(gc05a2->dev);
> + if (ret < 0)
> + return ret;
> +
> + ret = gc05a2_identify_module(gc05a2);
> + if (ret)
> + goto err_rpm_put;
> +
> + ret = cci_multi_reg_write(gc05a2->regmap,
> + mode_table_common,
> + ARRAY_SIZE(mode_table_common), NULL);
> + if (ret)
> + goto err_rpm_put;
> +
> + mode = gc05a2->cur_mode;
> + reg_list = &mode->reg_list;
> +
> + ret = cci_multi_reg_write(gc05a2->regmap,
> + reg_list->regs, reg_list->num_of_regs, NULL);
> + if (ret < 0)
> + goto err_rpm_put;
> +
> + ret = __v4l2_ctrl_handler_setup(&gc05a2->ctrls);
> + if (ret < 0) {
> + dev_err(gc05a2->dev, "could not sync v4l2 controls\n");
> + goto err_rpm_put;
> + }
> +
> + ret = cci_write(gc05a2->regmap, GC05A2_STREAMING_REG, 1, NULL);
> + if (ret < 0) {
> + dev_err(gc05a2->dev, "write STREAMING_REG failed: %d\n", ret);
> + goto err_rpm_put;
> + }
> +
> + return 0;
> +
> +err_rpm_put:
> + pm_runtime_put(gc05a2->dev);
> + return ret;
> +}
> +
> +static int gc05a2_stop_streaming(struct gc05a2 *gc05a2)
> +{
> + int ret;
> +
> + ret = cci_write(gc05a2->regmap, GC05A2_STREAMING_REG, 0, NULL);
> + if (ret < 0)
> + dev_err(gc05a2->dev, "could not sent stop streaming %d\n", ret);
> +
> + pm_runtime_put(gc05a2->dev);
> + return ret;
> +}
> +
> +static int gc05a2_s_stream(struct v4l2_subdev *subdev, int enable)
> +{
> + struct gc05a2 *gc05a2 = to_gc05a2(subdev);
> + struct v4l2_subdev_state *state;
> + int ret;
> +
> + state = v4l2_subdev_lock_and_get_active_state(subdev);
> +
> + if (enable)
> + ret = gc05a2_start_streaming(gc05a2);
> + else
> + ret = gc05a2_stop_streaming(gc05a2);
> +
> + v4l2_subdev_unlock_state(state);
> +
> + return ret;
> +}
> +
> +static const struct v4l2_subdev_video_ops gc05a2_video_ops = {
> + .s_stream = gc05a2_s_stream,
> +};
> +
> +static const struct v4l2_subdev_pad_ops gc05a2_subdev_pad_ops = {
> + .enum_mbus_code = gc05a2_enum_mbus_code,
> + .enum_frame_size = gc05a2_enum_frame_size,
> + .get_fmt = v4l2_subdev_get_fmt,
> + .set_fmt = gc05a2_set_format,
> + .get_selection = gc05a2_get_selection,
> +};
> +
> +static const struct v4l2_subdev_core_ops gc05a2_core_ops = {
> + .subscribe_event = v4l2_ctrl_subdev_subscribe_event,
> + .unsubscribe_event = v4l2_event_subdev_unsubscribe,
> +};
> +
> +static const struct v4l2_subdev_ops gc05a2_subdev_ops = {
> + .core = &gc05a2_core_ops,
> + .video = &gc05a2_video_ops,
> + .pad = &gc05a2_subdev_pad_ops,
> +};
> +
> +static const struct v4l2_subdev_internal_ops gc05a2_internal_ops = {
> + .init_state = gc05a2_init_state,
> +};
> +
> +static int gc05a2_get_regulators(struct device *dev, struct gc05a2 *gc05a2)
> +{
> + unsigned int i;
> +
> + for (i = 0; i < ARRAY_SIZE(gc05a2_supply_name); i++)
> + gc05a2->supplies[i].supply = gc05a2_supply_name[i];
> +
> + return devm_regulator_bulk_get(dev, ARRAY_SIZE(gc05a2_supply_name),
> + gc05a2->supplies);
> +}
> +
> +static int gc05a2_parse_fwnode(struct gc05a2 *gc05a2)
> +{
> + struct fwnode_handle *endpoint;
> + struct v4l2_fwnode_endpoint bus_cfg = {
> + .bus_type = V4L2_MBUS_CSI2_DPHY,
> + };
> + int ret;
> + struct device *dev = gc05a2->dev;
> +
> + endpoint =
> + fwnode_graph_get_endpoint_by_id(dev_fwnode(dev), 0, 0,
> + FWNODE_GRAPH_ENDPOINT_NEXT);
> + if (!endpoint) {
> + dev_err(dev, "endpoint node not found\n");
> + return -EINVAL;
> + }
> +
> + ret = v4l2_fwnode_endpoint_alloc_parse(endpoint, &bus_cfg);
> + if (ret) {
> + dev_err(dev, "parsing endpoint node failed\n");
> + goto done;
> + }
> +
> + ret = v4l2_link_freq_to_bitmap(dev, bus_cfg.link_frequencies,
> + bus_cfg.nr_of_link_frequencies,
> + gc05a2_link_freq_menu_items,
> + ARRAY_SIZE(gc05a2_link_freq_menu_items),
> + &gc05a2->link_freq_bitmap);
> + if (ret)
> + goto done;
> +
> +done:
> + v4l2_fwnode_endpoint_free(&bus_cfg);
> + fwnode_handle_put(endpoint);
> + return ret;
> +}
> +
> +static u64 gc05a2_to_pixel_rate(u32 f_index)
> +{
> + u64 pixel_rate =
> + gc05a2_link_freq_menu_items[f_index] * 2 * GC05A2_DATA_LANES;
> +
> + return div_u64(pixel_rate, GC05A2_RGB_DEPTH);
> +}
> +
> +static int gc05a2_init_controls(struct gc05a2 *gc05a2)
> +{
> + struct i2c_client *client = v4l2_get_subdevdata(&gc05a2->sd);
> + const struct gc05a2_mode *mode = &gc05a2_modes[0];
> + const struct v4l2_ctrl_ops *ops = &gc05a2_ctrl_ops;
> + struct v4l2_fwnode_device_properties props;
> + struct v4l2_ctrl_handler *ctrl_hdlr;
> + s64 exposure_max, h_blank;
> + int ret;
> +
> + ctrl_hdlr = &gc05a2->ctrls;
> + ret = v4l2_ctrl_handler_init(ctrl_hdlr, 9);
> + if (ret)
> + return ret;
> +
> + gc05a2->hflip = v4l2_ctrl_new_std(ctrl_hdlr, &gc05a2_ctrl_ops,
> + V4L2_CID_HFLIP, 0, 1, 1, 0);
> + gc05a2->vflip = v4l2_ctrl_new_std(ctrl_hdlr, &gc05a2_ctrl_ops,
> + V4L2_CID_VFLIP, 0, 1, 1, 0);
> + v4l2_ctrl_cluster(2, &gc05a2->hflip);
> +
> + gc05a2->link_freq =
> + v4l2_ctrl_new_int_menu(ctrl_hdlr,
> + &gc05a2_ctrl_ops,
> + V4L2_CID_LINK_FREQ,
> + ARRAY_SIZE(gc05a2_link_freq_menu_items) - 1,
> + 0,
> + gc05a2_link_freq_menu_items);
> + if (gc05a2->link_freq)
> + gc05a2->link_freq->flags |= V4L2_CTRL_FLAG_READ_ONLY;
> +
> + gc05a2->pixel_rate =
> + v4l2_ctrl_new_std(ctrl_hdlr,
> + &gc05a2_ctrl_ops,
> + V4L2_CID_PIXEL_RATE, 0,
> + gc05a2_to_pixel_rate(0),
> + 1,
> + gc05a2_to_pixel_rate(0));
> +
> + gc05a2->vblank =
> + v4l2_ctrl_new_std(ctrl_hdlr,
> + &gc05a2_ctrl_ops, V4L2_CID_VBLANK,
> + mode->vts_min - mode->height,
> + GC05A2_VTS_MAX - mode->height, 1,
> + mode->vts_def - mode->height);
> +
> + h_blank = mode->hts - mode->width;
> + gc05a2->hblank = v4l2_ctrl_new_std(ctrl_hdlr, &gc05a2_ctrl_ops,
> + V4L2_CID_HBLANK, h_blank, h_blank, 1,
> + h_blank);
> + if (gc05a2->hblank)
> + gc05a2->hblank->flags |= V4L2_CTRL_FLAG_READ_ONLY;
> +
> + v4l2_ctrl_new_std(ctrl_hdlr, &gc05a2_ctrl_ops,
> + V4L2_CID_ANALOGUE_GAIN, GC05A2_AGAIN_MIN,
> + GC05A2_AGAIN_MAX, GC05A2_AGAIN_STEP,
> + GC05A2_AGAIN_MIN);
> +
> + exposure_max = mode->vts_def - GC05A2_EXP_MARGIN;
> + gc05a2->exposure = v4l2_ctrl_new_std(ctrl_hdlr, &gc05a2_ctrl_ops,
> + V4L2_CID_EXPOSURE, GC05A2_EXP_MIN,
> + exposure_max, GC05A2_EXP_STEP,
> + exposure_max);
> +
> + v4l2_ctrl_new_std_menu_items(ctrl_hdlr, &gc05a2_ctrl_ops,
> + V4L2_CID_TEST_PATTERN,
> + ARRAY_SIZE(gc05a2_test_pattern_menu) - 1,
> + 0, 0, gc05a2_test_pattern_menu);
> +
> + /* register properties to fwnode (e.g. rotation, orientation) */
> + ret = v4l2_fwnode_device_parse(&client->dev, &props);
> + if (ret)
> + goto error_ctrls;
> +
> + ret = v4l2_ctrl_new_fwnode_properties(ctrl_hdlr, ops, &props);
> + if (ret)
> + goto error_ctrls;
> +
> + if (ctrl_hdlr->error) {
> + ret = ctrl_hdlr->error;
> + goto error_ctrls;
> + }
> +
> + gc05a2->sd.ctrl_handler = ctrl_hdlr;
> +
> + return 0;
> +
> +error_ctrls:
> + v4l2_ctrl_handler_free(ctrl_hdlr);
> +
> + return ret;
> +}
> +
> +static int gc05a2_probe(struct i2c_client *client)
> +{
> + struct device *dev = &client->dev;
> + struct gc05a2 *gc05a2;
> + int ret;
> +
> + gc05a2 = devm_kzalloc(dev, sizeof(*gc05a2), GFP_KERNEL);
> + if (!gc05a2)
> + return -ENOMEM;
> +
> + gc05a2->dev = dev;
> +
> + ret = gc05a2_parse_fwnode(gc05a2);
> + if (ret)
> + return ret;
> +
> + gc05a2->regmap = devm_cci_regmap_init_i2c(client, 16);
> + if (IS_ERR(gc05a2->regmap))
> + return dev_err_probe(dev, PTR_ERR(gc05a2->regmap),
> + "failed to init CCI\n");
> +
> + gc05a2->xclk = devm_clk_get(dev, NULL);
> + if (IS_ERR(gc05a2->xclk))
> + return dev_err_probe(dev, PTR_ERR(gc05a2->xclk),
> + "failed to get xclk\n");
> +
> + ret = clk_set_rate(gc05a2->xclk, GC05A2_DEFAULT_CLK_FREQ);
> + if (ret)
> + return dev_err_probe(dev, ret,
> + "failed to set xclk frequency\n");
> +
> + ret = gc05a2_get_regulators(dev, gc05a2);
> + if (ret < 0)
> + return dev_err_probe(dev, ret,
> + "failed to get regulators\n");
> +
> + gc05a2->reset_gpio = devm_gpiod_get(dev, "reset", GPIOD_OUT_LOW);
> + if (IS_ERR(gc05a2->reset_gpio))
> + return dev_err_probe(dev, PTR_ERR(gc05a2->reset_gpio),
> + "failed to get gpio\n");
> +
> + v4l2_i2c_subdev_init(&gc05a2->sd, client, &gc05a2_subdev_ops);
> + gc05a2->sd.internal_ops = &gc05a2_internal_ops;
> + gc05a2->cur_mode = &gc05a2_modes[0];
> +
> + ret = gc05a2_init_controls(gc05a2);
> + if (ret)
> + return dev_err_probe(dev, ret,
> + "failed to init controls\n");
> +
> + gc05a2->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE |
> + V4L2_SUBDEV_FL_HAS_EVENTS;
> + gc05a2->pad.flags = MEDIA_PAD_FL_SOURCE;
> + gc05a2->sd.dev = &client->dev;
> + gc05a2->sd.entity.function = MEDIA_ENT_F_CAM_SENSOR;
> +
> + ret = media_entity_pads_init(&gc05a2->sd.entity, 1, &gc05a2->pad);
> + if (ret < 0) {
> + dev_err(dev, "could not register media entity\n");
> + goto err_v4l2_ctrl_handler_free;
> + }
> +
> + gc05a2->sd.state_lock = gc05a2->ctrls.lock;
> + ret = v4l2_subdev_init_finalize(&gc05a2->sd);
> + if (ret < 0) {
> + dev_err(dev, "v4l2 subdev init error: %d\n", ret);
> + goto err_media_entity_cleanup;
> + }
> +
> + pm_runtime_set_active(gc05a2->dev);
> + pm_runtime_enable(gc05a2->dev);
> + pm_runtime_set_autosuspend_delay(gc05a2->dev, 1000);
> + pm_runtime_use_autosuspend(gc05a2->dev);
> + pm_runtime_idle(gc05a2->dev);
> +
> + ret = v4l2_async_register_subdev_sensor(&gc05a2->sd);
> + if (ret < 0) {
> + dev_err(dev, "could not register v4l2 device\n");
> + goto err_rpm;
> + }
> +
> + return 0;
> +
> +err_rpm:
> + pm_runtime_disable(gc05a2->dev);
> + v4l2_subdev_cleanup(&gc05a2->sd);
> +
> +err_media_entity_cleanup:
> + media_entity_cleanup(&gc05a2->sd.entity);
> +
> +err_v4l2_ctrl_handler_free:
> + v4l2_ctrl_handler_free(&gc05a2->ctrls);
> +
> + return ret;
> +}
> +
> +static void gc05a2_remove(struct i2c_client *client)
> +{
> + struct v4l2_subdev *sd = i2c_get_clientdata(client);
> + struct gc05a2 *gc05a2 = to_gc05a2(sd);
> +
> + v4l2_async_unregister_subdev(&gc05a2->sd);
> + v4l2_subdev_cleanup(sd);
> + media_entity_cleanup(&gc05a2->sd.entity);
> + v4l2_ctrl_handler_free(&gc05a2->ctrls);
> +
> + pm_runtime_disable(&client->dev);
> + if (!pm_runtime_status_suspended(&client->dev))
> + gc05a2_power_off(gc05a2->dev);
> + pm_runtime_set_suspended(&client->dev);
> +}
> +
> +static const struct of_device_id gc05a2_of_match[] = {
> + { .compatible = "galaxycore,gc05a2" },
> + {}
> +};
> +MODULE_DEVICE_TABLE(of, gc05a2_of_match);
> +
> +static DEFINE_RUNTIME_DEV_PM_OPS(gc05a2_pm_ops,
> + gc05a2_power_off,
> + gc05a2_power_on,
> + NULL);
> +
> +static struct i2c_driver gc05a2_i2c_driver = {
> + .driver = {
> + .of_match_table = gc05a2_of_match,
> + .pm = pm_ptr(&gc05a2_pm_ops),
> + .name = "gc05a2",
> + },
> + .probe = gc05a2_probe,
> + .remove = gc05a2_remove,
> +};
> +module_i2c_driver(gc05a2_i2c_driver);
> +
> +MODULE_DESCRIPTION("GalaxyCore gc05a2 Camera driver");
> +MODULE_AUTHOR("Zhi Mao <zhi.mao@mediatek.com>");
> +MODULE_LICENSE("GPL");
> --
> 2.25.1
>
^ permalink raw reply
* RE: [EXT] Re: [PATCH v1 1/1] arm64: dts: imx93-11x11-evk: add rtc PCF2131 support
From: Joy Zou @ 2024-04-07 9:09 UTC (permalink / raw)
To: Krzysztof Kozlowski, Jacky Bai, robh+dt@kernel.org,
krzysztof.kozlowski+dt@linaro.org, conor+dt@kernel.org,
shawnguo@kernel.org, s.hauer@pengutronix.de
Cc: kernel@pengutronix.de, festevam@gmail.com, dl-linux-imx,
devicetree@vger.kernel.org, imx@lists.linux.dev,
linux-arm-kernel@lists.infradead.org,
linux-kernel@vger.kernel.org
In-Reply-To: <f019690a-2397-4bf8-9472-ec38f4b94c1d@linaro.org>
> -----Original Message-----
> From: Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org>
> Sent: 2024年4月7日 17:04
> To: Joy Zou <joy.zou@nxp.com>; Jacky Bai <ping.bai@nxp.com>;
> robh+dt@kernel.org; krzysztof.kozlowski+dt@linaro.org;
> conor+dt@kernel.org; shawnguo@kernel.org; s.hauer@pengutronix.de
> Cc: kernel@pengutronix.de; festevam@gmail.com; dl-linux-imx
> <linux-imx@nxp.com>; devicetree@vger.kernel.org; imx@lists.linux.dev;
> linux-arm-kernel@lists.infradead.org; linux-kernel@vger.kernel.org
> Subject: [EXT] Re: [PATCH v1 1/1] arm64: dts: imx93-11x11-evk: add rtc
> PCF2131 support
> > +&lpi2c3 {
> > + #address-cells = <1>;
> > + #size-cells = <0>;
> > + clock-frequency = <400000>;
> > + pinctrl-names = "default", "sleep";
> > + pinctrl-0 = <&pinctrl_lpi2c3>;
> > + pinctrl-1 = <&pinctrl_lpi2c3>;
> > + status = "okay";
> > +
> > + pcf2131: rtc@53 {
> > + compatible = "nxp,pcf2131";
> > + reg = <0x53>;
> > + interrupt-parent = <&pcal6524>;
> > + interrupts = <1 IRQ_TYPE_EDGE_FALLING>;
> > + status = "okay";
>
> Really, just drop...
Ok, will drop the status in next version.
Thanks for your comment!
BR
Joy Zou
>
>
> Best regards,
> Krzysztof
^ permalink raw reply
* Re: [PATCH v2] dt-bindings: PCI: altera: Convert to YAML
From: Krzysztof Kozlowski @ 2024-04-07 9:11 UTC (permalink / raw)
To: matthew.gerlach, bhelgaas, lpieralisi, kw, robh,
krzysztof.kozlowski+dt, conor+dt, linux-pci, devicetree,
linux-kernel
In-Reply-To: <20240405145322.3805828-1-matthew.gerlach@linux.intel.com>
On 05/04/2024 16:53, matthew.gerlach@linux.intel.com wrote:
> From: Matthew Gerlach <matthew.gerlach@linux.intel.com>
>
> Convert the device tree bindings for the Altera Root Port PCIe controller
> from text to YAML.
>
> Signed-off-by: Matthew Gerlach <matthew.gerlach@linux.intel.com>
> ---
> v2:
> - Move allOf: to bottom of file, just like example-schema is showing
No, just open it and you will see it is placed differently...
> - add constraint for reg and reg-names
Not complete...
> - remove unneeded device_type
> - drop #address-cells and #size-cells
> - change minItems to maxItems for interrupts:
> - change msi-parent to just "msi-parent: true"
> - cleaned up required:
> - make subject consistent with other commits coverting to YAML
> - s/overt/onvert/g
> ---
> .../devicetree/bindings/pci/altera-pcie.txt | 50 ---------
> .../bindings/pci/altr,pcie-root-port.yaml | 106 ++++++++++++++++++
> 2 files changed, 106 insertions(+), 50 deletions(-)
> delete mode 100644 Documentation/devicetree/bindings/pci/altera-pcie.txt
> create mode 100644 Documentation/devicetree/bindings/pci/altr,pcie-root-port.yaml
>
> diff --git a/Documentation/devicetree/bindings/pci/altera-pcie.txt b/Documentation/devicetree/bindings/pci/altera-pcie.txt
> deleted file mode 100644
> index 816b244a221e..000000000000
> --- a/Documentation/devicetree/bindings/pci/altera-pcie.txt
> +++ /dev/null
> @@ -1,50 +0,0 @@
> -* Altera PCIe controller
> -
> -Required properties:
> -- compatible : should contain "altr,pcie-root-port-1.0" or "altr,pcie-root-port-2.0"
> -- reg: a list of physical base address and length for TXS and CRA.
> - For "altr,pcie-root-port-2.0", additional HIP base address and length.
> -- reg-names: must include the following entries:
> - "Txs": TX slave port region
> - "Cra": Control register access region
> - "Hip": Hard IP region (if "altr,pcie-root-port-2.0")
> -- interrupts: specifies the interrupt source of the parent interrupt
> - controller. The format of the interrupt specifier depends
> - on the parent interrupt controller.
> -- device_type: must be "pci"
> -- #address-cells: set to <3>
> -- #size-cells: set to <2>
> -- #interrupt-cells: set to <1>
> -- ranges: describes the translation of addresses for root ports and
> - standard PCI regions.
> -- interrupt-map-mask and interrupt-map: standard PCI properties to define the
> - mapping of the PCIe interface to interrupt numbers.
> -
> -Optional properties:
> -- msi-parent: Link to the hardware entity that serves as the MSI controller
> - for this PCIe controller.
> -- bus-range: PCI bus numbers covered
> -
> -Example
> - pcie_0: pcie@c00000000 {
> - compatible = "altr,pcie-root-port-1.0";
> - reg = <0xc0000000 0x20000000>,
> - <0xff220000 0x00004000>;
> - reg-names = "Txs", "Cra";
> - interrupt-parent = <&hps_0_arm_gic_0>;
> - interrupts = <0 40 4>;
> - interrupt-controller;
> - #interrupt-cells = <1>;
> - bus-range = <0x0 0xFF>;
> - device_type = "pci";
> - msi-parent = <&msi_to_gic_gen_0>;
> - #address-cells = <3>;
> - #size-cells = <2>;
> - interrupt-map-mask = <0 0 0 7>;
> - interrupt-map = <0 0 0 1 &pcie_0 1>,
> - <0 0 0 2 &pcie_0 2>,
> - <0 0 0 3 &pcie_0 3>,
> - <0 0 0 4 &pcie_0 4>;
> - ranges = <0x82000000 0x00000000 0x00000000 0xc0000000 0x00000000 0x10000000
> - 0x82000000 0x00000000 0x10000000 0xd0000000 0x00000000 0x10000000>;
> - };
> diff --git a/Documentation/devicetree/bindings/pci/altr,pcie-root-port.yaml b/Documentation/devicetree/bindings/pci/altr,pcie-root-port.yaml
> new file mode 100644
> index 000000000000..999dcda05f55
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/pci/altr,pcie-root-port.yaml
> @@ -0,0 +1,106 @@
> +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
> +# Copyright (C) 2024, Intel Corporation
This is derivative of previous work, which is easily visible by doing
the same mistakes in DTS as they were before.
You now added fresh copyrights ignoring all previous work, even though
you copied it. I don't agree.
If you want to ignore previous copyrights, then at least don't copy
existing code... although even that would not be sufficient.
> +%YAML 1.2
> +---
> +$id: http://devicetree.org/schemas/altr,pcie-root-port.yaml#
> +$schema: http://devicetree.org/meta-schemas/core.yaml#
> +
> +title: Altera PCIe Root Port
> +
> +maintainers:
> + - Matthew Gerlach <matthew.gerlach@linux.intel.com>
> +
> +properties:
> + compatible:
> + items:
Drop items.
> + - enum:
> + - altr,pcie-root-port-1.0
> + - altr,pcie-root-port-2.0
> +
Missing reg with constraints.
> + interrupts:
> + maxItems: 1
> +
> + interrupt-map-mask:
> + items:
> + - const: 0
> + - const: 0
> + - const: 0
> + - const: 7
> +
> + interrupt-map:
> + maxItems: 4
> +
> + "#interrupt-cells":
> + const: 1
> +
> + msi-parent: true
> +
> +required:
> + - compatible
> + - reg
> + - reg-names
> + - device_type
> + - interrupts
> + - interrupt-map
> + - interrupt-map-mask
> +
> +unevaluatedProperties: false
> +
> +allOf:
> + - $ref: /schemas/pci/pci-bus.yaml#
That's deprecated, as explained in its description. You should use
pci-host-bridge.yaml.
> + - if:
> + properties:
> + compatible:
> + enum:
> + - altr,pcie-root-port-1.0
> + then:
> + properties:
> + reg:
> + items:
> + - description: TX slave port region
> + - description: Control register access region
> +
> + reg-names:
> + items:
> + - const: Txs
> + - const: Cra
> +
> + else:
> + properties:
> + reg:
> + items:
> + - description: Hard IP region
> + - description: TX slave port region
> + - description: Control register access region
> +
> + reg-names:
> + items:
> + - const: Hip
> + - const: Txs
> + - const: Cra
> +
unevaluated goes here, just like example-schema.
> +examples:
> + - |
> + #include <dt-bindings/interrupt-controller/arm-gic.h>
> + #include <dt-bindings/interrupt-controller/irq.h>
> + pcie_0: pcie@c00000000 {
> + compatible = "altr,pcie-root-port-1.0";
> + reg = <0xc0000000 0x20000000>,
> + <0xff220000 0x00004000>;
> + reg-names = "Txs", "Cra";
> + interrupt-parent = <&hps_0_arm_gic_0>;
> + interrupts = <GIC_SPI 40 IRQ_TYPE_LEVEL_HIGH>;
> + #interrupt-cells = <1>;
> + bus-range = <0x0 0xff>;
> + device_type = "pci";
> + msi-parent = <&msi_to_gic_gen_0>;
> + #address-cells = <3>;
> + #size-cells = <2>;
> + interrupt-map-mask = <0 0 0 7>;
> + interrupt-map = <0 0 0 1 &pcie_intc 1>,
> + <0 0 0 2 &pcie_intc 2>,
> + <0 0 0 3 &pcie_intc 3>,
> + <0 0 0 4 &pcie_intc 4>;
> + ranges = <0x82000000 0x00000000 0x00000000 0xc0000000 0x00000000 0x10000000
> + 0x82000000 0x00000000 0x10000000 0xd0000000 0x00000000 0x10000000>;
That's two entries.
Best regards,
Krzysztof
^ permalink raw reply
* Re: [EXT] Re: [PATCH v1 1/1] arm64: dts: imx93-11x11-evk: add rtc PCF2131 support
From: Krzysztof Kozlowski @ 2024-04-07 9:12 UTC (permalink / raw)
To: Joy Zou, Jacky Bai, robh+dt@kernel.org,
krzysztof.kozlowski+dt@linaro.org, conor+dt@kernel.org,
shawnguo@kernel.org, s.hauer@pengutronix.de
Cc: kernel@pengutronix.de, festevam@gmail.com, dl-linux-imx,
devicetree@vger.kernel.org, imx@lists.linux.dev,
linux-arm-kernel@lists.infradead.org,
linux-kernel@vger.kernel.org
In-Reply-To: <AS4PR04MB9386C629F898A8417AE57506E1012@AS4PR04MB9386.eurprd04.prod.outlook.com>
On 07/04/2024 11:09, Joy Zou wrote:
>
>> -----Original Message-----
>> From: Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org>
>> Sent: 2024年4月7日 17:04
>> To: Joy Zou <joy.zou@nxp.com>; Jacky Bai <ping.bai@nxp.com>;
>> robh+dt@kernel.org; krzysztof.kozlowski+dt@linaro.org;
>> conor+dt@kernel.org; shawnguo@kernel.org; s.hauer@pengutronix.de
>> Cc: kernel@pengutronix.de; festevam@gmail.com; dl-linux-imx
>> <linux-imx@nxp.com>; devicetree@vger.kernel.org; imx@lists.linux.dev;
>> linux-arm-kernel@lists.infradead.org; linux-kernel@vger.kernel.org
>> Subject: [EXT] Re: [PATCH v1 1/1] arm64: dts: imx93-11x11-evk: add rtc
>> PCF2131 support
>>> +&lpi2c3 {
>>> + #address-cells = <1>;
>>> + #size-cells = <0>;
>>> + clock-frequency = <400000>;
>>> + pinctrl-names = "default", "sleep";
>>> + pinctrl-0 = <&pinctrl_lpi2c3>;
>>> + pinctrl-1 = <&pinctrl_lpi2c3>;
>>> + status = "okay";
>>> +
>>> + pcf2131: rtc@53 {
>>> + compatible = "nxp,pcf2131";
>>> + reg = <0x53>;
>>> + interrupt-parent = <&pcal6524>;
>>> + interrupts = <1 IRQ_TYPE_EDGE_FALLING>;
>>> + status = "okay";
>>
>> Really, just drop...
> Ok, will drop the status in next version.
> Thanks for your comment!
Please read DTS coding style.
Best regards,
Krzysztof
^ permalink raw reply
* [PATCH v9 0/4] ASoc: PCM6240: mixer-test report
From: Shenghao Ding @ 2024-04-07 9:18 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
v9:
- Retest with the code with Volume kcontrol
v8:
- use some reasonable format of changelog.
- fixed the format of subject
- remove *** BLURB HERE ***
mixer-test report:
root@am335x-evm:/bin# mixer-test
TAP version 13
# Card 0 - TI BeagleBone Black (TI BeagleBone Black)
1..455
ok 1 get_value.0.64
# 0.64 PCMD3180 i2c2 Profile id
ok 2 name.0.64
ok 3 write_default.0.64
ok 4 write_valid.0.64
ok 5 write_invalid.0.64
ok 6 event_missing.0.64
ok 7 event_spurious.0.64
ok 8 get_value.0.63
# 0.63 PCMD3180 i2c2 Dev3 Ch8 Digi Volume
ok 9 name.0.63
ok 10 write_default.0.63
ok 11 write_valid.0.63
ok 12 write_invalid.0.63
ok 13 event_missing.0.63
ok 14 event_spurious.0.63
ok 15 get_value.0.62
# 0.62 PCMD3180 i2c2 Dev3 Ch7 Digi Volume
ok 16 name.0.62
ok 17 write_default.0.62
ok 18 write_valid.0.62
ok 19 write_invalid.0.62
ok 20 event_missing.0.62
ok 21 event_spurious.0.62
ok 22 get_value.0.61
# 0.61 PCMD3180 i2c2 Dev3 Ch6 Digi Volume
ok 23 name.0.61
ok 24 write_default.0.61
ok 25 write_valid.0.61
ok 26 write_invalid.0.61
ok 27 event_missing.0.61
ok 28 event_spurious.0.61
ok 29 get_value.0.60
# 0.60 PCMD3180 i2c2 Dev3 Ch5 Digi Volume
ok 30 name.0.60
ok 31 write_default.0.60
ok 32 write_valid.0.60
ok 33 write_invalid.0.60
ok 34 event_missing.0.60
ok 35 event_spurious.0.60
ok 36 get_value.0.59
# 0.59 PCMD3180 i2c2 Dev3 Ch4 Digi Volume
ok 37 name.0.59
ok 38 write_default.0.59
ok 39 write_valid.0.59
ok 40 write_invalid.0.59
ok 41 event_missing.0.59
ok 42 event_spurious.0.59
ok 43 get_value.0.58
# 0.58 PCMD3180 i2c2 Dev3 Ch3 Digi Volume
ok 44 name.0.58
ok 45 write_default.0.58
ok 46 write_valid.0.58
ok 47 write_invalid.0.58
ok 48 event_missing.0.58
ok 49 event_spurious.0.58
ok 50 get_value.0.57
# 0.57 PCMD3180 i2c2 Dev3 Ch2 Digi Volume
ok 51 name.0.57
ok 52 write_default.0.57
ok 53 write_valid.0.57
ok 54 write_invalid.0.57
ok 55 event_missing.0.57
ok 56 event_spurious.0.57
ok 57 get_value.0.56
# 0.56 PCMD3180 i2c2 Dev3 Ch1 Digi Volume
ok 58 name.0.56
ok 59 write_default.0.56
ok 60 write_valid.0.56
ok 61 write_invalid.0.56
ok 62 event_missing.0.56
ok 63 event_spurious.0.56
ok 64 get_value.0.55
# 0.55 PCMD3180 i2c2 Dev3 Ch8 Fine Volume
ok 65 name.0.55
ok 66 write_default.0.55
ok 67 write_valid.0.55
ok 68 write_invalid.0.55
ok 69 event_missing.0.55
ok 70 event_spurious.0.55
ok 71 get_value.0.54
# 0.54 PCMD3180 i2c2 Dev3 Ch7 Fine Volume
ok 72 name.0.54
ok 73 write_default.0.54
ok 74 write_valid.0.54
ok 75 write_invalid.0.54
ok 76 event_missing.0.54
ok 77 event_spurious.0.54
ok 78 get_value.0.53
# 0.53 PCMD3180 i2c2 Dev3 Ch6 Fine Volume
ok 79 name.0.53
ok 80 write_default.0.53
ok 81 write_valid.0.53
ok 82 write_invalid.0.53
ok 83 event_missing.0.53
ok 84 event_spurious.0.53
ok 85 get_value.0.52
# 0.52 PCMD3180 i2c2 Dev3 Ch5 Fine Volume
ok 86 name.0.52
ok 87 write_default.0.52
ok 88 write_valid.0.52
ok 89 write_invalid.0.52
ok 90 event_missing.0.52
ok 91 event_spurious.0.52
ok 92 get_value.0.51
# 0.51 PCMD3180 i2c2 Dev3 Ch4 Fine Volume
ok 93 name.0.51
ok 94 write_default.0.51
ok 95 write_valid.0.51
ok 96 write_invalid.0.51
ok 97 event_missing.0.51
ok 98 event_spurious.0.51
ok 99 get_value.0.50
# 0.50 PCMD3180 i2c2 Dev3 Ch3 Fine Volume
ok 100 name.0.50
ok 101 write_default.0.50
ok 102 write_valid.0.50
ok 103 write_invalid.0.50
ok 104 event_missing.0.50
ok 105 event_spurious.0.50
ok 106 get_value.0.49
# 0.49 PCMD3180 i2c2 Dev3 Ch2 Fine Volume
ok 107 name.0.49
ok 108 write_default.0.49
ok 109 write_valid.0.49
ok 110 write_invalid.0.49
ok 111 event_missing.0.49
ok 112 event_spurious.0.49
ok 113 get_value.0.48
# 0.48 PCMD3180 i2c2 Dev3 Ch1 Fine Volume
ok 114 name.0.48
ok 115 write_default.0.48
ok 116 write_valid.0.48
ok 117 write_invalid.0.48
ok 118 event_missing.0.48
ok 119 event_spurious.0.48
ok 120 get_value.0.47
# 0.47 PCMD3180 i2c2 Dev2 Ch8 Digi Volume
ok 121 name.0.47
ok 122 write_default.0.47
ok 123 write_valid.0.47
ok 124 write_invalid.0.47
ok 125 event_missing.0.47
ok 126 event_spurious.0.47
ok 127 get_value.0.46
# 0.46 PCMD3180 i2c2 Dev2 Ch7 Digi Volume
ok 128 name.0.46
ok 129 write_default.0.46
ok 130 write_valid.0.46
ok 131 write_invalid.0.46
ok 132 event_missing.0.46
ok 133 event_spurious.0.46
ok 134 get_value.0.45
# 0.45 PCMD3180 i2c2 Dev2 Ch6 Digi Volume
ok 135 name.0.45
ok 136 write_default.0.45
ok 137 write_valid.0.45
ok 138 write_invalid.0.45
ok 139 event_missing.0.45
ok 140 event_spurious.0.45
ok 141 get_value.0.44
# 0.44 PCMD3180 i2c2 Dev2 Ch5 Digi Volume
ok 142 name.0.44
ok 143 write_default.0.44
ok 144 write_valid.0.44
ok 145 write_invalid.0.44
ok 146 event_missing.0.44
ok 147 event_spurious.0.44
ok 148 get_value.0.43
# 0.43 PCMD3180 i2c2 Dev2 Ch4 Digi Volume
ok 149 name.0.43
ok 150 write_default.0.43
ok 151 write_valid.0.43
ok 152 write_invalid.0.43
ok 153 event_missing.0.43
ok 154 event_spurious.0.43
ok 155 get_value.0.42
# 0.42 PCMD3180 i2c2 Dev2 Ch3 Digi Volume
ok 156 name.0.42
ok 157 write_default.0.42
ok 158 write_valid.0.42
ok 159 write_invalid.0.42
ok 160 event_missing.0.42
ok 161 event_spurious.0.42
ok 162 get_value.0.41
# 0.41 PCMD3180 i2c2 Dev2 Ch2 Digi Volume
ok 163 name.0.41
ok 164 write_default.0.41
ok 165 write_valid.0.41
ok 166 write_invalid.0.41
ok 167 event_missing.0.41
ok 168 event_spurious.0.41
ok 169 get_value.0.40
# 0.40 PCMD3180 i2c2 Dev2 Ch1 Digi Volume
ok 170 name.0.40
ok 171 write_default.0.40
ok 172 write_valid.0.40
ok 173 write_invalid.0.40
ok 174 event_missing.0.40
ok 175 event_spurious.0.40
ok 176 get_value.0.39
# 0.39 PCMD3180 i2c2 Dev2 Ch8 Fine Volume
ok 177 name.0.39
ok 178 write_default.0.39
ok 179 write_valid.0.39
ok 180 write_invalid.0.39
ok 181 event_missing.0.39
ok 182 event_spurious.0.39
ok 183 get_value.0.38
# 0.38 PCMD3180 i2c2 Dev2 Ch7 Fine Volume
ok 184 name.0.38
ok 185 write_default.0.38
ok 186 write_valid.0.38
ok 187 write_invalid.0.38
ok 188 event_missing.0.38
ok 189 event_spurious.0.38
ok 190 get_value.0.37
# 0.37 PCMD3180 i2c2 Dev2 Ch6 Fine Volume
ok 191 name.0.37
ok 192 write_default.0.37
ok 193 write_valid.0.37
ok 194 write_invalid.0.37
ok 195 event_missing.0.37
ok 196 event_spurious.0.37
ok 197 get_value.0.36
# 0.36 PCMD3180 i2c2 Dev2 Ch5 Fine Volume
ok 198 name.0.36
ok 199 write_default.0.36
ok 200 write_valid.0.36
ok 201 write_invalid.0.36
ok 202 event_missing.0.36
ok 203 event_spurious.0.36
ok 204 get_value.0.35
# 0.35 PCMD3180 i2c2 Dev2 Ch4 Fine Volume
ok 205 name.0.35
ok 206 write_default.0.35
ok 207 write_valid.0.35
ok 208 write_invalid.0.35
ok 209 event_missing.0.35
ok 210 event_spurious.0.35
ok 211 get_value.0.34
# 0.34 PCMD3180 i2c2 Dev2 Ch3 Fine Volume
ok 212 name.0.34
ok 213 write_default.0.34
ok 214 write_valid.0.34
ok 215 write_invalid.0.34
ok 216 event_missing.0.34
ok 217 event_spurious.0.34
ok 218 get_value.0.33
# 0.33 PCMD3180 i2c2 Dev2 Ch2 Fine Volume
ok 219 name.0.33
ok 220 write_default.0.33
ok 221 write_valid.0.33
ok 222 write_invalid.0.33
ok 223 event_missing.0.33
ok 224 event_spurious.0.33
ok 225 get_value.0.32
# 0.32 PCMD3180 i2c2 Dev2 Ch1 Fine Volume
ok 226 name.0.32
ok 227 write_default.0.32
ok 228 write_valid.0.32
ok 229 write_invalid.0.32
ok 230 event_missing.0.32
ok 231 event_spurious.0.32
ok 232 get_value.0.31
# 0.31 PCMD3180 i2c2 Dev1 Ch8 Digi Volume
ok 233 name.0.31
ok 234 write_default.0.31
ok 235 write_valid.0.31
ok 236 write_invalid.0.31
ok 237 event_missing.0.31
ok 238 event_spurious.0.31
ok 239 get_value.0.30
# 0.30 PCMD3180 i2c2 Dev1 Ch7 Digi Volume
ok 240 name.0.30
ok 241 write_default.0.30
ok 242 write_valid.0.30
ok 243 write_invalid.0.30
ok 244 event_missing.0.30
ok 245 event_spurious.0.30
ok 246 get_value.0.29
# 0.29 PCMD3180 i2c2 Dev1 Ch6 Digi Volume
ok 247 name.0.29
ok 248 write_default.0.29
ok 249 write_valid.0.29
ok 250 write_invalid.0.29
ok 251 event_missing.0.29
ok 252 event_spurious.0.29
ok 253 get_value.0.28
# 0.28 PCMD3180 i2c2 Dev1 Ch5 Digi Volume
ok 254 name.0.28
ok 255 write_default.0.28
ok 256 write_valid.0.28
ok 257 write_invalid.0.28
ok 258 event_missing.0.28
ok 259 event_spurious.0.28
ok 260 get_value.0.27
# 0.27 PCMD3180 i2c2 Dev1 Ch4 Digi Volume
ok 261 name.0.27
ok 262 write_default.0.27
ok 263 write_valid.0.27
ok 264 write_invalid.0.27
ok 265 event_missing.0.27
ok 266 event_spurious.0.27
ok 267 get_value.0.26
# 0.26 PCMD3180 i2c2 Dev1 Ch3 Digi Volume
ok 268 name.0.26
ok 269 write_default.0.26
ok 270 write_valid.0.26
ok 271 write_invalid.0.26
ok 272 event_missing.0.26
ok 273 event_spurious.0.26
ok 274 get_value.0.25
# 0.25 PCMD3180 i2c2 Dev1 Ch2 Digi Volume
ok 275 name.0.25
ok 276 write_default.0.25
ok 277 write_valid.0.25
ok 278 write_invalid.0.25
ok 279 event_missing.0.25
ok 280 event_spurious.0.25
ok 281 get_value.0.24
# 0.24 PCMD3180 i2c2 Dev1 Ch1 Digi Volume
ok 282 name.0.24
ok 283 write_default.0.24
ok 284 write_valid.0.24
ok 285 write_invalid.0.24
ok 286 event_missing.0.24
ok 287 event_spurious.0.24
ok 288 get_value.0.23
# 0.23 PCMD3180 i2c2 Dev1 Ch8 Fine Volume
ok 289 name.0.23
ok 290 write_default.0.23
ok 291 write_valid.0.23
ok 292 write_invalid.0.23
ok 293 event_missing.0.23
ok 294 event_spurious.0.23
ok 295 get_value.0.22
# 0.22 PCMD3180 i2c2 Dev1 Ch7 Fine Volume
ok 296 name.0.22
ok 297 write_default.0.22
ok 298 write_valid.0.22
ok 299 write_invalid.0.22
ok 300 event_missing.0.22
ok 301 event_spurious.0.22
ok 302 get_value.0.21
# 0.21 PCMD3180 i2c2 Dev1 Ch6 Fine Volume
ok 303 name.0.21
ok 304 write_default.0.21
ok 305 write_valid.0.21
ok 306 write_invalid.0.21
ok 307 event_missing.0.21
ok 308 event_spurious.0.21
ok 309 get_value.0.20
# 0.20 PCMD3180 i2c2 Dev1 Ch5 Fine Volume
ok 310 name.0.20
ok 311 write_default.0.20
ok 312 write_valid.0.20
ok 313 write_invalid.0.20
ok 314 event_missing.0.20
ok 315 event_spurious.0.20
ok 316 get_value.0.19
# 0.19 PCMD3180 i2c2 Dev1 Ch4 Fine Volume
ok 317 name.0.19
ok 318 write_default.0.19
ok 319 write_valid.0.19
ok 320 write_invalid.0.19
ok 321 event_missing.0.19
ok 322 event_spurious.0.19
ok 323 get_value.0.18
# 0.18 PCMD3180 i2c2 Dev1 Ch3 Fine Volume
ok 324 name.0.18
ok 325 write_default.0.18
ok 326 write_valid.0.18
ok 327 write_invalid.0.18
ok 328 event_missing.0.18
ok 329 event_spurious.0.18
ok 330 get_value.0.17
# 0.17 PCMD3180 i2c2 Dev1 Ch2 Fine Volume
ok 331 name.0.17
ok 332 write_default.0.17
ok 333 write_valid.0.17
ok 334 write_invalid.0.17
ok 335 event_missing.0.17
ok 336 event_spurious.0.17
ok 337 get_value.0.16
# 0.16 PCMD3180 i2c2 Dev1 Ch1 Fine Volume
ok 338 name.0.16
ok 339 write_default.0.16
ok 340 write_valid.0.16
ok 341 write_invalid.0.16
ok 342 event_missing.0.16
ok 343 event_spurious.0.16
ok 344 get_value.0.15
# 0.15 PCMD3180 i2c2 Dev0 Ch8 Digi Volume
ok 345 name.0.15
ok 346 write_default.0.15
ok 347 write_valid.0.15
ok 348 write_invalid.0.15
ok 349 event_missing.0.15
ok 350 event_spurious.0.15
ok 351 get_value.0.14
# 0.14 PCMD3180 i2c2 Dev0 Ch7 Digi Volume
ok 352 name.0.14
ok 353 write_default.0.14
ok 354 write_valid.0.14
ok 355 write_invalid.0.14
ok 356 event_missing.0.14
ok 357 event_spurious.0.14
ok 358 get_value.0.13
# 0.13 PCMD3180 i2c2 Dev0 Ch6 Digi Volume
ok 359 name.0.13
ok 360 write_default.0.13
ok 361 write_valid.0.13
ok 362 write_invalid.0.13
ok 363 event_missing.0.13
ok 364 event_spurious.0.13
ok 365 get_value.0.12
# 0.12 PCMD3180 i2c2 Dev0 Ch5 Digi Volume
ok 366 name.0.12
ok 367 write_default.0.12
ok 368 write_valid.0.12
ok 369 write_invalid.0.12
ok 370 event_missing.0.12
ok 371 event_spurious.0.12
ok 372 get_value.0.11
# 0.11 PCMD3180 i2c2 Dev0 Ch4 Digi Volume
ok 373 name.0.11
ok 374 write_default.0.11
ok 375 write_valid.0.11
ok 376 write_invalid.0.11
ok 377 event_missing.0.11
ok 378 event_spurious.0.11
ok 379 get_value.0.10
# 0.10 PCMD3180 i2c2 Dev0 Ch3 Digi Volume
ok 380 name.0.10
ok 381 write_default.0.10
ok 382 write_valid.0.10
ok 383 write_invalid.0.10
ok 384 event_missing.0.10
ok 385 event_spurious.0.10
ok 386 get_value.0.9
# 0.9 PCMD3180 i2c2 Dev0 Ch2 Digi Volume
ok 387 name.0.9
ok 388 write_default.0.9
ok 389 write_valid.0.9
ok 390 write_invalid.0.9
ok 391 event_missing.0.9
ok 392 event_spurious.0.9
ok 393 get_value.0.8
# 0.8 PCMD3180 i2c2 Dev0 Ch1 Digi Volume
ok 394 name.0.8
ok 395 write_default.0.8
ok 396 write_valid.0.8
ok 397 write_invalid.0.8
ok 398 event_missing.0.8
ok 399 event_spurious.0.8
ok 400 get_value.0.7
# 0.7 PCMD3180 i2c2 Dev0 Ch8 Fine Volume
ok 401 name.0.7
ok 402 write_default.0.7
ok 403 write_valid.0.7
ok 404 write_invalid.0.7
ok 405 event_missing.0.7
ok 406 event_spurious.0.7
ok 407 get_value.0.6
# 0.6 PCMD3180 i2c2 Dev0 Ch7 Fine Volume
ok 408 name.0.6
ok 409 write_default.0.6
ok 410 write_valid.0.6
ok 411 write_invalid.0.6
ok 412 event_missing.0.6
ok 413 event_spurious.0.6
ok 414 get_value.0.5
# 0.5 PCMD3180 i2c2 Dev0 Ch6 Fine Volume
ok 415 name.0.5
ok 416 write_default.0.5
ok 417 write_valid.0.5
ok 418 write_invalid.0.5
ok 419 event_missing.0.5
ok 420 event_spurious.0.5
ok 421 get_value.0.4
# 0.4 PCMD3180 i2c2 Dev0 Ch5 Fine Volume
ok 422 name.0.4
ok 423 write_default.0.4
ok 424 write_valid.0.4
ok 425 write_invalid.0.4
ok 426 event_missing.0.4
ok 427 event_spurious.0.4
ok 428 get_value.0.3
# 0.3 PCMD3180 i2c2 Dev0 Ch4 Fine Volume
ok 429 name.0.3
ok 430 write_default.0.3
ok 431 write_valid.0.3
ok 432 write_invalid.0.3
ok 433 event_missing.0.3
ok 434 event_spurious.0.3
ok 435 get_value.0.2
# 0.2 PCMD3180 i2c2 Dev0 Ch3 Fine Volume
ok 436 name.0.2
ok 437 write_default.0.2
ok 438 write_valid.0.2
ok 439 write_invalid.0.2
ok 440 event_missing.0.2
ok 441 event_spurious.0.2
ok 442 get_value.0.1
# 0.1 PCMD3180 i2c2 Dev0 Ch2 Fine Volume
ok 443 name.0.1
ok 444 write_default.0.1
ok 445 write_valid.0.1
ok 446 write_invalid.0.1
ok 447 event_missing.0.1
ok 448 event_spurious.0.1
ok 449 get_value.0.0
# 0.0 PCMD3180 i2c2 Dev0 Ch1 Fine Volume
ok 450 name.0.0
ok 451 write_default.0.0
ok 452 write_valid.0.0
ok 453 write_invalid.0.0
ok 454 event_missing.0.0
ok 455 event_spurious.0.0
# Totals: pass:455 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 | 2217 +++++++++++++++++
sound/soc/codecs/pcm6240.h | 252 ++
5 files changed, 2658 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.35.7
^ permalink raw reply
* RE: [EXT] Re: [PATCH v1 1/1] arm64: dts: imx93-11x11-evk: add rtc PCF2131 support
From: Joy Zou @ 2024-04-07 9:24 UTC (permalink / raw)
To: Krzysztof Kozlowski, Jacky Bai, robh+dt@kernel.org,
krzysztof.kozlowski+dt@linaro.org, conor+dt@kernel.org,
shawnguo@kernel.org, s.hauer@pengutronix.de
Cc: kernel@pengutronix.de, festevam@gmail.com, dl-linux-imx,
devicetree@vger.kernel.org, imx@lists.linux.dev,
linux-arm-kernel@lists.infradead.org,
linux-kernel@vger.kernel.org
In-Reply-To: <d18b05d9-266b-4a1b-a2cd-3b6f8173a39b@linaro.org>
BR
Joy Zou
> -----Original Message-----
> From: Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org>
> Sent: 2024年4月7日 17:12
> To: Joy Zou <joy.zou@nxp.com>; Jacky Bai <ping.bai@nxp.com>;
> robh+dt@kernel.org; krzysztof.kozlowski+dt@linaro.org;
> conor+dt@kernel.org; shawnguo@kernel.org; s.hauer@pengutronix.de
> Cc: kernel@pengutronix.de; festevam@gmail.com; dl-linux-imx
> <linux-imx@nxp.com>; devicetree@vger.kernel.org; imx@lists.linux.dev;
> linux-arm-kernel@lists.infradead.org; linux-kernel@vger.kernel.org
> Subject: Re: [EXT] Re: [PATCH v1 1/1] arm64: dts: imx93-11x11-evk: add rtc
> PCF2131 support
>
> Caution: This is an external email. Please take care when clicking links or
> opening attachments. When in doubt, report the message using the 'Report
> this email' button
>
>
> On 07/04/2024 11:09, Joy Zou wrote:
> >
> >> -----Original Message-----
> >> From: Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org>
> >> Sent: 2024年4月7日 17:04
> >> To: Joy Zou <joy.zou@nxp.com>; Jacky Bai <ping.bai@nxp.com>;
> >> robh+dt@kernel.org; krzysztof.kozlowski+dt@linaro.org;
> >> conor+dt@kernel.org; shawnguo@kernel.org; s.hauer@pengutronix.de
> >> Cc: kernel@pengutronix.de; festevam@gmail.com; dl-linux-imx
> >> <linux-imx@nxp.com>; devicetree@vger.kernel.org; imx@lists.linux.dev;
> >> linux-arm-kernel@lists.infradead.org; linux-kernel@vger.kernel.org
> >> Subject: [EXT] Re: [PATCH v1 1/1] arm64: dts: imx93-11x11-evk: add
> >> rtc
> >> PCF2131 support
> >>> +&lpi2c3 {
> >>> + #address-cells = <1>;
> >>> + #size-cells = <0>;
> >>> + clock-frequency = <400000>;
> >>> + pinctrl-names = "default", "sleep";
> >>> + pinctrl-0 = <&pinctrl_lpi2c3>;
> >>> + pinctrl-1 = <&pinctrl_lpi2c3>;
> >>> + status = "okay";
> >>> +
> >>> + pcf2131: rtc@53 {
> >>> + compatible = "nxp,pcf2131";
> >>> + reg = <0x53>;
> >>> + interrupt-parent = <&pcal6524>;
> >>> + interrupts = <1 IRQ_TYPE_EDGE_FALLING>;
> >>> + status = "okay";
> >>
> >> Really, just drop...
> > Ok, will drop the status in next version.
> > Thanks for your comment!
>
> Please read DTS coding style.
Thanks you very much!
Yeah, I have read the DTS coding style. The “status” property is by default “okay”, thus it can be omitted.
BR
Joy Zou
>
> Best regards,
> Krzysztof
^ permalink raw reply
* [PATCH v9 1/4] ASoc: PCM6240: Create PCM6240 Family driver code
From: Shenghao Ding @ 2024-04-07 9:18 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: <20240407091846.1299-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>
---
v9:
- fixed wrong return value in order to report errors to users in
pcmdev_put_volsw
- fixed indentation in pcmdevice_process_block, each case was
encapsulated into a function
- Gain kcontrols end with Volume
- rename the Gain kcontrol
- Add upper_dev_name in pcmdevice_priv for kcontrol complying with alsa
naming
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 | 2217 ++++++++++++++++++++++++++++++++++++
1 file changed, 2217 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..93d592dbee66
--- /dev/null
+++ b/sound/soc/codecs/pcm6240.c
@@ -0,0 +1,2217 @@
+// 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 Volume",
+ "%s i2c%d Dev%d Ch%d Digi Volume",
+ "%s i2c%d Dev%d Ch%d Fine Volume",
+};
+
+static const char *const pcmdev_ctrl_name_with_prefix[] = {
+ "%s Dev%d Ch%d Ana Volume",
+ "%s Dev%d Ch%d Digi Volume",
+ "%s Dev%d Ch%d Fine Volume",
+};
+
+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 pcmd3140_fine_gain_ctl[] = {
+ {
+ .shift = 4,
+ .reg = PCMD3140_REG_CH1_FINE_GAIN,
+ .max = 0xf,
+ .invert = 0,
+ },
+ {
+ .shift = 4,
+ .reg = PCMD3140_REG_CH2_FINE_GAIN,
+ .max = 0xf,
+ .invert = 0,
+ },
+ {
+ .shift = 4,
+ .reg = PCMD3140_REG_CH3_FINE_GAIN,
+ .max = 0xf,
+ .invert = 0,
+ },
+ {
+ .shift = 4,
+ .reg = PCMD3140_REG_CH4_FINE_GAIN,
+ .max = 0xf,
+ .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 pcmd3180_fine_gain_ctl[] = {
+ {
+ .shift = 4,
+ .reg = PCMD3180_REG_CH1_FINE_GAIN,
+ .max = 0xf,
+ .invert = 0,
+ },
+ {
+ .shift = 4,
+ .reg = PCMD3180_REG_CH2_FINE_GAIN,
+ .max = 0xf,
+ .invert = 0,
+ },
+ {
+ .shift = 4,
+ .reg = PCMD3180_REG_CH3_FINE_GAIN,
+ .max = 0xf,
+ .invert = 0,
+ },
+ {
+ .shift = 4,
+ .reg = PCMD3180_REG_CH4_FINE_GAIN,
+ .max = 0xf,
+ .invert = 0,
+ },
+ {
+ .shift = 4,
+ .reg = PCMD3180_REG_CH5_FINE_GAIN,
+ .max = 0xf,
+ .invert = 0,
+ },
+ {
+ .shift = 4,
+ .reg = PCMD3180_REG_CH6_FINE_GAIN,
+ .max = 0xf,
+ .invert = 0,
+ },
+ {
+ .shift = 4,
+ .reg = PCMD3180_REG_CH7_FINE_GAIN,
+ .max = 0xf,
+ .invert = 0,
+ },
+ {
+ .shift = 4,
+ .reg = PCMD3180_REG_CH8_FINE_GAIN,
+ .max = 0xf,
+ .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, rc;
+ 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;
+ }
+
+ rc = pcmdev_dev_update_bits(pcm_dev, dev_no, reg, val_mask, val);
+ if (rc < 0)
+ dev_err(pcm_dev->dev, "%s: update_bits err = %d\n",
+ __func__, rc);
+ else
+ rc = 1;
+ mutex_unlock(&pcm_dev->codec_lock);
+ return rc;
+}
+
+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
+ {
+ {
+ .gain = taa5412_fine_gain_tlv,
+ .pcmdev_ctrl = pcmd3140_fine_gain_ctl,
+ .ctrl_array_size = ARRAY_SIZE(pcmd3140_fine_gain_ctl),
+ .get = pcmdevice_get_volsw,
+ .put = pcmdevice_put_volsw,
+ .pcmdev_ctrl_name_id = 2,
+ },
+ {
+ .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
+ {
+ {
+ .gain = taa5412_fine_gain_tlv,
+ .pcmdev_ctrl = pcmd3180_fine_gain_ctl,
+ .ctrl_array_size = ARRAY_SIZE(pcmd3180_fine_gain_ctl),
+ .get = pcmdevice_get_volsw,
+ .put = pcmdevice_put_volsw,
+ .pcmdev_ctrl_name_id = 2,
+ },
+ {
+ .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->upper_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->upper_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 pcmdev_single_byte_wr(struct pcmdevice_priv *pcm_dev,
+ unsigned char *data, int devn, int sublocksize)
+{
+ unsigned short len = get_unaligned_be16(&data[2]);
+ int offset = 2;
+ int i, ret;
+
+ offset += 2;
+ if (offset + 4 * len > sublocksize) {
+ dev_err(pcm_dev->dev, "%s: dev-%d byt wr out of boundary\n",
+ __func__, devn);
+ return -EINVAL;
+ }
+
+ for (i = 0; i < len; i++) {
+ ret = pcmdev_dev_write(pcm_dev, devn,
+ PCMDEVICE_REG(data[offset + 1], data[offset + 2]),
+ data[offset + 3]);
+ /* skip this error for next operation or next devices */
+ if (ret < 0)
+ dev_err(pcm_dev->dev, "%s: dev-%d single write err\n",
+ __func__, devn);
+
+ offset += 4;
+ }
+
+ return offset;
+}
+
+static int pcmdev_burst_wr(struct pcmdevice_priv *pcm_dev,
+ unsigned char *data, int devn, int sublocksize)
+{
+ unsigned short len = get_unaligned_be16(&data[2]);
+ int offset = 2;
+ int ret;
+
+ offset += 2;
+ if (offset + 4 + len > sublocksize) {
+ dev_err(pcm_dev->dev, "%s: dev-%d burst Out of boundary\n",
+ __func__, devn);
+ return -EINVAL;
+ }
+ if (len % 4) {
+ dev_err(pcm_dev->dev, "%s: dev-%d bst-len(%u) not div by 4\n",
+ __func__, devn, len);
+ return -EINVAL;
+ }
+ ret = pcmdev_dev_bulk_write(pcm_dev, devn,
+ PCMDEVICE_REG(data[offset + 1], data[offset + 2]),
+ &(data[offset + 4]), len);
+ /* skip this error for next devices */
+ if (ret < 0)
+ dev_err(pcm_dev->dev, "%s: dev-%d bulk_write err = %d\n",
+ __func__, devn, ret);
+
+ offset += (len + 4);
+
+ return offset;
+}
+
+static int pcmdev_delay(struct pcmdevice_priv *pcm_dev,
+ unsigned char *data, int devn, int sublocksize)
+{
+ unsigned int delay_time = 0;
+ int offset = 2;
+
+ if (offset + 2 > sublocksize) {
+ dev_err(pcm_dev->dev, "%s: dev-%d deley out of boundary\n",
+ __func__, devn);
+ return -EINVAL;
+ }
+ delay_time = get_unaligned_be16(&data[2]) * 1000;
+ usleep_range(delay_time, delay_time + 50);
+ offset += 2;
+
+ return offset;
+}
+
+static int pcmdev_bits_wr(struct pcmdevice_priv *pcm_dev,
+ unsigned char *data, int devn, int sublocksize)
+{
+ int offset = 2;
+ int ret;
+
+ if (offset + 6 > sublocksize) {
+ dev_err(pcm_dev->dev, "%s: dev-%d bit write out of memory\n",
+ __func__, devn);
+ return -EINVAL;
+ }
+ ret = pcmdev_dev_update_bits(pcm_dev, devn,
+ PCMDEVICE_REG(data[offset + 3], data[offset + 4]),
+ data[offset + 1], data[offset + 5]);
+ /* skip this error for next devices */
+ if (ret < 0)
+ dev_err(pcm_dev->dev, "%s: dev-%d update_bits err = %d\n",
+ __func__, devn, ret);
+
+ offset += 6;
+
+ return offset;
+}
+
+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 devn, dev_end, ret = 0;
+ unsigned char subblk_typ = data[1];
+
+ if (dev_idx) {
+ devn = dev_idx - 1;
+ dev_end = dev_idx;
+ } else {
+ devn = 0;
+ dev_end = pcm_dev->ndev;
+ }
+
+ /* loop in case of several devices sharing the same sub-block */
+ for (; devn < dev_end; devn++) {
+ switch (subblk_typ) {
+ case PCMDEVICE_CMD_SING_W:
+ ret = pcmdev_single_byte_wr(pcm_dev, data, devn, sublocksize);
+ break;
+ case PCMDEVICE_CMD_BURST:
+ ret = pcmdev_burst_wr(pcm_dev, data, devn, sublocksize);
+ break;
+ case PCMDEVICE_CMD_DELAY:
+ ret = pcmdev_delay(pcm_dev, data, devn, sublocksize);
+ break;
+ case PCMDEVICE_CMD_FIELD_W:
+ ret = pcmdev_bits_wr(pcm_dev, data, devn, sublocksize);
+ break;
+ default:
+ break;
+ }
+ /*
+ * In case of sub-block error, break the loop for the rest of
+ * devices.
+ */
+ if (ret < 0)
+ break;
+ }
+
+ return ret;
+}
+
+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 char *str_to_upper(char *str)
+{
+ char *orig = str;
+
+ if (!str)
+ return NULL;
+
+ while (*str) {
+ *str = toupper(*str);
+ str++;
+ }
+
+ return orig;
+}
+
+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));
+
+ strscpy(pcm_dev->upper_dev_name,
+ pcmdevice_i2c_id[pcm_dev->chip_id].name,
+ sizeof(pcm_dev->upper_dev_name));
+
+ str_to_upper(pcm_dev->upper_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.35.7
^ permalink raw reply related
* [PATCH v9 3/4] ASoc: PCM6240: Add compile item for PCM6240 Family driver
From: Shenghao Ding @ 2024-04-07 9:18 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: <20240407091846.1299-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>
---
v9:
- No changes.
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.35.7
^ permalink raw reply related
* [PATCH v9 2/4] ASoc: PCM6240: Create header file for PCM6240 Family driver code
From: Shenghao Ding @ 2024-04-07 9:18 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: <20240407091846.1299-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>
---
v9:
- Add upper_dev_name in pcmdevice_priv for kcontrol complying with alsa
naming
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 | 252 +++++++++++++++++++++++++++++++++++++
1 file changed, 252 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..7c8f1b53d51f
--- /dev/null
+++ b/sound/soc/codecs/pcm6240.h
@@ -0,0 +1,252 @@
+/* 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 PCMD3140_REG_CH1_FINE_GAIN PCMDEVICE_REG(0X0, 0x3F)
+#define PCMD3140_REG_CH2_FINE_GAIN PCMDEVICE_REG(0X0, 0x44)
+#define PCMD3140_REG_CH3_FINE_GAIN PCMDEVICE_REG(0X0, 0x49)
+#define PCMD3140_REG_CH4_FINE_GAIN PCMDEVICE_REG(0X0, 0x4E)
+
+#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 PCMD3180_REG_CH1_FINE_GAIN PCMDEVICE_REG(0X0, 0x3F)
+#define PCMD3180_REG_CH2_FINE_GAIN PCMDEVICE_REG(0X0, 0x44)
+#define PCMD3180_REG_CH3_FINE_GAIN PCMDEVICE_REG(0X0, 0x49)
+#define PCMD3180_REG_CH4_FINE_GAIN PCMDEVICE_REG(0X0, 0x4E)
+#define PCMD3180_REG_CH5_FINE_GAIN PCMDEVICE_REG(0X0, 0x53)
+#define PCMD3180_REG_CH6_FINE_GAIN PCMDEVICE_REG(0X0, 0x58)
+#define PCMD3180_REG_CH7_FINE_GAIN PCMDEVICE_REG(0X0, 0x5D)
+#define PCMD3180_REG_CH8_FINE_GAIN PCMDEVICE_REG(0X0, 0x62)
+
+#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];
+ /* used for kcontrol name */
+ unsigned char upper_dev_name[I2C_NAME_SIZE];
+ 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.35.7
^ permalink raw reply related
* [PATCH v9 4/4] ASoc: dt-bindings: PCM6240: Add initial DT binding
From: Shenghao Ding @ 2024-04-07 9:18 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: <20240407091846.1299-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>
---
v9:
- No changes.
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.35.7
^ permalink raw reply related
* [PATCH 0/3] Fix up qcom,halt-regs definition in various schemas
From: Luca Weiss @ 2024-04-07 9:58 UTC (permalink / raw)
To: ~postmarketos/upstreaming, phone-devel, Bjorn Andersson,
Mathieu Poirier, Rob Herring, Krzysztof Kozlowski, Conor Dooley
Cc: linux-arm-msm, linux-remoteproc, devicetree, linux-kernel,
Luca Weiss
The original motivation is that a bunch of other schemas fail to
validate qcom,halt-regs, for example like in the following examples:
arch/arm64/boot/dts/qcom/apq8016-sbc.dtb: remoteproc@4080000: qcom,halt-regs:0: [20] is too short
from schema $id: http://devicetree.org/schemas/remoteproc/qcom,msm8916-mss-pil.yaml#
arch/arm64/boot/dts/qcom/apq8096-ifc6640.dtb: remoteproc@2080000: qcom,halt-regs:0: [82] is too short
from schema $id: http://devicetree.org/schemas/remoteproc/qcom,msm8996-mss-pil.yaml#
arch/arm64/boot/dts/qcom/apq8039-t2.dtb: remoteproc@4080000: qcom,halt-regs:0: [32] is too short
from schema $id: http://devicetree.org/schemas/remoteproc/qcom,msm8916-mss-pil.yaml#
While I'm actually not quite sure why these patches fix this in
the other schemas - feels like a bug/limitation in dt-schema maybe? -
the patches should be correct anyways to validate qcom,halt-regs in the
schemas I'm touching.
Signed-off-by: Luca Weiss <luca@z3ntu.xyz>
---
Luca Weiss (3):
dt-bindings: remoteproc: qcom,qcs404-cdsp-pil: Fix qcom,halt-regs definition
dt-bindings: remoteproc: qcom,sc7280-wpss-pil: Fix qcom,halt-regs definition
dt-bindings: remoteproc: qcom,sdm845-adsp-pil: Fix qcom,halt-regs definition
.../devicetree/bindings/remoteproc/qcom,qcs404-cdsp-pil.yaml | 6 +++++-
.../devicetree/bindings/remoteproc/qcom,sc7280-wpss-pil.yaml | 6 +++++-
.../devicetree/bindings/remoteproc/qcom,sdm845-adsp-pil.yaml | 6 +++++-
3 files changed, 15 insertions(+), 3 deletions(-)
---
base-commit: 8568bb2ccc278f344e6ac44af6ed010a90aa88dc
change-id: 20240407-qcom-halt-regs-fixup-2c6cce9734e4
Best regards,
--
Luca Weiss <luca@z3ntu.xyz>
^ permalink raw reply
* [PATCH 1/3] dt-bindings: remoteproc: qcom,qcs404-cdsp-pil: Fix qcom,halt-regs definition
From: Luca Weiss @ 2024-04-07 9:58 UTC (permalink / raw)
To: ~postmarketos/upstreaming, phone-devel, Bjorn Andersson,
Mathieu Poirier, Rob Herring, Krzysztof Kozlowski, Conor Dooley
Cc: linux-arm-msm, linux-remoteproc, devicetree, linux-kernel,
Luca Weiss
In-Reply-To: <20240407-qcom-halt-regs-fixup-v1-0-a0ea4e2c178e@z3ntu.xyz>
Set the 'items' correctly for the qcom,halt-regs property and update the
description to match what it should be.
Signed-off-by: Luca Weiss <luca@z3ntu.xyz>
---
.../devicetree/bindings/remoteproc/qcom,qcs404-cdsp-pil.yaml | 6 +++++-
1 file changed, 5 insertions(+), 1 deletion(-)
diff --git a/Documentation/devicetree/bindings/remoteproc/qcom,qcs404-cdsp-pil.yaml b/Documentation/devicetree/bindings/remoteproc/qcom,qcs404-cdsp-pil.yaml
index 06f5f93f62a9..bca59394aef4 100644
--- a/Documentation/devicetree/bindings/remoteproc/qcom,qcs404-cdsp-pil.yaml
+++ b/Documentation/devicetree/bindings/remoteproc/qcom,qcs404-cdsp-pil.yaml
@@ -81,7 +81,11 @@ properties:
$ref: /schemas/types.yaml#/definitions/phandle-array
description:
Phandle reference to a syscon representing TCSR followed by the
- three offsets within syscon for q6, modem and nc halt registers.
+ offset within syscon for q6 halt register.
+ items:
+ - items:
+ - description: phandle to TCSR syscon region
+ - description: offset to the Q6 halt register
qcom,smem-states:
$ref: /schemas/types.yaml#/definitions/phandle-array
--
2.44.0
^ permalink raw reply related
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