* Re: [PATCH 2/3] ASoC: simple-card: make sysclk index configurable
From: Mark Brown @ 2018-05-29 11:24 UTC (permalink / raw)
To: Daniel Mack; +Cc: devicetree, alsa-devel, lgirdwood, kuninori.morimoto.gx
In-Reply-To: <20180528193503.18905-3-daniel@zonque.org>
[-- Attachment #1.1: Type: text/plain, Size: 817 bytes --]
On Mon, May 28, 2018 at 09:35:02PM +0200, Daniel Mack wrote:
> The simple-card driver currently hard-codes the clk_id parameter in
> snd_soc_dai_set_sysclk() to 0. Make this configrable for both CPU and
> codec dai sub-nodes.
> This still has the limitation that only one clk_id can be configured, but it
> should help some more platforms to use simple-card in favor to a more
> specific machine driver.
If we want to get more complex usage of clocks in the DT we should be
moving the CODECs over to using the standard clock bindings for this
stuff rather than inventing custom ASoC clock bindings for it. That way
we don't have to deal with the pain of trying to join things up in the
future.
As a practical matter we also don't have any CODECs specifying any
bindings for ASoC level clock IDs right now either.
[-- Attachment #1.2: signature.asc --]
[-- Type: application/pgp-signature, Size: 488 bytes --]
[-- Attachment #2: Type: text/plain, Size: 0 bytes --]
^ permalink raw reply
* Re: [PATCH 1/3] ASoC: simple-card: set cpu dai clk in hw_params
From: Daniel Mack @ 2018-05-29 11:17 UTC (permalink / raw)
To: Mark Brown; +Cc: devicetree, alsa-devel, lgirdwood, kuninori.morimoto.gx
In-Reply-To: <20180529111632.GB23509@sirena.org.uk>
On Tuesday, May 29, 2018 01:16 PM, Mark Brown wrote:
> On Mon, May 28, 2018 at 09:35:01PM +0200, Daniel Mack wrote:
>
>> if (mclk_fs) {
>> mclk = params_rate(params) * mclk_fs;
>> +
>> + if (dai_props->cpu_dai.clk)
>> + clk_set_rate(dai_props->cpu_dai.clk, mclk);
>> +
>
> We're ignoring the return value here.
>
On purpose actually. Not all clocks might be settable, and in that case,
this is a no-op. You think we should bail or warn?
^ permalink raw reply
* Re: [PATCH 1/3] ASoC: simple-card: set cpu dai clk in hw_params
From: Mark Brown @ 2018-05-29 11:16 UTC (permalink / raw)
To: Daniel Mack; +Cc: devicetree, alsa-devel, lgirdwood, kuninori.morimoto.gx
In-Reply-To: <20180528193503.18905-2-daniel@zonque.org>
[-- Attachment #1.1: Type: text/plain, Size: 254 bytes --]
On Mon, May 28, 2018 at 09:35:01PM +0200, Daniel Mack wrote:
> if (mclk_fs) {
> mclk = params_rate(params) * mclk_fs;
> +
> + if (dai_props->cpu_dai.clk)
> + clk_set_rate(dai_props->cpu_dai.clk, mclk);
> +
We're ignoring the return value here.
[-- Attachment #1.2: signature.asc --]
[-- Type: application/pgp-signature, Size: 488 bytes --]
[-- Attachment #2: Type: text/plain, Size: 0 bytes --]
^ permalink raw reply
* Re: [PATCH v14 0/2] Kryo CPU scaling driver
From: Amit Kucheria @ 2018-05-29 11:11 UTC (permalink / raw)
To: Ilia Lin
Cc: vireshk, nm, sboyd, Rob Herring, Mark Rutland, Rafael J. Wysocki,
Linux PM list, devicetree, LKML
In-Reply-To: <1527250067-1256-1-git-send-email-ilialin@codeaurora.org>
On Fri, May 25, 2018 at 3:07 PM, Ilia Lin <ilialin@codeaurora.org> wrote:
> [v14]
> * Addressed comment from Sudeep about DT compatible
> * Added MAINTAINERS entry
>
> [v13]
> * Addressed comment from Sudeep about DT compatible check on init
>
> [v12]
> * Addressed comments from Sudeep and Viresh about the single init
>
> [v11]
> * Addressed comment from Russel about device_node reference
> * Addressed comment from Sudeep about the late_initcall
> * Transformed init into probe to take care of deferals
>
> [v10]
> * Split the series into domains
> * Addressed comments from Viresh and Sudeep about logical CPU numbering.
>
> The qcom-cpufreq-kryo driver is aimed to support different SOC versions.
> The driver reads eFuse information and chooses the required OPP subset
> by passing the OPP supported-hw parameter.
>
> The series depends on the series from Viresh:
> https://patchwork.kernel.org/patch/10418139/
>
> The previous spin was here:
> https://patchwork.kernel.org/patch/10424949/
>
> Ilia Lin (2):
> cpufreq: Add Kryo CPU scaling driver
> dt-bindings: cpufreq: Document operating-points-v2-kryo-cpu
>
> .../devicetree/bindings/opp/kryo-cpufreq.txt | 680 +++++++++++++++++++++
> MAINTAINERS | 7 +
> drivers/cpufreq/Kconfig.arm | 10 +
> drivers/cpufreq/Makefile | 1 +
> drivers/cpufreq/cpufreq-dt-platdev.c | 3 +
> drivers/cpufreq/qcom-cpufreq-kryo.c | 206 +++++++
> 6 files changed, 907 insertions(+)
> create mode 100644 Documentation/devicetree/bindings/opp/kryo-cpufreq.txt
> create mode 100644 drivers/cpufreq/qcom-cpufreq-kryo.c
>
FWIW,
Reviewed-by: Amit Kucheria <amit.kucheria@linaro.org>
Tested-by: Amit Kucheria <amit.kucheria@linaro.org>
^ permalink raw reply
* Re: [PATCH v2] arm64: dts: qcom: msm8996: Move UFS_GDSC to UFS HCD
From: Vivek Gautam @ 2018-05-29 11:01 UTC (permalink / raw)
To: Bjorn Andersson
Cc: Andy Gross, Manu Gautam, linux-arm-msm, linux-soc, devicetree,
linux-arm-kernel, open list
In-Reply-To: <20180525184525.355-1-bjorn.andersson@linaro.org>
On Sat, May 26, 2018 at 12:15 AM, Bjorn Andersson
<bjorn.andersson@linaro.org> wrote:
> The UFS_GDSC backs the resources needed by the UFS HCD, rather than the
> PHY. This results in the UFS HCD occationally failing to enable some of
> its clocks.
>
> Move the UFS_GDSC reference to the UFS HCD node instead, to correct
> this.
>
> Signed-off-by: Bjorn Andersson <bjorn.andersson@linaro.org>
> ---
>
> Changes since v1:
> - Dropped UFS_GDSC from phy node
>
> arch/arm64/boot/dts/qcom/msm8996.dtsi | 4 ++--
> 1 file changed, 2 insertions(+), 2 deletions(-)
>
> diff --git a/arch/arm64/boot/dts/qcom/msm8996.dtsi b/arch/arm64/boot/dts/qcom/msm8996.dtsi
> index 380e14591686..8c7f9ca25b53 100644
> --- a/arch/arm64/boot/dts/qcom/msm8996.dtsi
> +++ b/arch/arm64/boot/dts/qcom/msm8996.dtsi
> @@ -654,8 +654,6 @@
> clocks = <&rpmcc RPM_SMD_LN_BB_CLK>,
> <&gcc GCC_UFS_CLKREF_CLK>;
> status = "disabled";
> -
> - power-domains = <&gcc UFS_GDSC>;
> };
>
> ufshc@624000 {
> @@ -674,6 +672,8 @@
> vccq-max-microamp = <450000>;
> vccq2-max-microamp = <450000>;
>
> + power-domains = <&gcc UFS_GDSC>;
> +
Looks good.
Reviewed-by: Vivek Gautam <vivek.gautam@codeaurora.org>
Regards
Vivek
> clock-names =
> "core_clk_src",
> "core_clk",
> --
> 2.17.0
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-arm-msm" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at http://vger.kernel.org/majordomo-info.html
--
QUALCOMM INDIA, on behalf of Qualcomm Innovation Center, Inc. is a member
of Code Aurora Forum, hosted by The Linux Foundation
^ permalink raw reply
* RE: [v5 2/6] dmaengine: fsl-qdma: Add qDMA controller driver for Layerscape SoCs
From: Wen He @ 2018-05-29 10:38 UTC (permalink / raw)
To: Vinod
Cc: dmaengine@vger.kernel.org, robh+dt@kernel.org,
devicetree@vger.kernel.org, Leo Li, Jiafei Pan, Jiaheng Fan
In-Reply-To: <20180529101954.GJ5666@vkoul-mobl>
> -----Original Message-----
> From: Vinod [mailto:vkoul@kernel.org]
> Sent: 2018年5月29日 18:20
> To: Wen He <wen.he_1@nxp.com>
> Cc: dmaengine@vger.kernel.org; robh+dt@kernel.org;
> devicetree@vger.kernel.org; Leo Li <leoyang.li@nxp.com>; Jiafei Pan
> <jiafei.pan@nxp.com>; Jiaheng Fan <jiaheng.fan@nxp.com>
> Subject: Re: [v5 2/6] dmaengine: fsl-qdma: Add qDMA controller driver for
> Layerscape SoCs
>
> On 29-05-18, 09:59, Wen He wrote:
> > > On 25-05-18, 19:19, Wen He wrote:
> > >
> > > > +/**
> > > > + * struct fsl_qdma_format - This is the struct holding describing
> compound
> > > > + * descriptor format with qDMA.
> > > > + * @status: This field which describes command status and
> > > > + * enqueue status notification.
> > > > + * @cfg: This field which describes frame offset and
> frame
> > > > + * format.
> > > > + * @addr_lo: This field which indicating the start of the
> buffer
> > > > + * holding the compound descriptor of the lower 32-bits
> > > > + * address in memory 40-bit address.
> > > > + * @addr_hi: This field's the same as above field, but
> point
> > > high
> > > > + * 8-bits in memory 40-bit address.
> > > > + * @__reserved1: Reserved field.
> > > > + * @cfg8b_w1: This field which describes compound
> descriptor
> > > > + * command queue origin produced by qDMA and
> > > dynamic
> > >
> > > you may remove 'This field which describes'... in above lines, give
> > > reader no information :)
> > >
> >
> > Ok, so I remove 'this filed which describes' but keep the second half, right?
>
> right
>
> > > > + for (i = 0; i < queue_num; i++) {
> > > > + if (queue_size[i] > FSL_QDMA_CIRCULAR_DESC_SIZE_MAX
> > > > + || queue_size[i] <
> FSL_QDMA_CIRCULAR_DESC_SIZE_MIN) {
> > > > + dev_err(&pdev->dev, "Get wrong queue-sizes.\n");
> > > > + return NULL;
> > >
> > > the indents here are bad for reading..
> > >
> >
> > So I add a empty line in here?
>
> No, indent of trailing condition is same as code block, that causes confusion,
> they should have different indent
>
Got it.
> > > > + /*
> > > > + * Clear the command queue interrupt detect register for all
> queues.
> > > > + */
> > > > + qdma_writel(fsl_qdma, 0xffffffff, block + FSL_QDMA_BCQIDR(0));
> > >
> > > bunch of writes with 0xffffffff, can you explain why? Also helps to
> > > make a macro for this
> > >
> >
> > Maybe I missed that I should defined the value to the macro and add
> comment.
> > Right?
>
> that would help, but why are you writing 0xffffffff at all these places?
>
This value is from the datasheet.
Should I write comments to here?
> > > > +static void fsl_qdma_issue_pending(struct dma_chan *chan) {
> > > > + struct fsl_qdma_chan *fsl_chan = to_fsl_qdma_chan(chan);
> > > > + struct fsl_qdma_queue *fsl_queue = fsl_chan->queue;
> > > > + unsigned long flags;
> > > > +
> > > > + spin_lock_irqsave(&fsl_queue->queue_lock, flags);
> > > > + spin_lock(&fsl_chan->vchan.lock);
> > > > + if (vchan_issue_pending(&fsl_chan->vchan))
> > > > + fsl_qdma_enqueue_desc(fsl_chan);
> > > > + spin_unlock(&fsl_chan->vchan.lock);
> > > > + spin_unlock_irqrestore(&fsl_queue->queue_lock, flags);
> > >
> > > why do we need two locks, and since you are doing vchan why should
> > > you add your own lock on top
> > >
> >
> > Yes, we need two locks.
> > As you know, the QDMA support multiple virtualized blocks for multi-core
> support.
> > so we need to make sure that muliti-core access issues.
>
> but why cant you use vchan lock for all?
>
We can't only use vchan lock for all. otherwise enqueue action will be interrupted.
Best Regards,
Wen
> --
> ~Vinod
^ permalink raw reply
* Re: [PATCH v2 39/40] iommu/arm-smmu-v3: Add support for PRI
From: Jean-Philippe Brucker @ 2018-05-29 10:27 UTC (permalink / raw)
To: Bharat Kumar Gogada,
linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r@public.gmane.org,
linux-pci-u79uwXL29TY76Z2rM5mHXA@public.gmane.org,
linux-acpi-u79uwXL29TY76Z2rM5mHXA@public.gmane.org,
devicetree-u79uwXL29TY76Z2rM5mHXA@public.gmane.org,
iommu-cunTk1MwBs9QetFLy7KEm3xJsTq8ys+cHZ5vskTnxNA@public.gmane.org,
kvm-u79uwXL29TY76Z2rM5mHXA@public.gmane.org,
linux-mm-Bw31MaZKKs3YtjvyW6yDsg@public.gmane.org
Cc: xuzaibo-hv44wF8Li93QT0dZR+AlfA@public.gmane.org, Will Deacon,
okaya-sgV2jX0FEOL9JmXXK+q4OQ@public.gmane.org,
ashok.raj-ral2JQCrhuEAvxtiuMwx3w@public.gmane.org,
rfranz-YGCgFSpz5w/QT0dZR+AlfA@public.gmane.org,
Ravikiran Gummaluri,
ilias.apalodimas-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org,
dwmw2-wEGCiKHe2LqWVfeAwA7xHQ@public.gmane.org,
christian.koenig-5C7GfCeVMHo@public.gmane.org
In-Reply-To: <BLUPR0201MB150513BBAA161355DE9B3A48A5690-hRBPhS1iNj/g9tdZWAsUFxrHTHEw16jenBOFsp37pqbUKgpGm//BTAC/G2K4zDHf@public.gmane.org>
On 25/05/18 15:08, Bharat Kumar Gogada wrote:
>> + master->can_fault = true;
>> + master->ste.prg_resp_needs_ssid =
>> pci_prg_resp_requires_prefix(pdev);
>
> Any reason why this is not cleared in arm_smmu_disable_pri ?
Actually, setting it here is wrong. Since we now call enable_pri()
lazily, prg_resp_needs_ssid isn't initialized when writing the STE. That
bit is read by the SMMU when the PRIQ is full and it needs to
auto-respond. Fortunately the PRI doesn't need to be enabled in order to
read this bit, so we can move pci_prg_resp_requires_prefix() to
add_device() and clear the bit in remove_device(). Thanks for catching this.
Jean
^ permalink raw reply
* RE: [v5 1/6] dmaengine: fsldma: Replace DMA_IN/OUT by FSL_DMA_IN/OUT
From: Wen He @ 2018-05-29 10:22 UTC (permalink / raw)
To: Vinod
Cc: dmaengine@vger.kernel.org, robh+dt@kernel.org,
devicetree@vger.kernel.org, Leo Li, Jiafei Pan, Jiaheng Fan
In-Reply-To: <20180529102121.GK5666@vkoul-mobl>
> -----Original Message-----
> From: Vinod [mailto:vkoul@kernel.org]
> Sent: 2018年5月29日 18:21
> To: Wen He <wen.he_1@nxp.com>
> Cc: dmaengine@vger.kernel.org; robh+dt@kernel.org;
> devicetree@vger.kernel.org; Leo Li <leoyang.li@nxp.com>; Jiafei Pan
> <jiafei.pan@nxp.com>; Jiaheng Fan <jiaheng.fan@nxp.com>
> Subject: Re: [v5 1/6] dmaengine: fsldma: Replace DMA_IN/OUT by
> FSL_DMA_IN/OUT
>
> On 29-05-18, 10:14, Wen He wrote:
> > >
> > > Well that patch seems to do a bit more than replace DMA_IN/OUT by
> > > FSL_DMA_IN/OUT care to explain those. best would be to do a patch
> > > which does replace and then add new things in separate patch, easier
> > > to review
> > >
> >
> > What does means?
> > This also a patch.
>
> You cna do only replace DMA_IN/OUT by FSL_DMA_IN/OUT in this patch.
> Second patch can add additional macros you have added and explain what
> they do and why they are needed
>
Got it, it's good idea.
Wen
> --
> ~Vinod
^ permalink raw reply
* Re: [v5 1/6] dmaengine: fsldma: Replace DMA_IN/OUT by FSL_DMA_IN/OUT
From: Vinod @ 2018-05-29 10:21 UTC (permalink / raw)
To: Wen He
Cc: dmaengine@vger.kernel.org, robh+dt@kernel.org,
devicetree@vger.kernel.org, Leo Li, Jiafei Pan, Jiaheng Fan
In-Reply-To: <AM6PR0402MB3382F1DC777AD2AB106C57EEE26D0@AM6PR0402MB3382.eurprd04.prod.outlook.com>
On 29-05-18, 10:14, Wen He wrote:
> >
> > Well that patch seems to do a bit more than replace DMA_IN/OUT by
> > FSL_DMA_IN/OUT care to explain those. best would be to do a patch which
> > does replace and then add new things in separate patch, easier to review
> >
>
> What does means?
> This also a patch.
You cna do only replace DMA_IN/OUT by FSL_DMA_IN/OUT in this patch. Second patch
can add additional macros you have added and explain what they do and why they
are needed
--
~Vinod
^ permalink raw reply
* Re: [v5 2/6] dmaengine: fsl-qdma: Add qDMA controller driver for Layerscape SoCs
From: Vinod @ 2018-05-29 10:19 UTC (permalink / raw)
To: Wen He
Cc: dmaengine@vger.kernel.org, robh+dt@kernel.org,
devicetree@vger.kernel.org, Leo Li, Jiafei Pan, Jiaheng Fan
In-Reply-To: <AM6PR0402MB3382D42C76332B98D53D001AE26D0@AM6PR0402MB3382.eurprd04.prod.outlook.com>
On 29-05-18, 09:59, Wen He wrote:
> > On 25-05-18, 19:19, Wen He wrote:
> >
> > > +/**
> > > + * struct fsl_qdma_format - This is the struct holding describing compound
> > > + * descriptor format with qDMA.
> > > + * @status: This field which describes command status and
> > > + * enqueue status notification.
> > > + * @cfg: This field which describes frame offset and frame
> > > + * format.
> > > + * @addr_lo: This field which indicating the start of the buffer
> > > + * holding the compound descriptor of the lower 32-bits
> > > + * address in memory 40-bit address.
> > > + * @addr_hi: This field's the same as above field, but point
> > high
> > > + * 8-bits in memory 40-bit address.
> > > + * @__reserved1: Reserved field.
> > > + * @cfg8b_w1: This field which describes compound descriptor
> > > + * command queue origin produced by qDMA and
> > dynamic
> >
> > you may remove 'This field which describes'... in above lines, give reader no
> > information :)
> >
>
> Ok, so I remove 'this filed which describes' but keep the second half, right?
right
> > > + for (i = 0; i < queue_num; i++) {
> > > + if (queue_size[i] > FSL_QDMA_CIRCULAR_DESC_SIZE_MAX
> > > + || queue_size[i] < FSL_QDMA_CIRCULAR_DESC_SIZE_MIN) {
> > > + dev_err(&pdev->dev, "Get wrong queue-sizes.\n");
> > > + return NULL;
> >
> > the indents here are bad for reading..
> >
>
> So I add a empty line in here?
No, indent of trailing condition is same as code block, that causes confusion,
they should have different indent
> > > + /*
> > > + * Clear the command queue interrupt detect register for all queues.
> > > + */
> > > + qdma_writel(fsl_qdma, 0xffffffff, block + FSL_QDMA_BCQIDR(0));
> >
> > bunch of writes with 0xffffffff, can you explain why? Also helps to make a
> > macro for this
> >
>
> Maybe I missed that I should defined the value to the macro and add comment.
> Right?
that would help, but why are you writing 0xffffffff at all these places?
> > > +static void fsl_qdma_issue_pending(struct dma_chan *chan) {
> > > + struct fsl_qdma_chan *fsl_chan = to_fsl_qdma_chan(chan);
> > > + struct fsl_qdma_queue *fsl_queue = fsl_chan->queue;
> > > + unsigned long flags;
> > > +
> > > + spin_lock_irqsave(&fsl_queue->queue_lock, flags);
> > > + spin_lock(&fsl_chan->vchan.lock);
> > > + if (vchan_issue_pending(&fsl_chan->vchan))
> > > + fsl_qdma_enqueue_desc(fsl_chan);
> > > + spin_unlock(&fsl_chan->vchan.lock);
> > > + spin_unlock_irqrestore(&fsl_queue->queue_lock, flags);
> >
> > why do we need two locks, and since you are doing vchan why should you add
> > your own lock on top
> >
>
> Yes, we need two locks.
> As you know, the QDMA support multiple virtualized blocks for multi-core support.
> so we need to make sure that muliti-core access issues.
but why cant you use vchan lock for all?
--
~Vinod
^ permalink raw reply
* Re: [PATCH v2 5/6] soc: qcom: rpmh powerdomain driver
From: Rajendra Nayak @ 2018-05-29 10:19 UTC (permalink / raw)
To: David Collins, viresh.kumar, sboyd, andy.gross, ulf.hansson
Cc: devicetree, linux-arm-msm, linux-kernel, Lina Iyer
In-Reply-To: <215deee5-6472-d587-9a90-f7158162ed82@codeaurora.org>
Hi David,
On 05/26/2018 06:38 AM, David Collins wrote:
> Hello Rajendra,
>
> On 05/25/2018 03:01 AM, Rajendra Nayak wrote:
>> The RPMh powerdomain driver aggregates the corner votes from various
>
> s/powerdomain/power domain/
>
> This applies to all instances in this patch. "Power domain" seems to be
> the preferred spelling in the kernel.
thanks, will change in all applicable places.
>
>
>> consumers for the ARC resources and communicates it to RPMh.
>>
>> We also add data for all powerdomains on sdm845 as part of the patch.
>> The driver can be extended to support other SoCs which support RPMh
>>
>> Signed-off-by: Rajendra Nayak <rnayak@codeaurora.org>
>> ---
>> .../devicetree/bindings/power/qcom,rpmhpd.txt | 65 ++++
>> drivers/soc/qcom/Kconfig | 9 +
>> drivers/soc/qcom/Makefile | 1 +
>> drivers/soc/qcom/rpmhpd.c | 360 ++++++++++++++++++
>> 4 files changed, 435 insertions(+)
>> create mode 100644 Documentation/devicetree/bindings/power/qcom,rpmhpd.txt
>> create mode 100644 drivers/soc/qcom/rpmhpd.c
> ...
>> +++ b/Documentation/devicetree/bindings/power/qcom,rpmhpd.txt
>
> I think that this binding documentation should be in a patch separate from
> the driver.
yes, will split it when I repost
>
>
>> @@ -0,0 +1,65 @@
>> +Qualcomm RPMh Powerdomains
>
> s/Qualcomm/Qualcomm Technologies, Inc./
>
>
>> +
>> +* For RPMh powerdomains, we communicate a performance state to RPMh
>
> Does this line need to start with '*'?
No, will remove it
>
>
>> +which then translates it into a corresponding voltage on a rail
>> +
>> +Required Properties:
>> + - compatible: Should be one of the following
>> + * qcom,sdm845-rpmhpd: RPMh powerdomain for the sdm845 family of SoC
>> + - power-domain-cells: number of cells in power domain specifier
>> + must be 1
>> + - operating-points-v2: Phandle to the OPP table for the power-domain.
>> + Refer to Documentation/devicetree/bindings/power/power_domain.txt
>> + and Documentation/devicetree/bindings/opp/qcom-opp.txt for more details
>> +
>> +Example:
>> +
>> + rpmhpd: power-controller {
>> + compatible = "qcom,sdm845-rpmhpd";
>> + #power-domain-cells = <1>;
>> + operating-points-v2 = <&rpmhpd_opp_table>,
>> + <&rpmhpd_opp_table>,
>> + <&rpmhpd_opp_table>,
>> + <&rpmhpd_opp_table>,
>> + <&rpmhpd_opp_table>,
>> + <&rpmhpd_opp_table>,
>> + <&rpmhpd_opp_table>,
>> + <&rpmhpd_opp_table>,
>> + <&rpmhpd_opp_table>;
>
> Can this be changed to simply:
> operating-points-v2 = <&rpmhpd_opp_table>;
>
> The opp binding documentation [1] states that this should be ok:
>
> If only one phandle is available, then the same OPP table will be used
> for all power domains provided by the power domain provider.
thanks, I mentioned this to Viresh but didn't realize he fixed it up.
Will remove the redundant entries.
>
>
>> + };
>> +
>> + rpmhpd_opp_table: opp-table {
>> + compatible = "operating-points-v2-qcom-level", "operating-points-v2";
>> +
>> + rpmhpd_opp1: opp@1 {
>
> Is there any significance to the 1 through 8 values in these OPP table
> nodes? If not, then could this be changed to something like:
>
> rpmhpd_retention: opp@16 {
> ...
> rpmhpd_turbo_l1: opp@416 {
>
>
>> + qcom-corner = <16>;
>
> s/qcom-corner/qcom,level/g
Thanks, I'll fix these up.
>
>
>> + };
>> +
>> + rpmhpd_opp2: opp@2 {
>> + qcom-corner = <48>;
>> + };
>> +
>> + rpmhpd_opp3: opp@3 {
>> + qcom-corner = <64>;
>> + };
>> +
>> + rpmhpd_opp4: opp@4 {
>> + qcom-corner = <128>;
>> + };
>> +
>> + rpmhpd_opp5: opp@5 {
>> + qcom-corner = <192>;
>> + };
>> +
>> + rpmhpd_opp6: opp@6 {
>> + qcom-corner = <256>;
>> + };
>> +
>> + rpmhpd_opp7: opp@7 {
>> + qcom-corner = <320>;
>> + };
>
> Can you please add 336 and 384 to your example? 384 at least should be
> present as it corresponds to the Turbo level which all supplies support.
will do.
>
>
>> + rpmhpd_opp8: opp@8 {
>> + qcom-corner = <416>;
>> + };
>> + };
>
> How are consumers of these power domains supposed to identify which domain
> within <&rpmhpd> to use (e.g. VDD_CX vs VDD_MX)? If the answer is a plain
> integer index, then could you please add per-platform #define constants in
> a DT header file which explicitly define the meaning for each index?
>
> How do consumers of these power domains identify which level they want to
> set for a specific power domain (e.g. Nominal vs Turbo)?
>
> Would it be helpful to provide a DT header file with #define constants for
> the cross-platform sparse level mapping? This is done in [2] for the
> downstream rpmh-regulator driver that handles ARC managed regulators.
>
>
> Would it be ok to add some consumer DT nodes in this binding file example
> so that it is clear how consumers interact with the rpmhpd?
yes, I'll add the header for indexes and performance levels.
>
>
>> diff --git a/drivers/soc/qcom/Kconfig b/drivers/soc/qcom/Kconfig
>> index a7a405178967..1faed239701d 100644
>> --- a/drivers/soc/qcom/Kconfig
>> +++ b/drivers/soc/qcom/Kconfig
>> @@ -74,6 +74,15 @@ config QCOM_RMTFS_MEM
>>
>> Say y here if you intend to boot the modem remoteproc.
>>
>> +config QCOM_RPMHPD
>> + tristate "Qualcomm RPMh Powerdomain driver"
>
> s/Qualcomm/Qualcomm Technologies, Inc./
All other config options in qcom/Kconfig use 'Qualcomm XYZ feature'
for the comment. Maybe I will leave it that way for consistency?
[]...
>> +
>> +struct rpmhpd {
>> + struct device *dev;
>> + struct generic_pm_domain pd;
>> + struct rpmhpd *peer;
>> + const bool active_only;
>> + unsigned long corner;
>
> Does this actually need to be unsigned long? It looks like unsigned int
> is being passed in from rpmhpd_set_performance(). Also, hlvl values sent
> to RPMh will only every be in the range 0 - 15.
>
> If you change the type here, then can you also please change long to int
> in to_active_sleep() and rpmhpd_aggregate_corner() below?
yes, there's no need for an unsigned long, will change it
>
>
>> + u32 level[RPMH_ARC_MAX_LEVELS];
>> + int level_count;
>> + bool enabled;
>> + const char *res_name;
>> + u32 addr;
>> +};
>
> Can you please indent the fields of this struct to the same column with tabs?
will do.
>
>
>> +
>> +struct rpmhpd_desc {
>> + struct rpmhpd **rpmhpds;
>> + size_t num_pds;
>> +};
>
> This struct could be removed and the per-platform arrays could instead be
> NULL terminated.
Yes, but I would prefer it this way unless you have strong objections.
Just makes it easier to do the allocations at probe for genpd_onecell_data structures.
>> +
>> +static DEFINE_MUTEX(rpmhpd_lock);
>> +
>> +/* sdm845 RPMh powerdomains */
>> +DEFINE_RPMHPD(sdm845, ebi);
>> +DEFINE_RPMHPD_AO(sdm845, mx, mx_ao);
>> +DEFINE_RPMHPD_AO(sdm845, cx, cx_ao);
>> +DEFINE_RPMHPD(sdm845, lmx);
>> +DEFINE_RPMHPD(sdm845, lcx);
>> +DEFINE_RPMHPD(sdm845, gfx);
>> +DEFINE_RPMHPD(sdm845, mss);
>> +
>> +static struct rpmhpd *sdm845_rpmhpds[] = {
>> + [0] = &sdm845_ebi,
>
> If you are going to explicitly index these elements, then can you please
> use #define constants from a DT header file that specifies meaningful
> names? The existing 0-8 indexing is no better than implicit indexing.
yes, I will use the macros from the header.
>
>
>> + [1] = &sdm845_mx,
>> + [2] = &sdm845_mx_ao,
>> + [3] = &sdm845_cx,
>> + [4] = &sdm845_cx_ao,
>> + [5] = &sdm845_lmx,
>> + [6] = &sdm845_lcx,
>> + [7] = &sdm845_gfx,
>> + [8] = &sdm845_mss,
>> +};
>> +
>> +static const struct rpmhpd_desc sdm845_desc = {
>> + .rpmhpds = sdm845_rpmhpds,
>> + .num_pds = ARRAY_SIZE(sdm845_rpmhpds),
>> +};
>> +
>> +static const struct of_device_id rpmhpd_match_table[] = {
>> + { .compatible = "qcom,sdm845-rpmhpd", .data = &sdm845_desc },
>> + { }
>> +};
>> +MODULE_DEVICE_TABLE(of, rpmhpd_match_table);
>> +
>> +static int rpmhpd_send_corner(struct rpmhpd *pd, int state, unsigned int corner)
>> +{
>> + struct tcs_cmd cmd = {
>> + .addr = pd->addr,
>> + .data = corner,
>> + };
>> +
>> + return rpmh_write(pd->dev, state, &cmd, 1);
>
> This can be optimized by calling rpmh_write_async() whenever the corner
> being sent is smaller than the last value sent. That way, no time is
> wasted waiting for an ACK when decreasing voltage. Would you mind adding
> the necessary check and previous request caching for this?
thanks, looks useful, I will do the necessary changes.
>
>
>> +};
>> +
>> +static void to_active_sleep(struct rpmhpd *pd, unsigned long corner,
>> + unsigned long *active, unsigned long *sleep)
>> +{
>> + *active = corner;
>> +
>> + if (pd->active_only)
>> + *sleep = 0;
>> + else
>> + *sleep = *active;
>> +}
>> +
>> +static int rpmhpd_aggregate_corner(struct rpmhpd *pd)
>> +{
>> + int ret;
>> + struct rpmhpd *peer = pd->peer;
>> + unsigned long active_corner, sleep_corner;
>> + unsigned long this_corner = 0, this_sleep_corner = 0;
>> + unsigned long peer_corner = 0, peer_sleep_corner = 0;
>
> s/this_corner/this_active_corner/
> s/peer_corner/peer_active_corner/
>
> This is more consistent and I think that it makes the code a little more
> readable.
sure
>
>
>> +
>> + to_active_sleep(pd, pd->corner, &this_corner, &this_sleep_corner);
>> +
>> + if (peer && peer->enabled)
>> + to_active_sleep(peer, peer->corner, &peer_corner,
>> + &peer_sleep_corner);
>> +
>> + active_corner = max(this_corner, peer_corner);
>> +
>> + ret = rpmhpd_send_corner(pd, RPMH_ACTIVE_ONLY_STATE, active_corner);
>> + if (ret)
>> + return ret;
>> +
>> + sleep_corner = max(this_sleep_corner, peer_sleep_corner);
>> +
>> + return rpmhpd_send_corner(pd, RPMH_SLEEP_STATE, sleep_corner);
>> +}
>
> This aggregation function as well as the rpmhpd_send_corner() calls below
> are not sufficient for RPMh. There are 3 states that must all be used:
> RPMH_ACTIVE_ONLY_STATE, RPMH_WAKE_ONLY_STATE, and RPMH_SLEEP_STATE. The
> naming is somewhat confusing as rpmhpd is defining a different concept of
> active-only.
>
> For power domains without active-only or peers, only
> RPMH_ACTIVE_ONLY_STATE should be used. This instructs RPMh to issue the
> request immediately.
>
> For power domains with active-only, requests will need to be made for all
> three. active_corner would be sent for both RPMH_ACTIVE_ONLY_STATE (so
> that the request takes effect immediately) and RPMH_WAKE_ONLY_STATE (so
> that the request is inserted into the wake TCS). sleep_corner would be
> sent for RPMH_SLEEP_STATE (so that the request is inserted into the sleep
> TCS).
>
> You can see how this is handled in the RPMh clock driver in patch [3].
Thanks, I'll take another look at this and fix this up
>
> You may be able to get away with using only RPMH_SLEEP_STATE and
> RPMH_ACTIVE_ONLY_STATE assuming that you issue the RPMH_SLEEP_STATE
> request first due to the rpmh driver caching behavior added in the
> cache_rpm_request() function in [4]. However, could you please confirm
> with Lina that this usage will continue to work in the future? I'm not
> sure what guarantees are made at the rpmh API level.
sure, I'll check it up
>
>
>> +
>> +static int rpmhpd_power_on(struct generic_pm_domain *domain)
>> +{
>> + int ret = 0;
>> + struct rpmhpd *pd = domain_to_rpmhpd(domain);
>
> Minor: It might look a little nicer to list 'pd' definition first amongst
> the local variables in this function as well as those below.
okay
>
>
>> +
>> + mutex_lock(&rpmhpd_lock);
>> +
>> + pd->enabled = true;
>> +
>> + if (pd->corner)
>> + ret = rpmhpd_aggregate_corner(pd);
>> +
>> + mutex_unlock(&rpmhpd_lock);
>> +
>> + return ret;
>> +}
>> +
>> +static int rpmhpd_power_off(struct generic_pm_domain *domain)
>> +{
>> + int ret;
>> + struct rpmhpd *pd = domain_to_rpmhpd(domain);
>> +
>> + mutex_lock(&rpmhpd_lock);
>> +
>> + if (pd->level[0] == 0) {
>> + ret = rpmhpd_send_corner(pd, RPMH_ACTIVE_ONLY_STATE, 0);
>> + if (ret)
>> + return ret;
>> +
>> + ret = rpmhpd_send_corner(pd, RPMH_SLEEP_STATE, 0);
>> + if (ret)
>> + return ret;
>> + }
>> +
>> + pd->enabled = false;
>> +
>> + mutex_unlock(&rpmhpd_lock);
>> +
>> + return 0;
>> +}
>> +
>> +static int rpmhpd_set_performance(struct generic_pm_domain *domain,
>> + unsigned int state)
>> +{
>> + int ret = 0;
>> + struct rpmhpd *pd = domain_to_rpmhpd(domain);
>> +
>> + mutex_lock(&rpmhpd_lock);
>> +
>> + pd->corner = state;
>
> What is the numbering space for 'state'? I assume that it is a vlvl value
> corresponding to qcom,level in a DT OPP table node. If so, additional
> logic is required.
>
> When using RPMh, the platform and supply independent vlvl sparse numbering
> space is used by consumers so that they can always have consistent values.
> However, the actual requests sent to RPMh ARC must be in the hlvl
> numbering space (i.e. 0 - 15(max)). In the case of this driver, the
> acceptable hlvl values for a given power domain are 0 to pd->level_count - 1.
>
> I suspect that you need to add something like this here:
>
> int i;
>
> for (i = 0; i < pd->level_count; i++)
> if (state <= pd->level[i])
> break;
>
> if (i == pd->level_count) {
> ret = -EINVAL;
> dev_err(pd->dev, "invalid state=%u for domain %s",
> state, pd->pd.name);
> goto out;
> }
>
> pd->corner = i;
>
>
> Note that a given power domain will likely not support all of the vlvl
> values listed in the DT OPP table nodes.
yes indeed :/ I will add the translation bits here for vlvl to hlvl which is
needed before communicating with RPMh
>
>
>> +
>> + if (!pd->enabled)
>> + goto out;
>> +
>> + ret = rpmhpd_aggregate_corner(pd);
>> +out:
>> + mutex_unlock(&rpmhpd_lock);
>> +
>> + return ret;
>> +}
>> +
>> +static unsigned int rpmhpd_get_performance(struct generic_pm_domain *genpd,
>> + struct dev_pm_opp *opp)> +{
>> + struct device_node *np;
>> + unsigned int corner = 0;
>> +
>> + np = dev_pm_opp_get_of_node(opp);
>> + if (of_property_read_u32(np, "qcom,level", &corner)) {
>> + pr_err("%s: missing 'qcom,level' property\n", __func__);
>> + return 0;
>
> Why return 0 instead of an error?
The caller expects a 0 for failure
>
>
>> + }
>> +
>> + of_node_put(np);
>> +
>> + return corner;
>> +}
>
> Is there an API to determine the currently operating performance state of
> a given power domain? Is this information accessible from userspace? We
> will definitely need this for general debugging.
A quick look shows me its not. I agree its a necessary feature for debug.
I will add a patch to expose it via debugfs
>
>
>> +
>> +static int rpmhpd_update_level_mapping(struct rpmhpd *rpmhpd)
>> +{
>> + u8 *buf;
>
> This could be changed to the following in order to remove the need for
> kzalloc() and kfree() calls below:
>
> u8 buf[RPMH_ARC_MAX_LEVELS * RPMH_ARC_LEVEL_SIZE];
>
>
>> + int i, j, len, ret;
>> +
>> + len = cmd_db_read_aux_data_len(rpmhpd->res_name);
>> + if (len <= 0)
>> + return len;
>> +
>
> A check like this is needed here:
>
> if (len > RPMH_ARC_MAX_LEVELS * RPMH_ARC_LEVEL_SIZE)
> return -EINVAL;
>
>
>> + buf = kzalloc(len, GFP_KERNEL);
>> + if (!buf)
>> + return -ENOMEM;
>> +
>> + ret = cmd_db_read_aux_data(rpmhpd->res_name, buf, len);
>> + if (ret < 0)
>> + return ret;
>> +
>> + rpmhpd->level_count = len / RPMH_ARC_LEVEL_SIZE;
>> +
>> + for (i = 0; i < rpmhpd->level_count; i++) {
>
> If you make buf a fixed size array, then rpmhpd->level[i] = 0; is needed
> here or a memset() outside of the for loop.
Okay, I;ll move buf to a fixed size array instead
>
>
>> + for (j = 0; j < RPMH_ARC_LEVEL_SIZE; j++)
>> + rpmhpd->level[i] |=
>> + buf[i * RPMH_ARC_LEVEL_SIZE + j] << (8 * j);
>> +
>> + /*
>> + * The AUX data may be zero padded. These 0 valued entries at
>> + * the end of the map must be ignored.
>> + */
>> + if (i > 0 && rpmhpd->level[i] == 0) {
>> + rpmhpd->level_count = i;
>> + break;
>> + }
>> + pr_dbg("%s: ARC hlvl=%2d --> vlvl=%4u\n", rpmhpd->res_name, i,
>> + rpmhpd->level[i]);
>> + }
>> +
>> + kfree(buf);
>> + return 0;
>> +}
>> +
>> +static int rpmhpd_probe(struct platform_device *pdev)
>> +{
>> + int i, ret;
>> + size_t num;
>> + struct genpd_onecell_data *data;
>> + struct rpmhpd **rpmhpds;
>> + const struct rpmhpd_desc *desc;
>> +
>> + desc = of_device_get_match_data(&pdev->dev);
>> + if (!desc)
>> + return -EINVAL;
>> +
>> + rpmhpds = desc->rpmhpds;
>> + num = desc->num_pds;
>> +
>> + data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL);
>> + if (!data)
>> + return -ENOMEM;
>> +
>> + data->domains = devm_kcalloc(&pdev->dev, num, sizeof(*data->domains),
>> + GFP_KERNEL);
>> + data->num_domains = num;
>> +
>> + ret = cmd_db_ready();
>> + if (ret) {
>> + if (ret != -EPROBE_DEFER)
>> + dev_err(&pdev->dev, "Command DB unavailable, ret=%d\n",
>> + ret);
>> + return ret;
>> + }
>> +
>> + for (i = 0; i < num; i++) {
>> + if (!rpmhpds[i])
>> + continue;
>
> Why is this check needed?
Just to check/ignore if there are any holes.
maybe I should atleast throw a warning instead of silently ignoring it?
>
>
>> +
>> + rpmhpds[i]->dev = &pdev->dev;
>> + rpmhpds[i]->addr = cmd_db_read_addr(rpmhpds[i]->res_name);
>> + if (!rpmhpds[i]->addr) {
>> + dev_err(&pdev->dev, "Could not find RPMh address for resource %s\n",
>> + rpmhpds[i]->res_name);
>> + return -ENODEV;
>> + }
>> +
>> + ret = cmd_db_read_slave_id(rpmhpds[i]->res_name);
>> + if (ret != CMD_DB_HW_ARC) {
>> + dev_err(&pdev->dev, "RPMh slave ID mismatch\n");
>> + return -EINVAL;
>> + }
>> +
>> + ret = rpmhpd_update_level_mapping(rpmhpds[i]);
>> + if (ret)
>> + return ret;
>> +
>> + rpmhpds[i]->pd.power_off = rpmhpd_power_off;
>> + rpmhpds[i]->pd.power_on = rpmhpd_power_on;
>> + rpmhpds[i]->pd.set_performance_state = rpmhpd_set_performance;
>> + rpmhpds[i]->pd.opp_to_performance_state = rpmhpd_get_performance;
>> + pm_genpd_init(&rpmhpds[i]->pd, NULL, true);
>> +
>> + data->domains[i] = &rpmhpds[i]->pd;
>> + }
>> +
>> + return of_genpd_add_provider_onecell(pdev->dev.of_node, data);
>> +}
>> +
>> +static int rpmhpd_remove(struct platform_device *pdev)
>> +{
>> + of_genpd_del_provider(pdev->dev.of_node);
>> + return 0;
>> +}
>> +
>> +static struct platform_driver rpmhpd_driver = {
>> + .driver = {
>> + .name = "qcom-rpmhpd",
>> + .of_match_table = rpmhpd_match_table,
>> + },
>> + .probe = rpmhpd_probe,
>> + .remove = rpmhpd_remove,
>> +};
>> +
>> +static int __init rpmhpd_init(void)
>> +{
>> + return platform_driver_register(&rpmhpd_driver);
>> +}
>> +core_initcall(rpmhpd_init);
>> +
>> +static void __exit rpmhpd_exit(void)
>> +{
>> + platform_driver_unregister(&rpmhpd_driver);
>> +}
>> +module_exit(rpmhpd_exit);
>> +
>> +MODULE_DESCRIPTION("Qualcomm RPMh Power Domain Driver");
>
> s/Qualcomm/Qualcomm Technologies, Inc./
will do
>
>
>> +MODULE_LICENSE("GPL v2");
>> +MODULE_ALIAS("platform:qcom-rpmhpd");
>
> Thanks,
> David
Thanks David for taking time to review.
--
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum,
hosted by The Linux Foundation
^ permalink raw reply
* [PATCH 6/6] ASoC: qdsp6: q6routing: Add support to all TDM Mixers
From: Srinivas Kandagatla @ 2018-05-29 10:18 UTC (permalink / raw)
To: broonie, linux-arm-msm, alsa-devel, robh+dt, bgoswami
Cc: mark.rutland, lgirdwood, plai, tiwai, perex, devicetree,
linux-kernel, linux-arm-kernel, rohkumar, spatakok,
Srinivas Kandagatla
In-Reply-To: <20180529101833.30489-1-srinivas.kandagatla@linaro.org>
This patch adds TX and RX TDM mixers for 40 TDM ports.
Signed-off-by: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
---
sound/soc/qcom/qdsp6/q6routing.c | 455 ++++++++++++++++++++++++++++++++++++++-
1 file changed, 454 insertions(+), 1 deletion(-)
diff --git a/sound/soc/qcom/qdsp6/q6routing.c b/sound/soc/qcom/qdsp6/q6routing.c
index a4e74cac491b..593f66b8622f 100644
--- a/sound/soc/qcom/qdsp6/q6routing.c
+++ b/sound/soc/qcom/qdsp6/q6routing.c
@@ -67,7 +67,47 @@
{ mix_name, "PRI_MI2S_TX", "PRI_MI2S_TX" }, \
{ mix_name, "SEC_MI2S_TX", "SEC_MI2S_TX" }, \
{ mix_name, "QUAT_MI2S_TX", "QUAT_MI2S_TX" }, \
- { mix_name, "TERT_MI2S_TX", "TERT_MI2S_TX" }
+ { mix_name, "TERT_MI2S_TX", "TERT_MI2S_TX" }, \
+ { mix_name, "PRIMARY_TDM_TX_0", "PRIMARY_TDM_TX_0"}, \
+ { mix_name, "PRIMARY_TDM_TX_1", "PRIMARY_TDM_TX_1"}, \
+ { mix_name, "PRIMARY_TDM_TX_2", "PRIMARY_TDM_TX_2"}, \
+ { mix_name, "PRIMARY_TDM_TX_3", "PRIMARY_TDM_TX_3"}, \
+ { mix_name, "PRIMARY_TDM_TX_4", "PRIMARY_TDM_TX_4"}, \
+ { mix_name, "PRIMARY_TDM_TX_5", "PRIMARY_TDM_TX_5"}, \
+ { mix_name, "PRIMARY_TDM_TX_6", "PRIMARY_TDM_TX_6"}, \
+ { mix_name, "PRIMARY_TDM_TX_7", "PRIMARY_TDM_TX_7"}, \
+ { mix_name, "SEC_TDM_TX_0", "SEC_TDM_TX_0"}, \
+ { mix_name, "SEC_TDM_TX_1", "SEC_TDM_TX_1"}, \
+ { mix_name, "SEC_TDM_TX_2", "SEC_TDM_TX_2"}, \
+ { mix_name, "SEC_TDM_TX_3", "SEC_TDM_TX_3"}, \
+ { mix_name, "SEC_TDM_TX_4", "SEC_TDM_TX_4"}, \
+ { mix_name, "SEC_TDM_TX_5", "SEC_TDM_TX_5"}, \
+ { mix_name, "SEC_TDM_TX_6", "SEC_TDM_TX_6"}, \
+ { mix_name, "SEC_TDM_TX_7", "SEC_TDM_TX_7"}, \
+ { mix_name, "TERT_TDM_TX_0", "TERT_TDM_TX_0"}, \
+ { mix_name, "TERT_TDM_TX_1", "TERT_TDM_TX_1"}, \
+ { mix_name, "TERT_TDM_TX_2", "TERT_TDM_TX_2"}, \
+ { mix_name, "TERT_TDM_TX_3", "TERT_TDM_TX_3"}, \
+ { mix_name, "TERT_TDM_TX_4", "TERT_TDM_TX_4"}, \
+ { mix_name, "TERT_TDM_TX_5", "TERT_TDM_TX_5"}, \
+ { mix_name, "TERT_TDM_TX_6", "TERT_TDM_TX_6"}, \
+ { mix_name, "TERT_TDM_TX_7", "TERT_TDM_TX_7"}, \
+ { mix_name, "QUAT_TDM_TX_0", "QUAT_TDM_TX_0"}, \
+ { mix_name, "QUAT_TDM_TX_1", "QUAT_TDM_TX_1"}, \
+ { mix_name, "QUAT_TDM_TX_2", "QUAT_TDM_TX_2"}, \
+ { mix_name, "QUAT_TDM_TX_3", "QUAT_TDM_TX_3"}, \
+ { mix_name, "QUAT_TDM_TX_4", "QUAT_TDM_TX_4"}, \
+ { mix_name, "QUAT_TDM_TX_5", "QUAT_TDM_TX_5"}, \
+ { mix_name, "QUAT_TDM_TX_6", "QUAT_TDM_TX_6"}, \
+ { mix_name, "QUAT_TDM_TX_7", "QUAT_TDM_TX_7"}, \
+ { mix_name, "QUIN_TDM_TX_0", "QUIN_TDM_TX_0"}, \
+ { mix_name, "QUIN_TDM_TX_1", "QUIN_TDM_TX_1"}, \
+ { mix_name, "QUIN_TDM_TX_2", "QUIN_TDM_TX_2"}, \
+ { mix_name, "QUIN_TDM_TX_3", "QUIN_TDM_TX_3"}, \
+ { mix_name, "QUIN_TDM_TX_4", "QUIN_TDM_TX_4"}, \
+ { mix_name, "QUIN_TDM_TX_5", "QUIN_TDM_TX_5"}, \
+ { mix_name, "QUIN_TDM_TX_6", "QUIN_TDM_TX_6"}, \
+ { mix_name, "QUIN_TDM_TX_7", "QUIN_TDM_TX_7"}
#define Q6ROUTING_TX_MIXERS(id) \
SOC_SINGLE_EXT("PRI_MI2S_TX", PRIMARY_MI2S_TX, \
@@ -80,6 +120,126 @@
id, 1, 0, msm_routing_get_audio_mixer, \
msm_routing_put_audio_mixer), \
SOC_SINGLE_EXT("QUAT_MI2S_TX", QUATERNARY_MI2S_TX, \
+ id, 1, 0, msm_routing_get_audio_mixer, \
+ msm_routing_put_audio_mixer), \
+ SOC_SINGLE_EXT("PRIMARY_TDM_TX_0", PRIMARY_TDM_TX_0, \
+ id, 1, 0, msm_routing_get_audio_mixer, \
+ msm_routing_put_audio_mixer), \
+ SOC_SINGLE_EXT("PRIMARY_TDM_TX_1", PRIMARY_TDM_TX_1, \
+ id, 1, 0, msm_routing_get_audio_mixer, \
+ msm_routing_put_audio_mixer), \
+ SOC_SINGLE_EXT("PRIMARY_TDM_TX_2", PRIMARY_TDM_TX_2, \
+ id, 1, 0, msm_routing_get_audio_mixer, \
+ msm_routing_put_audio_mixer), \
+ SOC_SINGLE_EXT("PRIMARY_TDM_TX_3", PRIMARY_TDM_TX_3, \
+ id, 1, 0, msm_routing_get_audio_mixer, \
+ msm_routing_put_audio_mixer), \
+ SOC_SINGLE_EXT("PRIMARY_TDM_TX_4", PRIMARY_TDM_TX_4, \
+ id, 1, 0, msm_routing_get_audio_mixer, \
+ msm_routing_put_audio_mixer), \
+ SOC_SINGLE_EXT("PRIMARY_TDM_TX_5", PRIMARY_TDM_TX_5, \
+ id, 1, 0, msm_routing_get_audio_mixer, \
+ msm_routing_put_audio_mixer), \
+ SOC_SINGLE_EXT("PRIMARY_TDM_TX_6", PRIMARY_TDM_TX_6, \
+ id, 1, 0, msm_routing_get_audio_mixer, \
+ msm_routing_put_audio_mixer), \
+ SOC_SINGLE_EXT("PRIMARY_TDM_TX_7", PRIMARY_TDM_TX_7, \
+ id, 1, 0, msm_routing_get_audio_mixer, \
+ msm_routing_put_audio_mixer), \
+ SOC_SINGLE_EXT("SEC_TDM_TX_0", SECONDARY_TDM_TX_0, \
+ id, 1, 0, msm_routing_get_audio_mixer, \
+ msm_routing_put_audio_mixer), \
+ SOC_SINGLE_EXT("SEC_TDM_TX_1", SECONDARY_TDM_TX_1, \
+ id, 1, 0, msm_routing_get_audio_mixer, \
+ msm_routing_put_audio_mixer), \
+ SOC_SINGLE_EXT("SEC_TDM_TX_2", SECONDARY_TDM_TX_2, \
+ id, 1, 0, msm_routing_get_audio_mixer, \
+ msm_routing_put_audio_mixer), \
+ SOC_SINGLE_EXT("SEC_TDM_TX_3", SECONDARY_TDM_TX_3, \
+ id, 1, 0, msm_routing_get_audio_mixer, \
+ msm_routing_put_audio_mixer), \
+ SOC_SINGLE_EXT("SEC_TDM_TX_4", SECONDARY_TDM_TX_4, \
+ id, 1, 0, msm_routing_get_audio_mixer, \
+ msm_routing_put_audio_mixer), \
+ SOC_SINGLE_EXT("SEC_TDM_TX_5", SECONDARY_TDM_TX_5, \
+ id, 1, 0, msm_routing_get_audio_mixer, \
+ msm_routing_put_audio_mixer), \
+ SOC_SINGLE_EXT("SEC_TDM_TX_6", SECONDARY_TDM_TX_6, \
+ id, 1, 0, msm_routing_get_audio_mixer, \
+ msm_routing_put_audio_mixer), \
+ SOC_SINGLE_EXT("SEC_TDM_TX_7", SECONDARY_TDM_TX_7, \
+ id, 1, 0, msm_routing_get_audio_mixer, \
+ msm_routing_put_audio_mixer), \
+ SOC_SINGLE_EXT("TERT_TDM_TX_0", TERTIARY_TDM_TX_0, \
+ id, 1, 0, msm_routing_get_audio_mixer, \
+ msm_routing_put_audio_mixer), \
+ SOC_SINGLE_EXT("TERT_TDM_TX_1", TERTIARY_TDM_TX_1, \
+ id, 1, 0, msm_routing_get_audio_mixer, \
+ msm_routing_put_audio_mixer), \
+ SOC_SINGLE_EXT("TERT_TDM_TX_2", TERTIARY_TDM_TX_2, \
+ id, 1, 0, msm_routing_get_audio_mixer, \
+ msm_routing_put_audio_mixer), \
+ SOC_SINGLE_EXT("TERT_TDM_TX_3", TERTIARY_TDM_TX_3, \
+ id, 1, 0, msm_routing_get_audio_mixer, \
+ msm_routing_put_audio_mixer), \
+ SOC_SINGLE_EXT("TERT_TDM_TX_4", TERTIARY_TDM_TX_4, \
+ id, 1, 0, msm_routing_get_audio_mixer, \
+ msm_routing_put_audio_mixer), \
+ SOC_SINGLE_EXT("TERT_TDM_TX_5", TERTIARY_TDM_TX_5, \
+ id, 1, 0, msm_routing_get_audio_mixer, \
+ msm_routing_put_audio_mixer), \
+ SOC_SINGLE_EXT("TERT_TDM_TX_6", TERTIARY_TDM_TX_6, \
+ id, 1, 0, msm_routing_get_audio_mixer, \
+ msm_routing_put_audio_mixer), \
+ SOC_SINGLE_EXT("TERT_TDM_TX_7", TERTIARY_TDM_TX_7, \
+ id, 1, 0, msm_routing_get_audio_mixer, \
+ msm_routing_put_audio_mixer), \
+ SOC_SINGLE_EXT("QUAT_TDM_TX_0", QUATERNARY_TDM_TX_0, \
+ id, 1, 0, msm_routing_get_audio_mixer, \
+ msm_routing_put_audio_mixer), \
+ SOC_SINGLE_EXT("QUAT_TDM_TX_1", QUATERNARY_TDM_TX_1, \
+ id, 1, 0, msm_routing_get_audio_mixer, \
+ msm_routing_put_audio_mixer), \
+ SOC_SINGLE_EXT("QUAT_TDM_TX_2", QUATERNARY_TDM_TX_2, \
+ id, 1, 0, msm_routing_get_audio_mixer, \
+ msm_routing_put_audio_mixer), \
+ SOC_SINGLE_EXT("QUAT_TDM_TX_3", QUATERNARY_TDM_TX_3, \
+ id, 1, 0, msm_routing_get_audio_mixer, \
+ msm_routing_put_audio_mixer), \
+ SOC_SINGLE_EXT("QUAT_TDM_TX_4", QUATERNARY_TDM_TX_4, \
+ id, 1, 0, msm_routing_get_audio_mixer, \
+ msm_routing_put_audio_mixer), \
+ SOC_SINGLE_EXT("QUAT_TDM_TX_5", QUATERNARY_TDM_TX_5, \
+ id, 1, 0, msm_routing_get_audio_mixer, \
+ msm_routing_put_audio_mixer), \
+ SOC_SINGLE_EXT("QUAT_TDM_TX_6", QUATERNARY_TDM_TX_6, \
+ id, 1, 0, msm_routing_get_audio_mixer, \
+ msm_routing_put_audio_mixer), \
+ SOC_SINGLE_EXT("QUAT_TDM_TX_7", QUATERNARY_TDM_TX_7, \
+ id, 1, 0, msm_routing_get_audio_mixer, \
+ msm_routing_put_audio_mixer), \
+ SOC_SINGLE_EXT("QUIN_TDM_TX_0", QUINARY_TDM_TX_0, \
+ id, 1, 0, msm_routing_get_audio_mixer, \
+ msm_routing_put_audio_mixer), \
+ SOC_SINGLE_EXT("QUIN_TDM_TX_1", QUINARY_TDM_TX_1, \
+ id, 1, 0, msm_routing_get_audio_mixer, \
+ msm_routing_put_audio_mixer), \
+ SOC_SINGLE_EXT("QUIN_TDM_TX_2", QUINARY_TDM_TX_2, \
+ id, 1, 0, msm_routing_get_audio_mixer, \
+ msm_routing_put_audio_mixer), \
+ SOC_SINGLE_EXT("QUIN_TDM_TX_3", QUINARY_TDM_TX_3, \
+ id, 1, 0, msm_routing_get_audio_mixer, \
+ msm_routing_put_audio_mixer), \
+ SOC_SINGLE_EXT("QUIN_TDM_TX_4", QUINARY_TDM_TX_4, \
+ id, 1, 0, msm_routing_get_audio_mixer, \
+ msm_routing_put_audio_mixer), \
+ SOC_SINGLE_EXT("QUIN_TDM_TX_5", QUINARY_TDM_TX_5, \
+ id, 1, 0, msm_routing_get_audio_mixer, \
+ msm_routing_put_audio_mixer), \
+ SOC_SINGLE_EXT("QUIN_TDM_TX_6", QUINARY_TDM_TX_6, \
+ id, 1, 0, msm_routing_get_audio_mixer, \
+ msm_routing_put_audio_mixer), \
+ SOC_SINGLE_EXT("QUIN_TDM_TX_7", QUINARY_TDM_TX_7, \
id, 1, 0, msm_routing_get_audio_mixer, \
msm_routing_put_audio_mixer),
@@ -299,6 +459,127 @@ static const struct snd_kcontrol_new slimbus_5_rx_mixer_controls[] = {
static const struct snd_kcontrol_new slimbus_6_rx_mixer_controls[] = {
Q6ROUTING_RX_MIXERS(SLIMBUS_6_RX) };
+static const struct snd_kcontrol_new pri_tdm_rx_0_mixer_controls[] = {
+ Q6ROUTING_RX_MIXERS(PRIMARY_TDM_RX_0) };
+
+static const struct snd_kcontrol_new pri_tdm_rx_1_mixer_controls[] = {
+ Q6ROUTING_RX_MIXERS(PRIMARY_TDM_RX_1) };
+
+static const struct snd_kcontrol_new pri_tdm_rx_2_mixer_controls[] = {
+ Q6ROUTING_RX_MIXERS(PRIMARY_TDM_RX_2) };
+
+static const struct snd_kcontrol_new pri_tdm_rx_3_mixer_controls[] = {
+ Q6ROUTING_RX_MIXERS(PRIMARY_TDM_RX_3) };
+
+static const struct snd_kcontrol_new pri_tdm_rx_4_mixer_controls[] = {
+ Q6ROUTING_RX_MIXERS(PRIMARY_TDM_RX_4) };
+
+static const struct snd_kcontrol_new pri_tdm_rx_5_mixer_controls[] = {
+ Q6ROUTING_RX_MIXERS(PRIMARY_TDM_RX_5) };
+
+static const struct snd_kcontrol_new pri_tdm_rx_6_mixer_controls[] = {
+ Q6ROUTING_RX_MIXERS(PRIMARY_TDM_RX_6) };
+
+static const struct snd_kcontrol_new pri_tdm_rx_7_mixer_controls[] = {
+ Q6ROUTING_RX_MIXERS(PRIMARY_TDM_RX_7) };
+
+static const struct snd_kcontrol_new sec_tdm_rx_0_mixer_controls[] = {
+ Q6ROUTING_RX_MIXERS(SECONDARY_TDM_RX_0) };
+
+static const struct snd_kcontrol_new sec_tdm_rx_1_mixer_controls[] = {
+ Q6ROUTING_RX_MIXERS(SECONDARY_TDM_RX_1) };
+
+static const struct snd_kcontrol_new sec_tdm_rx_2_mixer_controls[] = {
+ Q6ROUTING_RX_MIXERS(SECONDARY_TDM_RX_2) };
+
+static const struct snd_kcontrol_new sec_tdm_rx_3_mixer_controls[] = {
+ Q6ROUTING_RX_MIXERS(SECONDARY_TDM_RX_3) };
+
+static const struct snd_kcontrol_new sec_tdm_rx_4_mixer_controls[] = {
+ Q6ROUTING_RX_MIXERS(SECONDARY_TDM_RX_4) };
+
+static const struct snd_kcontrol_new sec_tdm_rx_5_mixer_controls[] = {
+ Q6ROUTING_RX_MIXERS(SECONDARY_TDM_RX_5) };
+
+static const struct snd_kcontrol_new sec_tdm_rx_6_mixer_controls[] = {
+ Q6ROUTING_RX_MIXERS(SECONDARY_TDM_RX_6) };
+
+static const struct snd_kcontrol_new sec_tdm_rx_7_mixer_controls[] = {
+ Q6ROUTING_RX_MIXERS(SECONDARY_TDM_RX_7) };
+
+static const struct snd_kcontrol_new tert_tdm_rx_0_mixer_controls[] = {
+ Q6ROUTING_RX_MIXERS(TERTIARY_TDM_RX_0) };
+
+static const struct snd_kcontrol_new tert_tdm_rx_1_mixer_controls[] = {
+ Q6ROUTING_RX_MIXERS(TERTIARY_TDM_RX_1) };
+
+static const struct snd_kcontrol_new tert_tdm_rx_2_mixer_controls[] = {
+ Q6ROUTING_RX_MIXERS(TERTIARY_TDM_RX_2) };
+
+static const struct snd_kcontrol_new tert_tdm_rx_3_mixer_controls[] = {
+ Q6ROUTING_RX_MIXERS(TERTIARY_TDM_RX_3) };
+
+static const struct snd_kcontrol_new tert_tdm_rx_4_mixer_controls[] = {
+ Q6ROUTING_RX_MIXERS(TERTIARY_TDM_RX_4) };
+
+static const struct snd_kcontrol_new tert_tdm_rx_5_mixer_controls[] = {
+ Q6ROUTING_RX_MIXERS(TERTIARY_TDM_RX_5) };
+
+static const struct snd_kcontrol_new tert_tdm_rx_6_mixer_controls[] = {
+ Q6ROUTING_RX_MIXERS(TERTIARY_TDM_RX_6) };
+
+static const struct snd_kcontrol_new tert_tdm_rx_7_mixer_controls[] = {
+ Q6ROUTING_RX_MIXERS(TERTIARY_TDM_RX_7) };
+
+static const struct snd_kcontrol_new quat_tdm_rx_0_mixer_controls[] = {
+ Q6ROUTING_RX_MIXERS(QUATERNARY_TDM_RX_0) };
+
+static const struct snd_kcontrol_new quat_tdm_rx_1_mixer_controls[] = {
+ Q6ROUTING_RX_MIXERS(QUATERNARY_TDM_RX_1) };
+
+static const struct snd_kcontrol_new quat_tdm_rx_2_mixer_controls[] = {
+ Q6ROUTING_RX_MIXERS(QUATERNARY_TDM_RX_2) };
+
+static const struct snd_kcontrol_new quat_tdm_rx_3_mixer_controls[] = {
+ Q6ROUTING_RX_MIXERS(QUATERNARY_TDM_RX_3) };
+
+static const struct snd_kcontrol_new quat_tdm_rx_4_mixer_controls[] = {
+ Q6ROUTING_RX_MIXERS(QUATERNARY_TDM_RX_4) };
+
+static const struct snd_kcontrol_new quat_tdm_rx_5_mixer_controls[] = {
+ Q6ROUTING_RX_MIXERS(QUATERNARY_TDM_RX_5) };
+
+static const struct snd_kcontrol_new quat_tdm_rx_6_mixer_controls[] = {
+ Q6ROUTING_RX_MIXERS(QUATERNARY_TDM_RX_6) };
+
+static const struct snd_kcontrol_new quat_tdm_rx_7_mixer_controls[] = {
+ Q6ROUTING_RX_MIXERS(QUATERNARY_TDM_RX_7) };
+
+static const struct snd_kcontrol_new quin_tdm_rx_0_mixer_controls[] = {
+ Q6ROUTING_RX_MIXERS(QUINARY_TDM_RX_0) };
+
+static const struct snd_kcontrol_new quin_tdm_rx_1_mixer_controls[] = {
+ Q6ROUTING_RX_MIXERS(QUINARY_TDM_RX_1) };
+
+static const struct snd_kcontrol_new quin_tdm_rx_2_mixer_controls[] = {
+ Q6ROUTING_RX_MIXERS(QUINARY_TDM_RX_2) };
+
+static const struct snd_kcontrol_new quin_tdm_rx_3_mixer_controls[] = {
+ Q6ROUTING_RX_MIXERS(QUINARY_TDM_RX_3) };
+
+static const struct snd_kcontrol_new quin_tdm_rx_4_mixer_controls[] = {
+ Q6ROUTING_RX_MIXERS(QUINARY_TDM_RX_4) };
+
+static const struct snd_kcontrol_new quin_tdm_rx_5_mixer_controls[] = {
+ Q6ROUTING_RX_MIXERS(QUINARY_TDM_RX_5) };
+
+static const struct snd_kcontrol_new quin_tdm_rx_6_mixer_controls[] = {
+ Q6ROUTING_RX_MIXERS(QUINARY_TDM_RX_6) };
+
+static const struct snd_kcontrol_new quin_tdm_rx_7_mixer_controls[] = {
+ Q6ROUTING_RX_MIXERS(QUINARY_TDM_RX_7) };
+
+
static const struct snd_kcontrol_new mmul1_mixer_controls[] = {
Q6ROUTING_TX_MIXERS(MSM_FRONTEND_DAI_MULTIMEDIA1) };
@@ -380,6 +661,130 @@ static const struct snd_soc_dapm_widget msm_qdsp6_widgets[] = {
SND_SOC_DAPM_MIXER("TERT_MI2S_RX Audio Mixer", SND_SOC_NOPM, 0, 0,
tertiary_mi2s_rx_mixer_controls,
ARRAY_SIZE(tertiary_mi2s_rx_mixer_controls)),
+ SND_SOC_DAPM_MIXER("PRIMARY_TDM_RX_0 Audio Mixer", SND_SOC_NOPM, 0, 0,
+ pri_tdm_rx_0_mixer_controls,
+ ARRAY_SIZE(pri_tdm_rx_0_mixer_controls)),
+ SND_SOC_DAPM_MIXER("PRIMARY_TDM_RX_1 Audio Mixer", SND_SOC_NOPM, 0, 0,
+ pri_tdm_rx_1_mixer_controls,
+ ARRAY_SIZE(pri_tdm_rx_1_mixer_controls)),
+ SND_SOC_DAPM_MIXER("PRIMARY_TDM_RX_2 Audio Mixer", SND_SOC_NOPM, 0, 0,
+ pri_tdm_rx_2_mixer_controls,
+ ARRAY_SIZE(pri_tdm_rx_2_mixer_controls)),
+ SND_SOC_DAPM_MIXER("PRIMARY_TDM_RX_3 Audio Mixer", SND_SOC_NOPM, 0, 0,
+ pri_tdm_rx_3_mixer_controls,
+ ARRAY_SIZE(pri_tdm_rx_3_mixer_controls)),
+ SND_SOC_DAPM_MIXER("PRIMARY_TDM_RX_4 Audio Mixer", SND_SOC_NOPM, 0, 0,
+ pri_tdm_rx_4_mixer_controls,
+ ARRAY_SIZE(pri_tdm_rx_4_mixer_controls)),
+ SND_SOC_DAPM_MIXER("PRIMARY_TDM_RX_5 Audio Mixer", SND_SOC_NOPM, 0, 0,
+ pri_tdm_rx_5_mixer_controls,
+ ARRAY_SIZE(pri_tdm_rx_5_mixer_controls)),
+ SND_SOC_DAPM_MIXER("PRIMARY_TDM_RX_6 Audio Mixer", SND_SOC_NOPM, 0, 0,
+ pri_tdm_rx_6_mixer_controls,
+ ARRAY_SIZE(pri_tdm_rx_6_mixer_controls)),
+ SND_SOC_DAPM_MIXER("PRIMARY_TDM_RX_7 Audio Mixer", SND_SOC_NOPM, 0, 0,
+ pri_tdm_rx_7_mixer_controls,
+ ARRAY_SIZE(pri_tdm_rx_7_mixer_controls)),
+
+ SND_SOC_DAPM_MIXER("SEC_TDM_RX_0 Audio Mixer", SND_SOC_NOPM, 0, 0,
+ sec_tdm_rx_0_mixer_controls,
+ ARRAY_SIZE(sec_tdm_rx_0_mixer_controls)),
+ SND_SOC_DAPM_MIXER("SEC_TDM_RX_1 Audio Mixer", SND_SOC_NOPM, 0, 0,
+ sec_tdm_rx_1_mixer_controls,
+ ARRAY_SIZE(sec_tdm_rx_1_mixer_controls)),
+ SND_SOC_DAPM_MIXER("SEC_TDM_RX_2 Audio Mixer", SND_SOC_NOPM, 0, 0,
+ sec_tdm_rx_2_mixer_controls,
+ ARRAY_SIZE(sec_tdm_rx_2_mixer_controls)),
+ SND_SOC_DAPM_MIXER("SEC_TDM_RX_3 Audio Mixer", SND_SOC_NOPM, 0, 0,
+ sec_tdm_rx_3_mixer_controls,
+ ARRAY_SIZE(sec_tdm_rx_3_mixer_controls)),
+ SND_SOC_DAPM_MIXER("SEC_TDM_RX_4 Audio Mixer", SND_SOC_NOPM, 0, 0,
+ sec_tdm_rx_4_mixer_controls,
+ ARRAY_SIZE(sec_tdm_rx_4_mixer_controls)),
+ SND_SOC_DAPM_MIXER("SEC_TDM_RX_5 Audio Mixer", SND_SOC_NOPM, 0, 0,
+ sec_tdm_rx_5_mixer_controls,
+ ARRAY_SIZE(sec_tdm_rx_5_mixer_controls)),
+ SND_SOC_DAPM_MIXER("SEC_TDM_RX_6 Audio Mixer", SND_SOC_NOPM, 0, 0,
+ sec_tdm_rx_6_mixer_controls,
+ ARRAY_SIZE(sec_tdm_rx_6_mixer_controls)),
+ SND_SOC_DAPM_MIXER("SEC_TDM_RX_7 Audio Mixer", SND_SOC_NOPM, 0, 0,
+ sec_tdm_rx_7_mixer_controls,
+ ARRAY_SIZE(sec_tdm_rx_7_mixer_controls)),
+
+ SND_SOC_DAPM_MIXER("TERT_TDM_RX_0 Audio Mixer", SND_SOC_NOPM, 0, 0,
+ tert_tdm_rx_0_mixer_controls,
+ ARRAY_SIZE(tert_tdm_rx_0_mixer_controls)),
+ SND_SOC_DAPM_MIXER("TERT_TDM_RX_1 Audio Mixer", SND_SOC_NOPM, 0, 0,
+ tert_tdm_rx_1_mixer_controls,
+ ARRAY_SIZE(tert_tdm_rx_1_mixer_controls)),
+ SND_SOC_DAPM_MIXER("TERT_TDM_RX_2 Audio Mixer", SND_SOC_NOPM, 0, 0,
+ tert_tdm_rx_2_mixer_controls,
+ ARRAY_SIZE(tert_tdm_rx_2_mixer_controls)),
+ SND_SOC_DAPM_MIXER("TERT_TDM_RX_3 Audio Mixer", SND_SOC_NOPM, 0, 0,
+ tert_tdm_rx_3_mixer_controls,
+ ARRAY_SIZE(tert_tdm_rx_3_mixer_controls)),
+ SND_SOC_DAPM_MIXER("TERT_TDM_RX_4 Audio Mixer", SND_SOC_NOPM, 0, 0,
+ tert_tdm_rx_4_mixer_controls,
+ ARRAY_SIZE(tert_tdm_rx_4_mixer_controls)),
+ SND_SOC_DAPM_MIXER("TERT_TDM_RX_5 Audio Mixer", SND_SOC_NOPM, 0, 0,
+ tert_tdm_rx_5_mixer_controls,
+ ARRAY_SIZE(tert_tdm_rx_5_mixer_controls)),
+ SND_SOC_DAPM_MIXER("TERT_TDM_RX_6 Audio Mixer", SND_SOC_NOPM, 0, 0,
+ tert_tdm_rx_6_mixer_controls,
+ ARRAY_SIZE(tert_tdm_rx_6_mixer_controls)),
+ SND_SOC_DAPM_MIXER("TERT_TDM_RX_7 Audio Mixer", SND_SOC_NOPM, 0, 0,
+ tert_tdm_rx_7_mixer_controls,
+ ARRAY_SIZE(tert_tdm_rx_7_mixer_controls)),
+
+ SND_SOC_DAPM_MIXER("QUAT_TDM_RX_0 Audio Mixer", SND_SOC_NOPM, 0, 0,
+ quat_tdm_rx_0_mixer_controls,
+ ARRAY_SIZE(quat_tdm_rx_0_mixer_controls)),
+ SND_SOC_DAPM_MIXER("QUAT_TDM_RX_1 Audio Mixer", SND_SOC_NOPM, 0, 0,
+ quat_tdm_rx_1_mixer_controls,
+ ARRAY_SIZE(quat_tdm_rx_1_mixer_controls)),
+ SND_SOC_DAPM_MIXER("QUAT_TDM_RX_2 Audio Mixer", SND_SOC_NOPM, 0, 0,
+ quat_tdm_rx_2_mixer_controls,
+ ARRAY_SIZE(quat_tdm_rx_2_mixer_controls)),
+ SND_SOC_DAPM_MIXER("QUAT_TDM_RX_3 Audio Mixer", SND_SOC_NOPM, 0, 0,
+ quat_tdm_rx_3_mixer_controls,
+ ARRAY_SIZE(quat_tdm_rx_3_mixer_controls)),
+ SND_SOC_DAPM_MIXER("QUAT_TDM_RX_4 Audio Mixer", SND_SOC_NOPM, 0, 0,
+ quat_tdm_rx_4_mixer_controls,
+ ARRAY_SIZE(quat_tdm_rx_4_mixer_controls)),
+ SND_SOC_DAPM_MIXER("QUAT_TDM_RX_5 Audio Mixer", SND_SOC_NOPM, 0, 0,
+ quat_tdm_rx_5_mixer_controls,
+ ARRAY_SIZE(quat_tdm_rx_5_mixer_controls)),
+ SND_SOC_DAPM_MIXER("QUAT_TDM_RX_6 Audio Mixer", SND_SOC_NOPM, 0, 0,
+ quat_tdm_rx_6_mixer_controls,
+ ARRAY_SIZE(quat_tdm_rx_6_mixer_controls)),
+ SND_SOC_DAPM_MIXER("QUAT_TDM_RX_7 Audio Mixer", SND_SOC_NOPM, 0, 0,
+ quat_tdm_rx_7_mixer_controls,
+ ARRAY_SIZE(quat_tdm_rx_7_mixer_controls)),
+
+ SND_SOC_DAPM_MIXER("QUIN_TDM_RX_0 Audio Mixer", SND_SOC_NOPM, 0, 0,
+ quin_tdm_rx_0_mixer_controls,
+ ARRAY_SIZE(quin_tdm_rx_0_mixer_controls)),
+ SND_SOC_DAPM_MIXER("QUIN_TDM_RX_1 Audio Mixer", SND_SOC_NOPM, 0, 0,
+ quin_tdm_rx_1_mixer_controls,
+ ARRAY_SIZE(quin_tdm_rx_1_mixer_controls)),
+ SND_SOC_DAPM_MIXER("QUIN_TDM_RX_2 Audio Mixer", SND_SOC_NOPM, 0, 0,
+ quin_tdm_rx_2_mixer_controls,
+ ARRAY_SIZE(quin_tdm_rx_2_mixer_controls)),
+ SND_SOC_DAPM_MIXER("QUIN_TDM_RX_3 Audio Mixer", SND_SOC_NOPM, 0, 0,
+ quin_tdm_rx_3_mixer_controls,
+ ARRAY_SIZE(quin_tdm_rx_3_mixer_controls)),
+ SND_SOC_DAPM_MIXER("QUIN_TDM_RX_4 Audio Mixer", SND_SOC_NOPM, 0, 0,
+ quin_tdm_rx_4_mixer_controls,
+ ARRAY_SIZE(quin_tdm_rx_4_mixer_controls)),
+ SND_SOC_DAPM_MIXER("QUIN_TDM_RX_5 Audio Mixer", SND_SOC_NOPM, 0, 0,
+ quin_tdm_rx_5_mixer_controls,
+ ARRAY_SIZE(quin_tdm_rx_5_mixer_controls)),
+ SND_SOC_DAPM_MIXER("QUIN_TDM_RX_6 Audio Mixer", SND_SOC_NOPM, 0, 0,
+ quin_tdm_rx_6_mixer_controls,
+ ARRAY_SIZE(quin_tdm_rx_6_mixer_controls)),
+ SND_SOC_DAPM_MIXER("QUIN_TDM_RX_7 Audio Mixer", SND_SOC_NOPM, 0, 0,
+ quin_tdm_rx_7_mixer_controls,
+ ARRAY_SIZE(quin_tdm_rx_7_mixer_controls)),
SND_SOC_DAPM_MIXER("MultiMedia1 Mixer", SND_SOC_NOPM, 0, 0,
mmul1_mixer_controls, ARRAY_SIZE(mmul1_mixer_controls)),
SND_SOC_DAPM_MIXER("MultiMedia2 Mixer", SND_SOC_NOPM, 0, 0,
@@ -412,6 +817,54 @@ static const struct snd_soc_dapm_route intercon[] = {
Q6ROUTING_RX_DAPM_ROUTE("TERT_MI2S_RX Audio Mixer", "TERT_MI2S_RX"),
Q6ROUTING_RX_DAPM_ROUTE("SEC_MI2S_RX Audio Mixer", "SEC_MI2S_RX"),
Q6ROUTING_RX_DAPM_ROUTE("PRI_MI2S_RX Audio Mixer", "PRI_MI2S_RX"),
+ Q6ROUTING_RX_DAPM_ROUTE("PRIMARY_TDM_RX_0 Audio Mixer",
+ "PRIMARY_TDM_RX_0"),
+ Q6ROUTING_RX_DAPM_ROUTE("PRIMARY_TDM_RX_1 Audio Mixer",
+ "PRIMARY_TDM_RX_1"),
+ Q6ROUTING_RX_DAPM_ROUTE("PRIMARY_TDM_RX_2 Audio Mixer",
+ "PRIMARY_TDM_RX_2"),
+ Q6ROUTING_RX_DAPM_ROUTE("PRIMARY_TDM_RX_3 Audio Mixer",
+ "PRIMARY_TDM_RX_3"),
+ Q6ROUTING_RX_DAPM_ROUTE("PRIMARY_TDM_RX_4 Audio Mixer",
+ "PRIMARY_TDM_RX_4"),
+ Q6ROUTING_RX_DAPM_ROUTE("PRIMARY_TDM_RX_5 Audio Mixer",
+ "PRIMARY_TDM_RX_5"),
+ Q6ROUTING_RX_DAPM_ROUTE("PRIMARY_TDM_RX_6 Audio Mixer",
+ "PRIMARY_TDM_RX_6"),
+ Q6ROUTING_RX_DAPM_ROUTE("PRIMARY_TDM_RX_7 Audio Mixer",
+ "PRIMARY_TDM_RX_7"),
+ Q6ROUTING_RX_DAPM_ROUTE("SEC_TDM_RX_0 Audio Mixer", "SEC_TDM_RX_0"),
+ Q6ROUTING_RX_DAPM_ROUTE("SEC_TDM_RX_1 Audio Mixer", "SEC_TDM_RX_1"),
+ Q6ROUTING_RX_DAPM_ROUTE("SEC_TDM_RX_2 Audio Mixer", "SEC_TDM_RX_2"),
+ Q6ROUTING_RX_DAPM_ROUTE("SEC_TDM_RX_3 Audio Mixer", "SEC_TDM_RX_3"),
+ Q6ROUTING_RX_DAPM_ROUTE("SEC_TDM_RX_4 Audio Mixer", "SEC_TDM_RX_4"),
+ Q6ROUTING_RX_DAPM_ROUTE("SEC_TDM_RX_5 Audio Mixer", "SEC_TDM_RX_5"),
+ Q6ROUTING_RX_DAPM_ROUTE("SEC_TDM_RX_6 Audio Mixer", "SEC_TDM_RX_6"),
+ Q6ROUTING_RX_DAPM_ROUTE("SEC_TDM_RX_7 Audio Mixer", "SEC_TDM_RX_7"),
+ Q6ROUTING_RX_DAPM_ROUTE("TERT_TDM_RX_0 Audio Mixer", "TERT_TDM_RX_0"),
+ Q6ROUTING_RX_DAPM_ROUTE("TERT_TDM_RX_1 Audio Mixer", "TERT_TDM_RX_1"),
+ Q6ROUTING_RX_DAPM_ROUTE("TERT_TDM_RX_2 Audio Mixer", "TERT_TDM_RX_2"),
+ Q6ROUTING_RX_DAPM_ROUTE("TERT_TDM_RX_3 Audio Mixer", "TERT_TDM_RX_3"),
+ Q6ROUTING_RX_DAPM_ROUTE("TERT_TDM_RX_4 Audio Mixer", "TERT_TDM_RX_4"),
+ Q6ROUTING_RX_DAPM_ROUTE("TERT_TDM_RX_5 Audio Mixer", "TERT_TDM_RX_5"),
+ Q6ROUTING_RX_DAPM_ROUTE("TERT_TDM_RX_6 Audio Mixer", "TERT_TDM_RX_6"),
+ Q6ROUTING_RX_DAPM_ROUTE("TERT_TDM_RX_7 Audio Mixer", "TERT_TDM_RX_7"),
+ Q6ROUTING_RX_DAPM_ROUTE("QUAT_TDM_RX_0 Audio Mixer", "QUAT_TDM_RX_0"),
+ Q6ROUTING_RX_DAPM_ROUTE("QUAT_TDM_RX_1 Audio Mixer", "QUAT_TDM_RX_1"),
+ Q6ROUTING_RX_DAPM_ROUTE("QUAT_TDM_RX_2 Audio Mixer", "QUAT_TDM_RX_2"),
+ Q6ROUTING_RX_DAPM_ROUTE("QUAT_TDM_RX_3 Audio Mixer", "QUAT_TDM_RX_3"),
+ Q6ROUTING_RX_DAPM_ROUTE("QUAT_TDM_RX_4 Audio Mixer", "QUAT_TDM_RX_4"),
+ Q6ROUTING_RX_DAPM_ROUTE("QUAT_TDM_RX_5 Audio Mixer", "QUAT_TDM_RX_5"),
+ Q6ROUTING_RX_DAPM_ROUTE("QUAT_TDM_RX_6 Audio Mixer", "QUAT_TDM_RX_6"),
+ Q6ROUTING_RX_DAPM_ROUTE("QUAT_TDM_RX_7 Audio Mixer", "QUAT_TDM_RX_7"),
+ Q6ROUTING_RX_DAPM_ROUTE("QUIN_TDM_RX_0 Audio Mixer", "QUIN_TDM_RX_0"),
+ Q6ROUTING_RX_DAPM_ROUTE("QUIN_TDM_RX_1 Audio Mixer", "QUIN_TDM_RX_1"),
+ Q6ROUTING_RX_DAPM_ROUTE("QUIN_TDM_RX_2 Audio Mixer", "QUIN_TDM_RX_2"),
+ Q6ROUTING_RX_DAPM_ROUTE("QUIN_TDM_RX_3 Audio Mixer", "QUIN_TDM_RX_3"),
+ Q6ROUTING_RX_DAPM_ROUTE("QUIN_TDM_RX_4 Audio Mixer", "QUIN_TDM_RX_4"),
+ Q6ROUTING_RX_DAPM_ROUTE("QUIN_TDM_RX_5 Audio Mixer", "QUIN_TDM_RX_5"),
+ Q6ROUTING_RX_DAPM_ROUTE("QUIN_TDM_RX_6 Audio Mixer", "QUIN_TDM_RX_6"),
+ Q6ROUTING_RX_DAPM_ROUTE("QUIN_TDM_RX_7 Audio Mixer", "QUIN_TDM_RX_7"),
Q6ROUTING_TX_DAPM_ROUTE("MultiMedia1 Mixer"),
Q6ROUTING_TX_DAPM_ROUTE("MultiMedia2 Mixer"),
Q6ROUTING_TX_DAPM_ROUTE("MultiMedia3 Mixer"),
--
2.16.2
^ permalink raw reply related
* [PATCH 5/6] ASoC: qdsp6: q6routing: Add macros for mixers
From: Srinivas Kandagatla @ 2018-05-29 10:18 UTC (permalink / raw)
To: broonie, linux-arm-msm, alsa-devel, robh+dt, bgoswami
Cc: mark.rutland, lgirdwood, plai, tiwai, perex, devicetree,
linux-kernel, linux-arm-kernel, rohkumar, spatakok,
Srinivas Kandagatla
In-Reply-To: <20180529101833.30489-1-srinivas.kandagatla@linaro.org>
All the mixer controls are pretty much same from all the afe ports.
Make these as proper macros for 2 reasons.
1> To avoid any typos in adding new mixer controls for each port.
2> Easy to edit from single place, easy to add new ports
This also prepares the routing driver to accomdate 40 tdm dais.
Signed-off-by: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
---
sound/soc/qcom/qdsp6/q6routing.c | 631 ++++++---------------------------------
1 file changed, 97 insertions(+), 534 deletions(-)
diff --git a/sound/soc/qcom/qdsp6/q6routing.c b/sound/soc/qcom/qdsp6/q6routing.c
index 08c25c26adf4..a4e74cac491b 100644
--- a/sound/soc/qcom/qdsp6/q6routing.c
+++ b/sound/soc/qcom/qdsp6/q6routing.c
@@ -26,6 +26,63 @@
#define DRV_NAME "q6routing-component"
+#define Q6ROUTING_RX_MIXERS(id) \
+ SOC_SINGLE_EXT("MultiMedia1", id, \
+ MSM_FRONTEND_DAI_MULTIMEDIA1, 1, 0, msm_routing_get_audio_mixer,\
+ msm_routing_put_audio_mixer), \
+ SOC_SINGLE_EXT("MultiMedia2", id, \
+ MSM_FRONTEND_DAI_MULTIMEDIA2, 1, 0, msm_routing_get_audio_mixer,\
+ msm_routing_put_audio_mixer), \
+ SOC_SINGLE_EXT("MultiMedia3", id, \
+ MSM_FRONTEND_DAI_MULTIMEDIA3, 1, 0, msm_routing_get_audio_mixer,\
+ msm_routing_put_audio_mixer), \
+ SOC_SINGLE_EXT("MultiMedia4", id, \
+ MSM_FRONTEND_DAI_MULTIMEDIA4, 1, 0, msm_routing_get_audio_mixer,\
+ msm_routing_put_audio_mixer), \
+ SOC_SINGLE_EXT("MultiMedia5", id, \
+ MSM_FRONTEND_DAI_MULTIMEDIA5, 1, 0, msm_routing_get_audio_mixer,\
+ msm_routing_put_audio_mixer), \
+ SOC_SINGLE_EXT("MultiMedia6", id, \
+ MSM_FRONTEND_DAI_MULTIMEDIA6, 1, 0, msm_routing_get_audio_mixer,\
+ msm_routing_put_audio_mixer), \
+ SOC_SINGLE_EXT("MultiMedia7", id, \
+ MSM_FRONTEND_DAI_MULTIMEDIA7, 1, 0, msm_routing_get_audio_mixer,\
+ msm_routing_put_audio_mixer), \
+ SOC_SINGLE_EXT("MultiMedia8", id, \
+ MSM_FRONTEND_DAI_MULTIMEDIA8, 1, 0, msm_routing_get_audio_mixer,\
+ msm_routing_put_audio_mixer),
+
+#define Q6ROUTING_RX_DAPM_ROUTE(mix_name, s) \
+ { mix_name, "MultiMedia1", "MM_DL1" }, \
+ { mix_name, "MultiMedia2", "MM_DL2" }, \
+ { mix_name, "MultiMedia3", "MM_DL3" }, \
+ { mix_name, "MultiMedia4", "MM_DL4" }, \
+ { mix_name, "MultiMedia5", "MM_DL5" }, \
+ { mix_name, "MultiMedia6", "MM_DL6" }, \
+ { mix_name, "MultiMedia7", "MM_DL7" }, \
+ { mix_name, "MultiMedia8", "MM_DL8" }, \
+ { s, NULL, mix_name }
+
+#define Q6ROUTING_TX_DAPM_ROUTE(mix_name) \
+ { mix_name, "PRI_MI2S_TX", "PRI_MI2S_TX" }, \
+ { mix_name, "SEC_MI2S_TX", "SEC_MI2S_TX" }, \
+ { mix_name, "QUAT_MI2S_TX", "QUAT_MI2S_TX" }, \
+ { mix_name, "TERT_MI2S_TX", "TERT_MI2S_TX" }
+
+#define Q6ROUTING_TX_MIXERS(id) \
+ SOC_SINGLE_EXT("PRI_MI2S_TX", PRIMARY_MI2S_TX, \
+ id, 1, 0, msm_routing_get_audio_mixer, \
+ msm_routing_put_audio_mixer), \
+ SOC_SINGLE_EXT("SEC_MI2S_TX", SECONDARY_MI2S_TX, \
+ id, 1, 0, msm_routing_get_audio_mixer, \
+ msm_routing_put_audio_mixer), \
+ SOC_SINGLE_EXT("TERT_MI2S_TX", TERTIARY_MI2S_TX, \
+ id, 1, 0, msm_routing_get_audio_mixer, \
+ msm_routing_put_audio_mixer), \
+ SOC_SINGLE_EXT("QUAT_MI2S_TX", QUATERNARY_MI2S_TX, \
+ id, 1, 0, msm_routing_get_audio_mixer, \
+ msm_routing_put_audio_mixer),
+
struct session_data {
int state;
int port_id;
@@ -207,430 +264,64 @@ static int msm_routing_put_audio_mixer(struct snd_kcontrol *kcontrol,
}
static const struct snd_kcontrol_new hdmi_mixer_controls[] = {
- SOC_SINGLE_EXT("MultiMedia1", HDMI_RX,
- MSM_FRONTEND_DAI_MULTIMEDIA1, 1, 0,
- msm_routing_get_audio_mixer,
- msm_routing_put_audio_mixer),
- SOC_SINGLE_EXT("MultiMedia2", HDMI_RX,
- MSM_FRONTEND_DAI_MULTIMEDIA2, 1, 0,
- msm_routing_get_audio_mixer,
- msm_routing_put_audio_mixer),
- SOC_SINGLE_EXT("MultiMedia3", HDMI_RX,
- MSM_FRONTEND_DAI_MULTIMEDIA3, 1, 0,
- msm_routing_get_audio_mixer,
- msm_routing_put_audio_mixer),
- SOC_SINGLE_EXT("MultiMedia4", HDMI_RX,
- MSM_FRONTEND_DAI_MULTIMEDIA4, 1, 0,
- msm_routing_get_audio_mixer,
- msm_routing_put_audio_mixer),
- SOC_SINGLE_EXT("MultiMedia5", HDMI_RX,
- MSM_FRONTEND_DAI_MULTIMEDIA5, 1, 0,
- msm_routing_get_audio_mixer,
- msm_routing_put_audio_mixer),
- SOC_SINGLE_EXT("MultiMedia6", HDMI_RX,
- MSM_FRONTEND_DAI_MULTIMEDIA6, 1, 0,
- msm_routing_get_audio_mixer,
- msm_routing_put_audio_mixer),
- SOC_SINGLE_EXT("MultiMedia7", HDMI_RX,
- MSM_FRONTEND_DAI_MULTIMEDIA7, 1, 0,
- msm_routing_get_audio_mixer,
- msm_routing_put_audio_mixer),
- SOC_SINGLE_EXT("MultiMedia8", HDMI_RX,
- MSM_FRONTEND_DAI_MULTIMEDIA8, 1, 0,
- msm_routing_get_audio_mixer,
- msm_routing_put_audio_mixer),
-};
+ Q6ROUTING_RX_MIXERS(HDMI_RX) };
static const struct snd_kcontrol_new primary_mi2s_rx_mixer_controls[] = {
- SOC_SINGLE_EXT("MultiMedia1", PRIMARY_MI2S_RX,
- MSM_FRONTEND_DAI_MULTIMEDIA1, 1, 0, msm_routing_get_audio_mixer,
- msm_routing_put_audio_mixer),
- SOC_SINGLE_EXT("MultiMedia2", PRIMARY_MI2S_RX,
- MSM_FRONTEND_DAI_MULTIMEDIA2, 1, 0, msm_routing_get_audio_mixer,
- msm_routing_put_audio_mixer),
- SOC_SINGLE_EXT("MultiMedia3", PRIMARY_MI2S_RX,
- MSM_FRONTEND_DAI_MULTIMEDIA3, 1, 0, msm_routing_get_audio_mixer,
- msm_routing_put_audio_mixer),
- SOC_SINGLE_EXT("MultiMedia4", PRIMARY_MI2S_RX,
- MSM_FRONTEND_DAI_MULTIMEDIA4, 1, 0, msm_routing_get_audio_mixer,
- msm_routing_put_audio_mixer),
- SOC_SINGLE_EXT("MultiMedia5", PRIMARY_MI2S_RX,
- MSM_FRONTEND_DAI_MULTIMEDIA5, 1, 0, msm_routing_get_audio_mixer,
- msm_routing_put_audio_mixer),
- SOC_SINGLE_EXT("MultiMedia6", PRIMARY_MI2S_RX,
- MSM_FRONTEND_DAI_MULTIMEDIA6, 1, 0, msm_routing_get_audio_mixer,
- msm_routing_put_audio_mixer),
- SOC_SINGLE_EXT("MultiMedia7", PRIMARY_MI2S_RX,
- MSM_FRONTEND_DAI_MULTIMEDIA7, 1, 0, msm_routing_get_audio_mixer,
- msm_routing_put_audio_mixer),
- SOC_SINGLE_EXT("MultiMedia8", PRIMARY_MI2S_RX,
- MSM_FRONTEND_DAI_MULTIMEDIA8, 1, 0, msm_routing_get_audio_mixer,
- msm_routing_put_audio_mixer),
-};
+ Q6ROUTING_RX_MIXERS(PRIMARY_MI2S_RX) };
static const struct snd_kcontrol_new secondary_mi2s_rx_mixer_controls[] = {
- SOC_SINGLE_EXT("MultiMedia1", SECONDARY_MI2S_RX,
- MSM_FRONTEND_DAI_MULTIMEDIA1, 1, 0, msm_routing_get_audio_mixer,
- msm_routing_put_audio_mixer),
- SOC_SINGLE_EXT("MultiMedia2", SECONDARY_MI2S_RX,
- MSM_FRONTEND_DAI_MULTIMEDIA2, 1, 0, msm_routing_get_audio_mixer,
- msm_routing_put_audio_mixer),
- SOC_SINGLE_EXT("MultiMedia3", SECONDARY_MI2S_RX,
- MSM_FRONTEND_DAI_MULTIMEDIA3, 1, 0, msm_routing_get_audio_mixer,
- msm_routing_put_audio_mixer),
- SOC_SINGLE_EXT("MultiMedia4", SECONDARY_MI2S_RX,
- MSM_FRONTEND_DAI_MULTIMEDIA4, 1, 0, msm_routing_get_audio_mixer,
- msm_routing_put_audio_mixer),
- SOC_SINGLE_EXT("MultiMedia5", SECONDARY_MI2S_RX,
- MSM_FRONTEND_DAI_MULTIMEDIA5, 1, 0, msm_routing_get_audio_mixer,
- msm_routing_put_audio_mixer),
- SOC_SINGLE_EXT("MultiMedia6", SECONDARY_MI2S_RX,
- MSM_FRONTEND_DAI_MULTIMEDIA6, 1, 0, msm_routing_get_audio_mixer,
- msm_routing_put_audio_mixer),
- SOC_SINGLE_EXT("MultiMedia7", SECONDARY_MI2S_RX,
- MSM_FRONTEND_DAI_MULTIMEDIA7, 1, 0, msm_routing_get_audio_mixer,
- msm_routing_put_audio_mixer),
- SOC_SINGLE_EXT("MultiMedia8", SECONDARY_MI2S_RX,
- MSM_FRONTEND_DAI_MULTIMEDIA8, 1, 0, msm_routing_get_audio_mixer,
- msm_routing_put_audio_mixer),
-};
+ Q6ROUTING_RX_MIXERS(SECONDARY_MI2S_RX) };
static const struct snd_kcontrol_new quaternary_mi2s_rx_mixer_controls[] = {
- SOC_SINGLE_EXT("MultiMedia1", QUATERNARY_MI2S_RX,
- MSM_FRONTEND_DAI_MULTIMEDIA1, 1, 0, msm_routing_get_audio_mixer,
- msm_routing_put_audio_mixer),
- SOC_SINGLE_EXT("MultiMedia2", QUATERNARY_MI2S_RX,
- MSM_FRONTEND_DAI_MULTIMEDIA2, 1, 0, msm_routing_get_audio_mixer,
- msm_routing_put_audio_mixer),
- SOC_SINGLE_EXT("MultiMedia3", QUATERNARY_MI2S_RX,
- MSM_FRONTEND_DAI_MULTIMEDIA3, 1, 0, msm_routing_get_audio_mixer,
- msm_routing_put_audio_mixer),
- SOC_SINGLE_EXT("MultiMedia4", QUATERNARY_MI2S_RX,
- MSM_FRONTEND_DAI_MULTIMEDIA4, 1, 0, msm_routing_get_audio_mixer,
- msm_routing_put_audio_mixer),
- SOC_SINGLE_EXT("MultiMedia5", QUATERNARY_MI2S_RX,
- MSM_FRONTEND_DAI_MULTIMEDIA5, 1, 0, msm_routing_get_audio_mixer,
- msm_routing_put_audio_mixer),
- SOC_SINGLE_EXT("MultiMedia6", QUATERNARY_MI2S_RX,
- MSM_FRONTEND_DAI_MULTIMEDIA6, 1, 0, msm_routing_get_audio_mixer,
- msm_routing_put_audio_mixer),
- SOC_SINGLE_EXT("MultiMedia7", QUATERNARY_MI2S_RX,
- MSM_FRONTEND_DAI_MULTIMEDIA7, 1, 0, msm_routing_get_audio_mixer,
- msm_routing_put_audio_mixer),
- SOC_SINGLE_EXT("MultiMedia8", QUATERNARY_MI2S_RX,
- MSM_FRONTEND_DAI_MULTIMEDIA8, 1, 0, msm_routing_get_audio_mixer,
- msm_routing_put_audio_mixer),
-};
+ Q6ROUTING_RX_MIXERS(QUATERNARY_MI2S_RX) };
static const struct snd_kcontrol_new tertiary_mi2s_rx_mixer_controls[] = {
- SOC_SINGLE_EXT("MultiMedia1", TERTIARY_MI2S_RX,
- MSM_FRONTEND_DAI_MULTIMEDIA1, 1, 0, msm_routing_get_audio_mixer,
- msm_routing_put_audio_mixer),
- SOC_SINGLE_EXT("MultiMedia2", TERTIARY_MI2S_RX,
- MSM_FRONTEND_DAI_MULTIMEDIA2, 1, 0, msm_routing_get_audio_mixer,
- msm_routing_put_audio_mixer),
- SOC_SINGLE_EXT("MultiMedia3", TERTIARY_MI2S_RX,
- MSM_FRONTEND_DAI_MULTIMEDIA3, 1, 0, msm_routing_get_audio_mixer,
- msm_routing_put_audio_mixer),
- SOC_SINGLE_EXT("MultiMedia4", TERTIARY_MI2S_RX,
- MSM_FRONTEND_DAI_MULTIMEDIA4, 1, 0, msm_routing_get_audio_mixer,
- msm_routing_put_audio_mixer),
-};
-
+ Q6ROUTING_RX_MIXERS(TERTIARY_MI2S_RX) };
static const struct snd_kcontrol_new slimbus_rx_mixer_controls[] = {
- SOC_SINGLE_EXT("MultiMedia1", SLIMBUS_0_RX,
- MSM_FRONTEND_DAI_MULTIMEDIA1, 1, 0, msm_routing_get_audio_mixer,
- msm_routing_put_audio_mixer),
- SOC_SINGLE_EXT("MultiMedia2", SLIMBUS_0_RX,
- MSM_FRONTEND_DAI_MULTIMEDIA2, 1, 0, msm_routing_get_audio_mixer,
- msm_routing_put_audio_mixer),
- SOC_SINGLE_EXT("MultiMedia3", SLIMBUS_0_RX,
- MSM_FRONTEND_DAI_MULTIMEDIA3, 1, 0, msm_routing_get_audio_mixer,
- msm_routing_put_audio_mixer),
- SOC_SINGLE_EXT("MultiMedia4", SLIMBUS_0_RX,
- MSM_FRONTEND_DAI_MULTIMEDIA4, 1, 0, msm_routing_get_audio_mixer,
- msm_routing_put_audio_mixer),
- SOC_SINGLE_EXT("MultiMedia5", SLIMBUS_0_RX,
- MSM_FRONTEND_DAI_MULTIMEDIA5, 1, 0, msm_routing_get_audio_mixer,
- msm_routing_put_audio_mixer),
- SOC_SINGLE_EXT("MultiMedia6", SLIMBUS_0_RX,
- MSM_FRONTEND_DAI_MULTIMEDIA6, 1, 0, msm_routing_get_audio_mixer,
- msm_routing_put_audio_mixer),
- SOC_SINGLE_EXT("MultiMedia7", SLIMBUS_0_RX,
- MSM_FRONTEND_DAI_MULTIMEDIA7, 1, 0, msm_routing_get_audio_mixer,
- msm_routing_put_audio_mixer),
- SOC_SINGLE_EXT("MultiMedia8", SLIMBUS_0_RX,
- MSM_FRONTEND_DAI_MULTIMEDIA8, 1, 0, msm_routing_get_audio_mixer,
- msm_routing_put_audio_mixer),
-};
+ Q6ROUTING_RX_MIXERS(SLIMBUS_0_RX) };
static const struct snd_kcontrol_new slimbus_1_rx_mixer_controls[] = {
- SOC_SINGLE_EXT("MultiMedia1", SLIMBUS_1_RX,
- MSM_FRONTEND_DAI_MULTIMEDIA1, 1, 0, msm_routing_get_audio_mixer,
- msm_routing_put_audio_mixer),
- SOC_SINGLE_EXT("MultiMedia2", SLIMBUS_1_RX,
- MSM_FRONTEND_DAI_MULTIMEDIA2, 1, 0, msm_routing_get_audio_mixer,
- msm_routing_put_audio_mixer),
- SOC_SINGLE_EXT("MultiMedia3", SLIMBUS_1_RX,
- MSM_FRONTEND_DAI_MULTIMEDIA3, 1, 0, msm_routing_get_audio_mixer,
- msm_routing_put_audio_mixer),
- SOC_SINGLE_EXT("MultiMedia4", SLIMBUS_1_RX,
- MSM_FRONTEND_DAI_MULTIMEDIA4, 1, 0, msm_routing_get_audio_mixer,
- msm_routing_put_audio_mixer),
- SOC_SINGLE_EXT("MultiMedia5", SLIMBUS_1_RX,
- MSM_FRONTEND_DAI_MULTIMEDIA5, 1, 0, msm_routing_get_audio_mixer,
- msm_routing_put_audio_mixer),
- SOC_SINGLE_EXT("MultiMedia6", SLIMBUS_1_RX,
- MSM_FRONTEND_DAI_MULTIMEDIA6, 1, 0, msm_routing_get_audio_mixer,
- msm_routing_put_audio_mixer),
- SOC_SINGLE_EXT("MultiMedia7", SLIMBUS_1_RX,
- MSM_FRONTEND_DAI_MULTIMEDIA7, 1, 0, msm_routing_get_audio_mixer,
- msm_routing_put_audio_mixer),
- SOC_SINGLE_EXT("MultiMedia8", SLIMBUS_1_RX,
- MSM_FRONTEND_DAI_MULTIMEDIA8, 1, 0, msm_routing_get_audio_mixer,
- msm_routing_put_audio_mixer),
-};
+ Q6ROUTING_RX_MIXERS(SLIMBUS_1_RX) };
static const struct snd_kcontrol_new slimbus_2_rx_mixer_controls[] = {
- SOC_SINGLE_EXT("MultiMedia1", SLIMBUS_2_RX,
- MSM_FRONTEND_DAI_MULTIMEDIA1, 1, 0, msm_routing_get_audio_mixer,
- msm_routing_put_audio_mixer),
- SOC_SINGLE_EXT("MultiMedia2", SLIMBUS_2_RX,
- MSM_FRONTEND_DAI_MULTIMEDIA2, 1, 0, msm_routing_get_audio_mixer,
- msm_routing_put_audio_mixer),
- SOC_SINGLE_EXT("MultiMedia3", SLIMBUS_2_RX,
- MSM_FRONTEND_DAI_MULTIMEDIA3, 1, 0, msm_routing_get_audio_mixer,
- msm_routing_put_audio_mixer),
- SOC_SINGLE_EXT("MultiMedia4", SLIMBUS_2_RX,
- MSM_FRONTEND_DAI_MULTIMEDIA4, 1, 0, msm_routing_get_audio_mixer,
- msm_routing_put_audio_mixer),
- SOC_SINGLE_EXT("MultiMedia5", SLIMBUS_2_RX,
- MSM_FRONTEND_DAI_MULTIMEDIA5, 1, 0, msm_routing_get_audio_mixer,
- msm_routing_put_audio_mixer),
- SOC_SINGLE_EXT("MultiMedia6", SLIMBUS_2_RX,
- MSM_FRONTEND_DAI_MULTIMEDIA6, 1, 0, msm_routing_get_audio_mixer,
- msm_routing_put_audio_mixer),
- SOC_SINGLE_EXT("MultiMedia7", SLIMBUS_2_RX,
- MSM_FRONTEND_DAI_MULTIMEDIA7, 1, 0, msm_routing_get_audio_mixer,
- msm_routing_put_audio_mixer),
- SOC_SINGLE_EXT("MultiMedia8", SLIMBUS_2_RX,
- MSM_FRONTEND_DAI_MULTIMEDIA8, 1, 0, msm_routing_get_audio_mixer,
- msm_routing_put_audio_mixer),
-};
+ Q6ROUTING_RX_MIXERS(SLIMBUS_2_RX) };
static const struct snd_kcontrol_new slimbus_3_rx_mixer_controls[] = {
- SOC_SINGLE_EXT("MultiMedia1", SLIMBUS_3_RX,
- MSM_FRONTEND_DAI_MULTIMEDIA1, 1, 0, msm_routing_get_audio_mixer,
- msm_routing_put_audio_mixer),
- SOC_SINGLE_EXT("MultiMedia2", SLIMBUS_3_RX,
- MSM_FRONTEND_DAI_MULTIMEDIA2, 1, 0, msm_routing_get_audio_mixer,
- msm_routing_put_audio_mixer),
- SOC_SINGLE_EXT("MultiMedia3", SLIMBUS_3_RX,
- MSM_FRONTEND_DAI_MULTIMEDIA3, 1, 0, msm_routing_get_audio_mixer,
- msm_routing_put_audio_mixer),
- SOC_SINGLE_EXT("MultiMedia4", SLIMBUS_3_RX,
- MSM_FRONTEND_DAI_MULTIMEDIA4, 1, 0, msm_routing_get_audio_mixer,
- msm_routing_put_audio_mixer),
- SOC_SINGLE_EXT("MultiMedia5", SLIMBUS_3_RX,
- MSM_FRONTEND_DAI_MULTIMEDIA5, 1, 0, msm_routing_get_audio_mixer,
- msm_routing_put_audio_mixer),
- SOC_SINGLE_EXT("MultiMedia6", SLIMBUS_3_RX,
- MSM_FRONTEND_DAI_MULTIMEDIA6, 1, 0, msm_routing_get_audio_mixer,
- msm_routing_put_audio_mixer),
- SOC_SINGLE_EXT("MultiMedia7", SLIMBUS_3_RX,
- MSM_FRONTEND_DAI_MULTIMEDIA7, 1, 0, msm_routing_get_audio_mixer,
- msm_routing_put_audio_mixer),
- SOC_SINGLE_EXT("MultiMedia8", SLIMBUS_3_RX,
- MSM_FRONTEND_DAI_MULTIMEDIA8, 1, 0, msm_routing_get_audio_mixer,
- msm_routing_put_audio_mixer),
-};
+ Q6ROUTING_RX_MIXERS(SLIMBUS_3_RX) };
static const struct snd_kcontrol_new slimbus_4_rx_mixer_controls[] = {
- SOC_SINGLE_EXT("MultiMedia1", SLIMBUS_4_RX,
- MSM_FRONTEND_DAI_MULTIMEDIA1, 1, 0, msm_routing_get_audio_mixer,
- msm_routing_put_audio_mixer),
- SOC_SINGLE_EXT("MultiMedia2", SLIMBUS_4_RX,
- MSM_FRONTEND_DAI_MULTIMEDIA2, 1, 0, msm_routing_get_audio_mixer,
- msm_routing_put_audio_mixer),
- SOC_SINGLE_EXT("MultiMedia5", SLIMBUS_4_RX,
- MSM_FRONTEND_DAI_MULTIMEDIA5, 1, 0, msm_routing_get_audio_mixer,
- msm_routing_put_audio_mixer),
-};
+ Q6ROUTING_RX_MIXERS(SLIMBUS_4_RX) };
static const struct snd_kcontrol_new slimbus_5_rx_mixer_controls[] = {
- SOC_SINGLE_EXT("MultiMedia1", SLIMBUS_5_RX,
- MSM_FRONTEND_DAI_MULTIMEDIA1, 1, 0, msm_routing_get_audio_mixer,
- msm_routing_put_audio_mixer),
- SOC_SINGLE_EXT("MultiMedia2", SLIMBUS_5_RX,
- MSM_FRONTEND_DAI_MULTIMEDIA2, 1, 0, msm_routing_get_audio_mixer,
- msm_routing_put_audio_mixer),
- SOC_SINGLE_EXT("MultiMedia3", SLIMBUS_5_RX,
- MSM_FRONTEND_DAI_MULTIMEDIA3, 1, 0, msm_routing_get_audio_mixer,
- msm_routing_put_audio_mixer),
- SOC_SINGLE_EXT("MultiMedia4", SLIMBUS_5_RX,
- MSM_FRONTEND_DAI_MULTIMEDIA4, 1, 0, msm_routing_get_audio_mixer,
- msm_routing_put_audio_mixer),
- SOC_SINGLE_EXT("MultiMedia5", SLIMBUS_5_RX,
- MSM_FRONTEND_DAI_MULTIMEDIA5, 1, 0, msm_routing_get_audio_mixer,
- msm_routing_put_audio_mixer),
- SOC_SINGLE_EXT("MultiMedia6", SLIMBUS_5_RX,
- MSM_FRONTEND_DAI_MULTIMEDIA6, 1, 0, msm_routing_get_audio_mixer,
- msm_routing_put_audio_mixer),
- SOC_SINGLE_EXT("MultiMedia7", SLIMBUS_5_RX,
- MSM_FRONTEND_DAI_MULTIMEDIA7, 1, 0, msm_routing_get_audio_mixer,
- msm_routing_put_audio_mixer),
- SOC_SINGLE_EXT("MultiMedia8", SLIMBUS_5_RX,
- MSM_FRONTEND_DAI_MULTIMEDIA8, 1, 0, msm_routing_get_audio_mixer,
- msm_routing_put_audio_mixer),
-};
+ Q6ROUTING_RX_MIXERS(SLIMBUS_5_RX) };
static const struct snd_kcontrol_new slimbus_6_rx_mixer_controls[] = {
- SOC_SINGLE_EXT("MultiMedia1", SLIMBUS_6_RX,
- MSM_FRONTEND_DAI_MULTIMEDIA1, 1, 0, msm_routing_get_audio_mixer,
- msm_routing_put_audio_mixer),
- SOC_SINGLE_EXT("MultiMedia2", SLIMBUS_6_RX,
- MSM_FRONTEND_DAI_MULTIMEDIA2, 1, 0, msm_routing_get_audio_mixer,
- msm_routing_put_audio_mixer),
- SOC_SINGLE_EXT("MultiMedia3", SLIMBUS_6_RX,
- MSM_FRONTEND_DAI_MULTIMEDIA3, 1, 0, msm_routing_get_audio_mixer,
- msm_routing_put_audio_mixer),
- SOC_SINGLE_EXT("MultiMedia4", SLIMBUS_6_RX,
- MSM_FRONTEND_DAI_MULTIMEDIA4, 1, 0, msm_routing_get_audio_mixer,
- msm_routing_put_audio_mixer),
- SOC_SINGLE_EXT("MultiMedia5", SLIMBUS_6_RX,
- MSM_FRONTEND_DAI_MULTIMEDIA5, 1, 0, msm_routing_get_audio_mixer,
- msm_routing_put_audio_mixer),
- SOC_SINGLE_EXT("MultiMedia6", SLIMBUS_6_RX,
- MSM_FRONTEND_DAI_MULTIMEDIA6, 1, 0, msm_routing_get_audio_mixer,
- msm_routing_put_audio_mixer),
- SOC_SINGLE_EXT("MultiMedia7", SLIMBUS_6_RX,
- MSM_FRONTEND_DAI_MULTIMEDIA7, 1, 0, msm_routing_get_audio_mixer,
- msm_routing_put_audio_mixer),
- SOC_SINGLE_EXT("MultiMedia8", SLIMBUS_6_RX,
- MSM_FRONTEND_DAI_MULTIMEDIA8, 1, 0, msm_routing_get_audio_mixer,
- msm_routing_put_audio_mixer),
-};
+ Q6ROUTING_RX_MIXERS(SLIMBUS_6_RX) };
static const struct snd_kcontrol_new mmul1_mixer_controls[] = {
- SOC_SINGLE_EXT("PRI_MI2S_TX", PRIMARY_MI2S_TX,
- MSM_FRONTEND_DAI_MULTIMEDIA1, 1, 0, msm_routing_get_audio_mixer,
- msm_routing_put_audio_mixer),
- SOC_SINGLE_EXT("QUAT_MI2S_TX", QUATERNARY_MI2S_TX,
- MSM_FRONTEND_DAI_MULTIMEDIA1, 1, 0, msm_routing_get_audio_mixer,
- msm_routing_put_audio_mixer),
- SOC_SINGLE_EXT("TERT_MI2S_TX", TERTIARY_MI2S_TX,
- MSM_FRONTEND_DAI_MULTIMEDIA1, 1, 0, msm_routing_get_audio_mixer,
- msm_routing_put_audio_mixer),
- SOC_SINGLE_EXT("SEC_MI2S_TX", SECONDARY_MI2S_TX,
- MSM_FRONTEND_DAI_MULTIMEDIA1, 1, 0, msm_routing_get_audio_mixer,
- msm_routing_put_audio_mixer),
-};
+ Q6ROUTING_TX_MIXERS(MSM_FRONTEND_DAI_MULTIMEDIA1) };
static const struct snd_kcontrol_new mmul2_mixer_controls[] = {
- SOC_SINGLE_EXT("PRI_MI2S_TX", PRIMARY_MI2S_TX,
- MSM_FRONTEND_DAI_MULTIMEDIA2, 1, 0, msm_routing_get_audio_mixer,
- msm_routing_put_audio_mixer),
- SOC_SINGLE_EXT("QUAT_MI2S_TX", QUATERNARY_MI2S_TX,
- MSM_FRONTEND_DAI_MULTIMEDIA2, 1, 0, msm_routing_get_audio_mixer,
- msm_routing_put_audio_mixer),
- SOC_SINGLE_EXT("TERT_MI2S_TX", TERTIARY_MI2S_TX,
- MSM_FRONTEND_DAI_MULTIMEDIA2, 1, 0, msm_routing_get_audio_mixer,
- msm_routing_put_audio_mixer),
- SOC_SINGLE_EXT("SEC_MI2S_TX", SECONDARY_MI2S_TX,
- MSM_FRONTEND_DAI_MULTIMEDIA2, 1, 0, msm_routing_get_audio_mixer,
- msm_routing_put_audio_mixer),
-};
+ Q6ROUTING_TX_MIXERS(MSM_FRONTEND_DAI_MULTIMEDIA2) };
static const struct snd_kcontrol_new mmul3_mixer_controls[] = {
- SOC_SINGLE_EXT("PRI_MI2S_TX", PRIMARY_MI2S_TX,
- MSM_FRONTEND_DAI_MULTIMEDIA3, 1, 0, msm_routing_get_audio_mixer,
- msm_routing_put_audio_mixer),
- SOC_SINGLE_EXT("QUAT_MI2S_TX", QUATERNARY_MI2S_TX,
- MSM_FRONTEND_DAI_MULTIMEDIA3, 1, 0, msm_routing_get_audio_mixer,
- msm_routing_put_audio_mixer),
- SOC_SINGLE_EXT("TERT_MI2S_TX", TERTIARY_MI2S_TX,
- MSM_FRONTEND_DAI_MULTIMEDIA3, 1, 0, msm_routing_get_audio_mixer,
- msm_routing_put_audio_mixer),
- SOC_SINGLE_EXT("SEC_MI2S_TX", SECONDARY_MI2S_TX,
- MSM_FRONTEND_DAI_MULTIMEDIA3, 1, 0, msm_routing_get_audio_mixer,
- msm_routing_put_audio_mixer),
-};
+ Q6ROUTING_TX_MIXERS(MSM_FRONTEND_DAI_MULTIMEDIA3) };
static const struct snd_kcontrol_new mmul4_mixer_controls[] = {
- SOC_SINGLE_EXT("PRI_MI2S_TX", PRIMARY_MI2S_TX,
- MSM_FRONTEND_DAI_MULTIMEDIA4, 1, 0, msm_routing_get_audio_mixer,
- msm_routing_put_audio_mixer),
- SOC_SINGLE_EXT("QUAT_MI2S_TX", QUATERNARY_MI2S_TX,
- MSM_FRONTEND_DAI_MULTIMEDIA4, 1, 0, msm_routing_get_audio_mixer,
- msm_routing_put_audio_mixer),
- SOC_SINGLE_EXT("TERT_MI2S_TX", TERTIARY_MI2S_TX,
- MSM_FRONTEND_DAI_MULTIMEDIA4, 1, 0, msm_routing_get_audio_mixer,
- msm_routing_put_audio_mixer),
- SOC_SINGLE_EXT("SEC_MI2S_TX", SECONDARY_MI2S_TX,
- MSM_FRONTEND_DAI_MULTIMEDIA4, 1, 0, msm_routing_get_audio_mixer,
- msm_routing_put_audio_mixer),
-};
+ Q6ROUTING_TX_MIXERS(MSM_FRONTEND_DAI_MULTIMEDIA4) };
static const struct snd_kcontrol_new mmul5_mixer_controls[] = {
- SOC_SINGLE_EXT("PRI_MI2S_TX", PRIMARY_MI2S_TX,
- MSM_FRONTEND_DAI_MULTIMEDIA5, 1, 0, msm_routing_get_audio_mixer,
- msm_routing_put_audio_mixer),
- SOC_SINGLE_EXT("QUAT_MI2S_TX", QUATERNARY_MI2S_TX,
- MSM_FRONTEND_DAI_MULTIMEDIA5, 1, 0, msm_routing_get_audio_mixer,
- msm_routing_put_audio_mixer),
- SOC_SINGLE_EXT("TERT_MI2S_TX", TERTIARY_MI2S_TX,
- MSM_FRONTEND_DAI_MULTIMEDIA5, 1, 0, msm_routing_get_audio_mixer,
- msm_routing_put_audio_mixer),
- SOC_SINGLE_EXT("SEC_MI2S_TX", SECONDARY_MI2S_TX,
- MSM_FRONTEND_DAI_MULTIMEDIA5, 1, 0, msm_routing_get_audio_mixer,
- msm_routing_put_audio_mixer),
-};
+ Q6ROUTING_TX_MIXERS(MSM_FRONTEND_DAI_MULTIMEDIA5) };
static const struct snd_kcontrol_new mmul6_mixer_controls[] = {
- SOC_SINGLE_EXT("PRI_MI2S_TX", PRIMARY_MI2S_TX,
- MSM_FRONTEND_DAI_MULTIMEDIA6, 1, 0, msm_routing_get_audio_mixer,
- msm_routing_put_audio_mixer),
- SOC_SINGLE_EXT("QUAT_MI2S_TX", QUATERNARY_MI2S_TX,
- MSM_FRONTEND_DAI_MULTIMEDIA6, 1, 0, msm_routing_get_audio_mixer,
- msm_routing_put_audio_mixer),
- SOC_SINGLE_EXT("TERT_MI2S_TX", TERTIARY_MI2S_TX,
- MSM_FRONTEND_DAI_MULTIMEDIA6, 1, 0, msm_routing_get_audio_mixer,
- msm_routing_put_audio_mixer),
- SOC_SINGLE_EXT("SEC_MI2S_TX", SECONDARY_MI2S_TX,
- MSM_FRONTEND_DAI_MULTIMEDIA6, 1, 0, msm_routing_get_audio_mixer,
- msm_routing_put_audio_mixer),
-};
+ Q6ROUTING_TX_MIXERS(MSM_FRONTEND_DAI_MULTIMEDIA6) };
static const struct snd_kcontrol_new mmul7_mixer_controls[] = {
- SOC_SINGLE_EXT("PRI_MI2S_TX", PRIMARY_MI2S_TX,
- MSM_FRONTEND_DAI_MULTIMEDIA7, 1, 0, msm_routing_get_audio_mixer,
- msm_routing_put_audio_mixer),
- SOC_SINGLE_EXT("QUAT_MI2S_TX", QUATERNARY_MI2S_TX,
- MSM_FRONTEND_DAI_MULTIMEDIA7, 1, 0, msm_routing_get_audio_mixer,
- msm_routing_put_audio_mixer),
- SOC_SINGLE_EXT("TERT_MI2S_TX", TERTIARY_MI2S_TX,
- MSM_FRONTEND_DAI_MULTIMEDIA7, 1, 0, msm_routing_get_audio_mixer,
- msm_routing_put_audio_mixer),
- SOC_SINGLE_EXT("SEC_MI2S_TX", SECONDARY_MI2S_TX,
- MSM_FRONTEND_DAI_MULTIMEDIA7, 1, 0, msm_routing_get_audio_mixer,
- msm_routing_put_audio_mixer),
-};
+ Q6ROUTING_TX_MIXERS(MSM_FRONTEND_DAI_MULTIMEDIA7) };
static const struct snd_kcontrol_new mmul8_mixer_controls[] = {
- SOC_SINGLE_EXT("PRI_MI2S_TX", PRIMARY_MI2S_TX,
- MSM_FRONTEND_DAI_MULTIMEDIA8, 1, 0, msm_routing_get_audio_mixer,
- msm_routing_put_audio_mixer),
- SOC_SINGLE_EXT("QUAT_MI2S_TX", QUATERNARY_MI2S_TX,
- MSM_FRONTEND_DAI_MULTIMEDIA8, 1, 0, msm_routing_get_audio_mixer,
- msm_routing_put_audio_mixer),
- SOC_SINGLE_EXT("TERT_MI2S_TX", TERTIARY_MI2S_TX,
- MSM_FRONTEND_DAI_MULTIMEDIA8, 1, 0, msm_routing_get_audio_mixer,
- msm_routing_put_audio_mixer),
- SOC_SINGLE_EXT("SEC_MI2S_TX", SECONDARY_MI2S_TX,
- MSM_FRONTEND_DAI_MULTIMEDIA8, 1, 0, msm_routing_get_audio_mixer,
- msm_routing_put_audio_mixer),
-};
+ Q6ROUTING_TX_MIXERS(MSM_FRONTEND_DAI_MULTIMEDIA8) };
static const struct snd_soc_dapm_widget msm_qdsp6_widgets[] = {
/* Frontend AIF */
@@ -709,154 +400,26 @@ static const struct snd_soc_dapm_widget msm_qdsp6_widgets[] = {
};
static const struct snd_soc_dapm_route intercon[] = {
- {"HDMI Mixer", "MultiMedia1", "MM_DL1"},
- {"HDMI Mixer", "MultiMedia2", "MM_DL2"},
- {"HDMI Mixer", "MultiMedia3", "MM_DL3"},
- {"HDMI Mixer", "MultiMedia4", "MM_DL4"},
- {"HDMI Mixer", "MultiMedia5", "MM_DL5"},
- {"HDMI Mixer", "MultiMedia6", "MM_DL6"},
- {"HDMI Mixer", "MultiMedia7", "MM_DL7"},
- {"HDMI Mixer", "MultiMedia8", "MM_DL8"},
- {"HDMI_RX", NULL, "HDMI Mixer"},
-
- {"SLIMBUS_0_RX Audio Mixer", "MultiMedia1", "MM_DL1"},
- {"SLIMBUS_0_RX Audio Mixer", "MultiMedia2", "MM_DL2"},
- {"SLIMBUS_0_RX Audio Mixer", "MultiMedia3", "MM_DL3"},
- {"SLIMBUS_0_RX Audio Mixer", "MultiMedia4", "MM_DL4"},
- {"SLIMBUS_0_RX Audio Mixer", "MultiMedia5", "MM_DL5"},
- {"SLIMBUS_0_RX Audio Mixer", "MultiMedia6", "MM_DL6"},
- {"SLIMBUS_0_RX Audio Mixer", "MultiMedia7", "MM_DL7"},
- {"SLIMBUS_0_RX Audio Mixer", "MultiMedia8", "MM_DL8"},
- {"SLIMBUS_0_RX", NULL, "SLIMBUS_0_RX Audio Mixer"},
-
- {"SLIMBUS_1_RX Audio Mixer", "MultiMedia1", "MM_DL1"},
- {"SLIMBUS_1_RX Audio Mixer", "MultiMedia2", "MM_DL2"},
- {"SLIMBUS_1_RX Audio Mixer", "MultiMedia3", "MM_DL3"},
- {"SLIMBUS_1_RX Audio Mixer", "MultiMedia4", "MM_DL4"},
- {"SLIMBUS_1_RX Audio Mixer", "MultiMedia5", "MM_DL5"},
- {"SLIMBUS_1_RX Audio Mixer", "MultiMedia6", "MM_DL6"},
- {"SLIMBUS_1_RX Audio Mixer", "MultiMedia7", "MM_DL7"},
- {"SLIMBUS_1_RX Audio Mixer", "MultiMedia8", "MM_DL8"},
- {"SLIMBUS_1_RX", NULL, "SLIMBUS_1_RX Audio Mixer"},
-
- {"SLIMBUS_2_RX Audio Mixer", "MultiMedia1", "MM_DL1"},
- {"SLIMBUS_2_RX Audio Mixer", "MultiMedia2", "MM_DL2"},
- {"SLIMBUS_2_RX Audio Mixer", "MultiMedia3", "MM_DL3"},
- {"SLIMBUS_2_RX Audio Mixer", "MultiMedia4", "MM_DL4"},
- {"SLIMBUS_2_RX Audio Mixer", "MultiMedia5", "MM_DL5"},
- {"SLIMBUS_2_RX Audio Mixer", "MultiMedia6", "MM_DL6"},
- {"SLIMBUS_2_RX Audio Mixer", "MultiMedia7", "MM_DL7"},
- {"SLIMBUS_2_RX Audio Mixer", "MultiMedia8", "MM_DL8"},
- {"SLIMBUS_2_RX", NULL, "SLIMBUS_2_RX Audio Mixer"},
-
- {"SLIMBUS_3_RX Audio Mixer", "MultiMedia1", "MM_DL1"},
- {"SLIMBUS_3_RX Audio Mixer", "MultiMedia2", "MM_DL2"},
- {"SLIMBUS_3_RX Audio Mixer", "MultiMedia3", "MM_DL3"},
- {"SLIMBUS_3_RX Audio Mixer", "MultiMedia4", "MM_DL4"},
- {"SLIMBUS_3_RX Audio Mixer", "MultiMedia5", "MM_DL5"},
- {"SLIMBUS_3_RX Audio Mixer", "MultiMedia6", "MM_DL6"},
- {"SLIMBUS_3_RX Audio Mixer", "MultiMedia7", "MM_DL7"},
- {"SLIMBUS_3_RX Audio Mixer", "MultiMedia8", "MM_DL8"},
- {"SLIMBUS_3_RX", NULL, "SLIMBUS_3_RX Audio Mixer"},
-
- {"SLIMBUS_4_RX Audio Mixer", "MultiMedia1", "MM_DL1"},
- {"SLIMBUS_4_RX Audio Mixer", "MultiMedia2", "MM_DL2"},
- {"SLIMBUS_4_RX Audio Mixer", "MultiMedia5", "MM_DL5"},
- {"SLIMBUS_4_RX", NULL, "SLIMBUS_4_RX Audio Mixer"},
-
- {"SLIMBUS_5_RX Audio Mixer", "MultiMedia1", "MM_DL1"},
- {"SLIMBUS_5_RX Audio Mixer", "MultiMedia2", "MM_DL2"},
- {"SLIMBUS_5_RX Audio Mixer", "MultiMedia3", "MM_DL3"},
- {"SLIMBUS_5_RX Audio Mixer", "MultiMedia4", "MM_DL4"},
- {"SLIMBUS_5_RX Audio Mixer", "MultiMedia5", "MM_DL5"},
- {"SLIMBUS_5_RX Audio Mixer", "MultiMedia6", "MM_DL6"},
- {"SLIMBUS_5_RX Audio Mixer", "MultiMedia7", "MM_DL7"},
- {"SLIMBUS_5_RX Audio Mixer", "MultiMedia8", "MM_DL8"},
- {"SLIMBUS_5_RX", NULL, "SLIMBUS_5_RX Audio Mixer"},
-
- {"SLIMBUS_6_RX Audio Mixer", "MultiMedia1", "MM_DL1"},
- {"SLIMBUS_6_RX Audio Mixer", "MultiMedia2", "MM_DL2"},
- {"SLIMBUS_6_RX Audio Mixer", "MultiMedia3", "MM_DL3"},
- {"SLIMBUS_6_RX Audio Mixer", "MultiMedia4", "MM_DL4"},
- {"SLIMBUS_6_RX Audio Mixer", "MultiMedia5", "MM_DL5"},
- {"SLIMBUS_6_RX Audio Mixer", "MultiMedia6", "MM_DL6"},
- {"SLIMBUS_6_RX Audio Mixer", "MultiMedia7", "MM_DL7"},
- {"SLIMBUS_6_RX Audio Mixer", "MultiMedia8", "MM_DL8"},
- {"SLIMBUS_6_RX", NULL, "SLIMBUS_6_RX Audio Mixer"},
-
- {"QUAT_MI2S_RX Audio Mixer", "MultiMedia1", "MM_DL1"},
- {"QUAT_MI2S_RX Audio Mixer", "MultiMedia2", "MM_DL2"},
- {"QUAT_MI2S_RX Audio Mixer", "MultiMedia3", "MM_DL3"},
- {"QUAT_MI2S_RX Audio Mixer", "MultiMedia4", "MM_DL4"},
- {"QUAT_MI2S_RX Audio Mixer", "MultiMedia5", "MM_DL5"},
- {"QUAT_MI2S_RX Audio Mixer", "MultiMedia6", "MM_DL6"},
- {"QUAT_MI2S_RX Audio Mixer", "MultiMedia7", "MM_DL7"},
- {"QUAT_MI2S_RX Audio Mixer", "MultiMedia8", "MM_DL8"},
- {"QUAT_MI2S_RX", NULL, "QUAT_MI2S_RX Audio Mixer"},
-
- {"TERT_MI2S_RX Audio Mixer", "MultiMedia1", "MM_DL1"},
- {"TERT_MI2S_RX Audio Mixer", "MultiMedia2", "MM_DL2"},
- {"TERT_MI2S_RX Audio Mixer", "MultiMedia3", "MM_DL3"},
- {"TERT_MI2S_RX Audio Mixer", "MultiMedia4", "MM_DL4"},
- {"TERT_MI2S_RX", NULL, "TERT_MI2S_RX Audio Mixer"},
-
- {"SEC_MI2S_RX Audio Mixer", "MultiMedia1", "MM_DL1"},
- {"SEC_MI2S_RX Audio Mixer", "MultiMedia2", "MM_DL2"},
- {"SEC_MI2S_RX Audio Mixer", "MultiMedia3", "MM_DL3"},
- {"SEC_MI2S_RX Audio Mixer", "MultiMedia4", "MM_DL4"},
- {"SEC_MI2S_RX Audio Mixer", "MultiMedia5", "MM_DL5"},
- {"SEC_MI2S_RX Audio Mixer", "MultiMedia6", "MM_DL5"},
- {"SEC_MI2S_RX Audio Mixer", "MultiMedia7", "MM_DL7"},
- {"SEC_MI2S_RX Audio Mixer", "MultiMedia8", "MM_DL7"},
- {"SEC_MI2S_RX", NULL, "SEC_MI2S_RX Audio Mixer"},
-
- {"PRI_MI2S_RX Audio Mixer", "MultiMedia1", "MM_DL1"},
- {"PRI_MI2S_RX Audio Mixer", "MultiMedia2", "MM_DL2"},
- {"PRI_MI2S_RX Audio Mixer", "MultiMedia3", "MM_DL3"},
- {"PRI_MI2S_RX Audio Mixer", "MultiMedia4", "MM_DL4"},
- {"PRI_MI2S_RX Audio Mixer", "MultiMedia5", "MM_DL5"},
- {"PRI_MI2S_RX Audio Mixer", "MultiMedia7", "MM_DL7"},
- {"PRI_MI2S_RX", NULL, "PRI_MI2S_RX Audio Mixer"},
-
- {"MultiMedia1 Mixer", "PRI_MI2S_TX", "PRI_MI2S_TX"},
- {"MultiMedia1 Mixer", "SEC_MI2S_TX", "SEC_MI2S_TX"},
- {"MultiMedia1 Mixer", "QUAT_MI2S_TX", "QUAT_MI2S_TX"},
- {"MultiMedia1 Mixer", "TERT_MI2S_TX", "TERT_MI2S_TX"},
-
- {"MultiMedia2 Mixer", "PRI_MI2S_TX", "PRI_MI2S_TX"},
- {"MultiMedia2 Mixer", "SEC_MI2S_TX", "SEC_MI2S_TX"},
- {"MultiMedia2 Mixer", "QUAT_MI2S_TX", "QUAT_MI2S_TX"},
- {"MultiMedia2 Mixer", "TERT_MI2S_TX", "TERT_MI2S_TX"},
-
- {"MultiMedia3 Mixer", "PRI_MI2S_TX", "PRI_MI2S_TX"},
- {"MultiMedia3 Mixer", "SEC_MI2S_TX", "SEC_MI2S_TX"},
- {"MultiMedia3 Mixer", "QUAT_MI2S_TX", "QUAT_MI2S_TX"},
- {"MultiMedia3 Mixer", "TERT_MI2S_TX", "TERT_MI2S_TX"},
-
- {"MultiMedia4 Mixer", "PRI_MI2S_TX", "PRI_MI2S_TX"},
- {"MultiMedia4 Mixer", "SEC_MI2S_TX", "SEC_MI2S_TX"},
- {"MultiMedia4 Mixer", "QUAT_MI2S_TX", "QUAT_MI2S_TX"},
- {"MultiMedia4 Mixer", "TERT_MI2S_TX", "TERT_MI2S_TX"},
-
- {"MultiMedia5 Mixer", "PRI_MI2S_TX", "PRI_MI2S_TX"},
- {"MultiMedia5 Mixer", "SEC_MI2S_TX", "SEC_MI2S_TX"},
- {"MultiMedia5 Mixer", "QUAT_MI2S_TX", "QUAT_MI2S_TX"},
- {"MultiMedia5 Mixer", "TERT_MI2S_TX", "TERT_MI2S_TX"},
-
- {"MultiMedia6 Mixer", "PRI_MI2S_TX", "PRI_MI2S_TX"},
- {"MultiMedia6 Mixer", "SEC_MI2S_TX", "SEC_MI2S_TX"},
- {"MultiMedia6 Mixer", "QUAT_MI2S_TX", "QUAT_MI2S_TX"},
- {"MultiMedia6 Mixer", "TERT_MI2S_TX", "TERT_MI2S_TX"},
-
- {"MultiMedia7 Mixer", "PRI_MI2S_TX", "PRI_MI2S_TX"},
- {"MultiMedia7 Mixer", "SEC_MI2S_TX", "SEC_MI2S_TX"},
- {"MultiMedia7 Mixer", "QUAT_MI2S_TX", "QUAT_MI2S_TX"},
- {"MultiMedia7 Mixer", "TERT_MI2S_TX", "TERT_MI2S_TX"},
-
- {"MultiMedia8 Mixer", "PRI_MI2S_TX", "PRI_MI2S_TX"},
- {"MultiMedia8 Mixer", "SEC_MI2S_TX", "SEC_MI2S_TX"},
- {"MultiMedia8 Mixer", "QUAT_MI2S_TX", "QUAT_MI2S_TX"},
- {"MultiMedia8 Mixer", "TERT_MI2S_TX", "TERT_MI2S_TX"},
+ Q6ROUTING_RX_DAPM_ROUTE("HDMI Mixer", "HDMI_RX"),
+ Q6ROUTING_RX_DAPM_ROUTE("SLIMBUS_0_RX Audio Mixer", "SLIMBUS_0_RX"),
+ Q6ROUTING_RX_DAPM_ROUTE("SLIMBUS_1_RX Audio Mixer", "SLIMBUS_1_RX"),
+ Q6ROUTING_RX_DAPM_ROUTE("SLIMBUS_2_RX Audio Mixer", "SLIMBUS_2_RX"),
+ Q6ROUTING_RX_DAPM_ROUTE("SLIMBUS_3_RX Audio Mixer", "SLIMBUS_3_RX"),
+ Q6ROUTING_RX_DAPM_ROUTE("SLIMBUS_4_RX Audio Mixer", "SLIMBUS_4_RX"),
+ Q6ROUTING_RX_DAPM_ROUTE("SLIMBUS_5_RX Audio Mixer", "SLIMBUS_5_RX"),
+ Q6ROUTING_RX_DAPM_ROUTE("SLIMBUS_6_RX Audio Mixer", "SLIMBUS_6_RX"),
+ Q6ROUTING_RX_DAPM_ROUTE("QUAT_MI2S_RX Audio Mixer", "QUAT_MI2S_RX"),
+ Q6ROUTING_RX_DAPM_ROUTE("TERT_MI2S_RX Audio Mixer", "TERT_MI2S_RX"),
+ Q6ROUTING_RX_DAPM_ROUTE("SEC_MI2S_RX Audio Mixer", "SEC_MI2S_RX"),
+ Q6ROUTING_RX_DAPM_ROUTE("PRI_MI2S_RX Audio Mixer", "PRI_MI2S_RX"),
+ Q6ROUTING_TX_DAPM_ROUTE("MultiMedia1 Mixer"),
+ Q6ROUTING_TX_DAPM_ROUTE("MultiMedia2 Mixer"),
+ Q6ROUTING_TX_DAPM_ROUTE("MultiMedia3 Mixer"),
+ Q6ROUTING_TX_DAPM_ROUTE("MultiMedia4 Mixer"),
+ Q6ROUTING_TX_DAPM_ROUTE("MultiMedia5 Mixer"),
+ Q6ROUTING_TX_DAPM_ROUTE("MultiMedia6 Mixer"),
+ Q6ROUTING_TX_DAPM_ROUTE("MultiMedia7 Mixer"),
+ Q6ROUTING_TX_DAPM_ROUTE("MultiMedia8 Mixer"),
{"MM_UL1", NULL, "MultiMedia1 Mixer"},
{"MM_UL2", NULL, "MultiMedia2 Mixer"},
--
2.16.2
^ permalink raw reply related
* [PATCH 4/6] ASoC: qdsp6: q6afe-dai: add support to tdm dais
From: Srinivas Kandagatla @ 2018-05-29 10:18 UTC (permalink / raw)
To: broonie, linux-arm-msm, alsa-devel, robh+dt, bgoswami
Cc: mark.rutland, lgirdwood, plai, tiwai, perex, devicetree,
linux-kernel, linux-arm-kernel, rohkumar, spatakok,
Srinivas Kandagatla
In-Reply-To: <20180529101833.30489-1-srinivas.kandagatla@linaro.org>
This patch adds support to 40 TDM ports supported in AFE.
Signed-off-by: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
---
sound/soc/qcom/qdsp6/q6afe-dai.c | 574 ++++++++++++++++++++++++++++++++++++++-
1 file changed, 573 insertions(+), 1 deletion(-)
diff --git a/sound/soc/qcom/qdsp6/q6afe-dai.c b/sound/soc/qcom/qdsp6/q6afe-dai.c
index e529edfd8001..5002dd05bf27 100644
--- a/sound/soc/qcom/qdsp6/q6afe-dai.c
+++ b/sound/soc/qcom/qdsp6/q6afe-dai.c
@@ -14,8 +14,56 @@
#include <sound/pcm_params.h>
#include "q6afe.h"
+#define Q6AFE_TDM_PB_DAI(pre, num, did) { \
+ .playback = { \
+ .stream_name = pre" TDM"#num" Playback", \
+ .rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |\
+ SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000 |\
+ SNDRV_PCM_RATE_176400, \
+ .formats = SNDRV_PCM_FMTBIT_S16_LE | \
+ SNDRV_PCM_FMTBIT_S24_LE | \
+ SNDRV_PCM_FMTBIT_S32_LE, \
+ .channels_min = 1, \
+ .channels_max = 8, \
+ .rate_min = 8000, \
+ .rate_max = 176400, \
+ }, \
+ .name = #did, \
+ .ops = &q6tdm_ops, \
+ .id = did, \
+ .probe = msm_dai_q6_dai_probe, \
+ .remove = msm_dai_q6_dai_remove, \
+ }
+
+#define Q6AFE_TDM_CAP_DAI(pre, num, did) { \
+ .capture = { \
+ .stream_name = pre" TDM"#num" Capture", \
+ .rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |\
+ SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000 |\
+ SNDRV_PCM_RATE_176400, \
+ .formats = SNDRV_PCM_FMTBIT_S16_LE | \
+ SNDRV_PCM_FMTBIT_S24_LE | \
+ SNDRV_PCM_FMTBIT_S32_LE, \
+ .channels_min = 1, \
+ .channels_max = 8, \
+ .rate_min = 8000, \
+ .rate_max = 176400, \
+ }, \
+ .name = #did, \
+ .ops = &q6tdm_ops, \
+ .id = did, \
+ .probe = msm_dai_q6_dai_probe, \
+ .remove = msm_dai_q6_dai_remove, \
+ }
+
struct q6afe_dai_priv_data {
uint32_t sd_line_mask;
+ uint32_t sync_mode;
+ uint32_t sync_src;
+ uint32_t data_out_enable;
+ uint32_t invert_sync;
+ uint32_t data_delay;
+ uint32_t data_align;
};
struct q6afe_dai_data {
@@ -130,6 +178,137 @@ static int q6i2s_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
return 0;
}
+static int q6tdm_set_tdm_slot(struct snd_soc_dai *dai,
+ unsigned int tx_mask,
+ unsigned int rx_mask,
+ int slots, int slot_width)
+{
+
+ struct q6afe_dai_data *dai_data = dev_get_drvdata(dai->dev);
+ struct q6afe_tdm_cfg *tdm = &dai_data->port_config[dai->id].tdm;
+ unsigned int cap_mask;
+ int rc = 0;
+
+ /* HW only supports 16 and 32 bit slot width configuration */
+ if ((slot_width != 16) && (slot_width != 32)) {
+ dev_err(dai->dev, "%s: invalid slot_width %d\n",
+ __func__, slot_width);
+ return -EINVAL;
+ }
+
+ /* HW supports 1-32 slots configuration. Typical: 1, 2, 4, 8, 16, 32 */
+ switch (slots) {
+ case 2:
+ cap_mask = 0x03;
+ break;
+ case 4:
+ cap_mask = 0x0F;
+ break;
+ case 8:
+ cap_mask = 0xFF;
+ break;
+ case 16:
+ cap_mask = 0xFFFF;
+ break;
+ default:
+ dev_err(dai->dev, "%s: invalid slots %d\n",
+ __func__, slots);
+ return -EINVAL;
+ }
+
+ switch (dai->id) {
+ case PRIMARY_TDM_RX_0 ... QUINARY_TDM_TX_7:
+ tdm->nslots_per_frame = slots;
+ tdm->slot_width = slot_width;
+ /* TDM RX dais ids are even and tx are odd */
+ tdm->slot_mask = (dai->id & 0x1 ? tx_mask : rx_mask) & cap_mask;
+ break;
+ default:
+ dev_err(dai->dev, "%s: invalid dai id 0x%x\n",
+ __func__, dai->id);
+ return -EINVAL;
+ }
+
+ return rc;
+}
+
+static int q6tdm_set_channel_map(struct snd_soc_dai *dai,
+ unsigned int tx_num, unsigned int *tx_slot,
+ unsigned int rx_num, unsigned int *rx_slot)
+{
+
+ struct q6afe_dai_data *dai_data = dev_get_drvdata(dai->dev);
+ struct q6afe_tdm_cfg *tdm = &dai_data->port_config[dai->id].tdm;
+ int rc = 0;
+ int i = 0;
+
+ switch (dai->id) {
+ case PRIMARY_TDM_RX_0 ... QUINARY_TDM_TX_7:
+ if (dai->id & 0x1) {
+ if (!tx_slot) {
+ dev_err(dai->dev, "tx slot not found\n");
+ return -EINVAL;
+ }
+ if (tx_num > AFE_PORT_MAX_AUDIO_CHAN_CNT) {
+ dev_err(dai->dev, "invalid tx num %d\n",
+ tx_num);
+ return -EINVAL;
+ }
+
+ for (i = 0; i < tx_num; i++)
+ tdm->ch_mapping[i] = tx_slot[i];
+
+ for (i = tx_num; i < AFE_PORT_MAX_AUDIO_CHAN_CNT; i++)
+ tdm->ch_mapping[i] = Q6AFE_CMAP_INVALID;
+
+ tdm->num_channels = tx_num;
+ } else {
+ /* rx */
+ if (!rx_slot) {
+ dev_err(dai->dev, "rx slot not found\n");
+ return -EINVAL;
+ }
+ if (rx_num > AFE_PORT_MAX_AUDIO_CHAN_CNT) {
+ dev_err(dai->dev, "invalid rx num %d\n",
+ rx_num);
+ return -EINVAL;
+ }
+
+ for (i = 0; i < rx_num; i++)
+ tdm->ch_mapping[i] = rx_slot[i];
+
+ for (i = rx_num; i < AFE_PORT_MAX_AUDIO_CHAN_CNT; i++)
+ tdm->ch_mapping[i] = Q6AFE_CMAP_INVALID;
+
+ tdm->num_channels = rx_num;
+ }
+
+ break;
+ default:
+ dev_err(dai->dev, "%s: invalid dai id 0x%x\n",
+ __func__, dai->id);
+ return -EINVAL;
+ }
+
+ return rc;
+}
+
+static int q6tdm_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params,
+ struct snd_soc_dai *dai)
+{
+ struct q6afe_dai_data *dai_data = dev_get_drvdata(dai->dev);
+ struct q6afe_tdm_cfg *tdm = &dai_data->port_config[dai->id].tdm;
+
+ tdm->bit_width = params_width(params);
+ tdm->sample_rate = params_rate(params);
+ tdm->num_channels = params_channels(params);
+ tdm->data_align_type = dai_data->priv[dai->id].data_align;
+ tdm->sync_src = dai_data->priv[dai->id].sync_src;
+ tdm->sync_mode = dai_data->priv[dai->id].sync_mode;
+
+ return 0;
+}
static void q6afe_dai_shutdown(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
@@ -177,6 +356,10 @@ static int q6afe_dai_prepare(struct snd_pcm_substream *substream,
return rc;
}
break;
+ case PRIMARY_TDM_RX_0 ... QUINARY_TDM_TX_7:
+ q6afe_tdm_port_prepare(dai_data->port[dai->id],
+ &dai_data->port_config[dai->id].tdm);
+ break;
default:
return -EINVAL;
}
@@ -235,11 +418,17 @@ static int q6afe_mi2s_set_sysclk(struct snd_soc_dai *dai,
Q6AFE_LPASS_CLK_SRC_INTERNAL,
Q6AFE_LPASS_CLK_ROOT_DEFAULT,
freq, dir);
- case Q6AFE_LPASS_CLK_ID_PRI_MI2S_IBIT ... Q6AFE_LPASS_CLK_ID_INT_MCLK_1:
+ case Q6AFE_LPASS_CLK_ID_PRI_MI2S_IBIT ... Q6AFE_LPASS_CLK_ID_QUI_MI2S_OSR:
+ case Q6AFE_LPASS_CLK_ID_MCLK_1 ... Q6AFE_LPASS_CLK_ID_INT_MCLK_1:
return q6afe_port_set_sysclk(port, clk_id,
Q6AFE_LPASS_CLK_ATTRIBUTE_COUPLE_NO,
Q6AFE_LPASS_CLK_ROOT_DEFAULT,
freq, dir);
+ case Q6AFE_LPASS_CLK_ID_PRI_TDM_IBIT ... Q6AFE_LPASS_CLK_ID_QUIN_TDM_EBIT:
+ return q6afe_port_set_sysclk(port, clk_id,
+ Q6AFE_LPASS_CLK_ATTRIBUTE_INVERT_COUPLE_NO,
+ Q6AFE_LPASS_CLK_ROOT_DEFAULT,
+ freq, dir);
}
return 0;
@@ -259,6 +448,96 @@ static const struct snd_soc_dapm_route q6afe_dapm_routes[] = {
{"Tertiary MI2S Playback", NULL, "TERT_MI2S_RX"},
{"Quaternary MI2S Playback", NULL, "QUAT_MI2S_RX"},
+ {"Primary TDM0 Playback", NULL, "PRIMARY_TDM_RX_0"},
+ {"Primary TDM1 Playback", NULL, "PRIMARY_TDM_RX_1"},
+ {"Primary TDM2 Playback", NULL, "PRIMARY_TDM_RX_2"},
+ {"Primary TDM3 Playback", NULL, "PRIMARY_TDM_RX_3"},
+ {"Primary TDM4 Playback", NULL, "PRIMARY_TDM_RX_4"},
+ {"Primary TDM5 Playback", NULL, "PRIMARY_TDM_RX_5"},
+ {"Primary TDM6 Playback", NULL, "PRIMARY_TDM_RX_6"},
+ {"Primary TDM7 Playback", NULL, "PRIMARY_TDM_RX_7"},
+
+ {"Secondary TDM0 Playback", NULL, "SEC_TDM_RX_0"},
+ {"Secondary TDM1 Playback", NULL, "SEC_TDM_RX_1"},
+ {"Secondary TDM2 Playback", NULL, "SEC_TDM_RX_2"},
+ {"Secondary TDM3 Playback", NULL, "SEC_TDM_RX_3"},
+ {"Secondary TDM4 Playback", NULL, "SEC_TDM_RX_4"},
+ {"Secondary TDM5 Playback", NULL, "SEC_TDM_RX_5"},
+ {"Secondary TDM6 Playback", NULL, "SEC_TDM_RX_6"},
+ {"Secondary TDM7 Playback", NULL, "SEC_TDM_RX_7"},
+
+ {"Tertiary TDM0 Playback", NULL, "TERT_TDM_RX_0"},
+ {"Tertiary TDM1 Playback", NULL, "TERT_TDM_RX_1"},
+ {"Tertiary TDM2 Playback", NULL, "TERT_TDM_RX_2"},
+ {"Tertiary TDM3 Playback", NULL, "TERT_TDM_RX_3"},
+ {"Tertiary TDM4 Playback", NULL, "TERT_TDM_RX_4"},
+ {"Tertiary TDM5 Playback", NULL, "TERT_TDM_RX_5"},
+ {"Tertiary TDM6 Playback", NULL, "TERT_TDM_RX_6"},
+ {"Tertiary TDM7 Playback", NULL, "TERT_TDM_RX_7"},
+
+ {"Quaternary TDM0 Playback", NULL, "QUAT_TDM_RX_0"},
+ {"Quaternary TDM1 Playback", NULL, "QUAT_TDM_RX_1"},
+ {"Quaternary TDM2 Playback", NULL, "QUAT_TDM_RX_2"},
+ {"Quaternary TDM3 Playback", NULL, "QUAT_TDM_RX_3"},
+ {"Quaternary TDM4 Playback", NULL, "QUAT_TDM_RX_4"},
+ {"Quaternary TDM5 Playback", NULL, "QUAT_TDM_RX_5"},
+ {"Quaternary TDM6 Playback", NULL, "QUAT_TDM_RX_6"},
+ {"Quaternary TDM7 Playback", NULL, "QUAT_TDM_RX_7"},
+
+ {"Quinary TDM0 Playback", NULL, "QUIN_TDM_RX_0"},
+ {"Quinary TDM1 Playback", NULL, "QUIN_TDM_RX_1"},
+ {"Quinary TDM2 Playback", NULL, "QUIN_TDM_RX_2"},
+ {"Quinary TDM3 Playback", NULL, "QUIN_TDM_RX_3"},
+ {"Quinary TDM4 Playback", NULL, "QUIN_TDM_RX_4"},
+ {"Quinary TDM5 Playback", NULL, "QUIN_TDM_RX_5"},
+ {"Quinary TDM6 Playback", NULL, "QUIN_TDM_RX_6"},
+ {"Quinary TDM7 Playback", NULL, "QUIN_TDM_RX_7"},
+
+ {"PRIMARY_TDM_TX_0", NULL, "Primary TDM0 Capture"},
+ {"PRIMARY_TDM_TX_1", NULL, "Primary TDM1 Capture"},
+ {"PRIMARY_TDM_TX_2", NULL, "Primary TDM2 Capture"},
+ {"PRIMARY_TDM_TX_3", NULL, "Primary TDM3 Capture"},
+ {"PRIMARY_TDM_TX_4", NULL, "Primary TDM4 Capture"},
+ {"PRIMARY_TDM_TX_5", NULL, "Primary TDM5 Capture"},
+ {"PRIMARY_TDM_TX_6", NULL, "Primary TDM6 Capture"},
+ {"PRIMARY_TDM_TX_7", NULL, "Primary TDM7 Capture"},
+
+ {"SEC_TDM_TX_0", NULL, "Secondary TDM0 Capture"},
+ {"SEC_TDM_TX_1", NULL, "Secondary TDM1 Capture"},
+ {"SEC_TDM_TX_2", NULL, "Secondary TDM2 Capture"},
+ {"SEC_TDM_TX_3", NULL, "Secondary TDM3 Capture"},
+ {"SEC_TDM_TX_4", NULL, "Secondary TDM4 Capture"},
+ {"SEC_TDM_TX_5", NULL, "Secondary TDM5 Capture"},
+ {"SEC_TDM_TX_6", NULL, "Secondary TDM6 Capture"},
+ {"SEC_TDM_TX_7", NULL, "Secondary TDM7 Capture"},
+
+ {"TERT_TDM_TX_0", NULL, "Tertiary TDM0 Capture"},
+ {"TERT_TDM_TX_1", NULL, "Tertiary TDM1 Capture"},
+ {"TERT_TDM_TX_2", NULL, "Tertiary TDM2 Capture"},
+ {"TERT_TDM_TX_3", NULL, "Tertiary TDM3 Capture"},
+ {"TERT_TDM_TX_4", NULL, "Tertiary TDM4 Capture"},
+ {"TERT_TDM_TX_5", NULL, "Tertiary TDM5 Capture"},
+ {"TERT_TDM_TX_6", NULL, "Tertiary TDM6 Capture"},
+ {"TERT_TDM_TX_7", NULL, "Tertiary TDM7 Capture"},
+
+ {"QUAT_TDM_TX_0", NULL, "Quaternary TDM0 Capture"},
+ {"QUAT_TDM_TX_1", NULL, "Quaternary TDM1 Capture"},
+ {"QUAT_TDM_TX_2", NULL, "Quaternary TDM2 Capture"},
+ {"QUAT_TDM_TX_3", NULL, "Quaternary TDM3 Capture"},
+ {"QUAT_TDM_TX_4", NULL, "Quaternary TDM4 Capture"},
+ {"QUAT_TDM_TX_5", NULL, "Quaternary TDM5 Capture"},
+ {"QUAT_TDM_TX_6", NULL, "Quaternary TDM6 Capture"},
+ {"QUAT_TDM_TX_7", NULL, "Quaternary TDM7 Capture"},
+
+ {"QUIN_TDM_TX_0", NULL, "Quinary TDM0 Capture"},
+ {"QUIN_TDM_TX_1", NULL, "Quinary TDM1 Capture"},
+ {"QUIN_TDM_TX_2", NULL, "Quinary TDM2 Capture"},
+ {"QUIN_TDM_TX_3", NULL, "Quinary TDM3 Capture"},
+ {"QUIN_TDM_TX_4", NULL, "Quinary TDM4 Capture"},
+ {"QUIN_TDM_TX_5", NULL, "Quinary TDM5 Capture"},
+ {"QUIN_TDM_TX_6", NULL, "Quinary TDM6 Capture"},
+ {"QUIN_TDM_TX_7", NULL, "Quinary TDM7 Capture"},
+
{"TERT_MI2S_TX", NULL, "Tertiary MI2S Capture"},
{"PRI_MI2S_TX", NULL, "Primary MI2S Capture"},
{"SEC_MI2S_TX", NULL, "Secondary MI2S Capture"},
@@ -286,6 +565,15 @@ static struct snd_soc_dai_ops q6slim_ops = {
.set_channel_map = q6slim_set_channel_map,
};
+static struct snd_soc_dai_ops q6tdm_ops = {
+ .prepare = q6afe_dai_prepare,
+ .shutdown = q6afe_dai_shutdown,
+ .set_sysclk = q6afe_mi2s_set_sysclk,
+ .set_tdm_slot = q6tdm_set_tdm_slot,
+ .set_channel_map = q6tdm_set_channel_map,
+ .hw_params = q6tdm_hw_params,
+};
+
static int msm_dai_q6_dai_probe(struct snd_soc_dai *dai)
{
struct q6afe_dai_data *dai_data = dev_get_drvdata(dai->dev);
@@ -574,6 +862,86 @@ static struct snd_soc_dai_driver q6afe_dais[] = {
.probe = msm_dai_q6_dai_probe,
.remove = msm_dai_q6_dai_remove,
},
+ Q6AFE_TDM_PB_DAI("Primary", 0, PRIMARY_TDM_RX_0),
+ Q6AFE_TDM_PB_DAI("Primary", 1, PRIMARY_TDM_RX_1),
+ Q6AFE_TDM_PB_DAI("Primary", 2, PRIMARY_TDM_RX_2),
+ Q6AFE_TDM_PB_DAI("Primary", 3, PRIMARY_TDM_RX_3),
+ Q6AFE_TDM_PB_DAI("Primary", 4, PRIMARY_TDM_RX_4),
+ Q6AFE_TDM_PB_DAI("Primary", 5, PRIMARY_TDM_RX_5),
+ Q6AFE_TDM_PB_DAI("Primary", 6, PRIMARY_TDM_RX_6),
+ Q6AFE_TDM_PB_DAI("Primary", 7, PRIMARY_TDM_RX_7),
+ Q6AFE_TDM_CAP_DAI("Primary", 0, PRIMARY_TDM_TX_0),
+ Q6AFE_TDM_CAP_DAI("Primary", 1, PRIMARY_TDM_TX_1),
+ Q6AFE_TDM_CAP_DAI("Primary", 2, PRIMARY_TDM_TX_2),
+ Q6AFE_TDM_CAP_DAI("Primary", 3, PRIMARY_TDM_TX_3),
+ Q6AFE_TDM_CAP_DAI("Primary", 4, PRIMARY_TDM_TX_4),
+ Q6AFE_TDM_CAP_DAI("Primary", 5, PRIMARY_TDM_TX_5),
+ Q6AFE_TDM_CAP_DAI("Primary", 6, PRIMARY_TDM_TX_6),
+ Q6AFE_TDM_CAP_DAI("Primary", 7, PRIMARY_TDM_TX_7),
+ Q6AFE_TDM_PB_DAI("Secondary", 0, SECONDARY_TDM_RX_0),
+ Q6AFE_TDM_PB_DAI("Secondary", 1, SECONDARY_TDM_RX_1),
+ Q6AFE_TDM_PB_DAI("Secondary", 2, SECONDARY_TDM_RX_2),
+ Q6AFE_TDM_PB_DAI("Secondary", 3, SECONDARY_TDM_RX_3),
+ Q6AFE_TDM_PB_DAI("Secondary", 4, SECONDARY_TDM_RX_4),
+ Q6AFE_TDM_PB_DAI("Secondary", 5, SECONDARY_TDM_RX_5),
+ Q6AFE_TDM_PB_DAI("Secondary", 6, SECONDARY_TDM_RX_6),
+ Q6AFE_TDM_PB_DAI("Secondary", 7, SECONDARY_TDM_RX_7),
+ Q6AFE_TDM_CAP_DAI("Secondary", 0, SECONDARY_TDM_TX_0),
+ Q6AFE_TDM_CAP_DAI("Secondary", 1, SECONDARY_TDM_TX_1),
+ Q6AFE_TDM_CAP_DAI("Secondary", 2, SECONDARY_TDM_TX_2),
+ Q6AFE_TDM_CAP_DAI("Secondary", 3, SECONDARY_TDM_TX_3),
+ Q6AFE_TDM_CAP_DAI("Secondary", 4, SECONDARY_TDM_TX_4),
+ Q6AFE_TDM_CAP_DAI("Secondary", 5, SECONDARY_TDM_TX_5),
+ Q6AFE_TDM_CAP_DAI("Secondary", 6, SECONDARY_TDM_TX_6),
+ Q6AFE_TDM_CAP_DAI("Secondary", 7, SECONDARY_TDM_TX_7),
+ Q6AFE_TDM_PB_DAI("Tertiary", 0, TERTIARY_TDM_RX_0),
+ Q6AFE_TDM_PB_DAI("Tertiary", 1, TERTIARY_TDM_RX_1),
+ Q6AFE_TDM_PB_DAI("Tertiary", 2, TERTIARY_TDM_RX_2),
+ Q6AFE_TDM_PB_DAI("Tertiary", 3, TERTIARY_TDM_RX_3),
+ Q6AFE_TDM_PB_DAI("Tertiary", 4, TERTIARY_TDM_RX_4),
+ Q6AFE_TDM_PB_DAI("Tertiary", 5, TERTIARY_TDM_RX_5),
+ Q6AFE_TDM_PB_DAI("Tertiary", 6, TERTIARY_TDM_RX_6),
+ Q6AFE_TDM_PB_DAI("Tertiary", 7, TERTIARY_TDM_RX_7),
+ Q6AFE_TDM_CAP_DAI("Tertiary", 0, TERTIARY_TDM_TX_0),
+ Q6AFE_TDM_CAP_DAI("Tertiary", 1, TERTIARY_TDM_TX_1),
+ Q6AFE_TDM_CAP_DAI("Tertiary", 2, TERTIARY_TDM_TX_2),
+ Q6AFE_TDM_CAP_DAI("Tertiary", 3, TERTIARY_TDM_TX_3),
+ Q6AFE_TDM_CAP_DAI("Tertiary", 4, TERTIARY_TDM_TX_4),
+ Q6AFE_TDM_CAP_DAI("Tertiary", 5, TERTIARY_TDM_TX_5),
+ Q6AFE_TDM_CAP_DAI("Tertiary", 6, TERTIARY_TDM_TX_6),
+ Q6AFE_TDM_CAP_DAI("Tertiary", 7, TERTIARY_TDM_TX_7),
+ Q6AFE_TDM_PB_DAI("Quaternary", 0, QUATERNARY_TDM_RX_0),
+ Q6AFE_TDM_PB_DAI("Quaternary", 1, QUATERNARY_TDM_RX_1),
+ Q6AFE_TDM_PB_DAI("Quaternary", 2, QUATERNARY_TDM_RX_2),
+ Q6AFE_TDM_PB_DAI("Quaternary", 3, QUATERNARY_TDM_RX_3),
+ Q6AFE_TDM_PB_DAI("Quaternary", 4, QUATERNARY_TDM_RX_4),
+ Q6AFE_TDM_PB_DAI("Quaternary", 5, QUATERNARY_TDM_RX_5),
+ Q6AFE_TDM_PB_DAI("Quaternary", 6, QUATERNARY_TDM_RX_6),
+ Q6AFE_TDM_PB_DAI("Quaternary", 7, QUATERNARY_TDM_RX_7),
+ Q6AFE_TDM_CAP_DAI("Quaternary", 0, QUATERNARY_TDM_TX_0),
+ Q6AFE_TDM_CAP_DAI("Quaternary", 1, QUATERNARY_TDM_TX_1),
+ Q6AFE_TDM_CAP_DAI("Quaternary", 2, QUATERNARY_TDM_TX_2),
+ Q6AFE_TDM_CAP_DAI("Quaternary", 3, QUATERNARY_TDM_TX_3),
+ Q6AFE_TDM_CAP_DAI("Quaternary", 4, QUATERNARY_TDM_TX_4),
+ Q6AFE_TDM_CAP_DAI("Quaternary", 5, QUATERNARY_TDM_TX_5),
+ Q6AFE_TDM_CAP_DAI("Quaternary", 6, QUATERNARY_TDM_TX_6),
+ Q6AFE_TDM_CAP_DAI("Quaternary", 7, QUATERNARY_TDM_TX_7),
+ Q6AFE_TDM_PB_DAI("Quinary", 0, QUINARY_TDM_RX_0),
+ Q6AFE_TDM_PB_DAI("Quinary", 1, QUINARY_TDM_RX_1),
+ Q6AFE_TDM_PB_DAI("Quinary", 2, QUINARY_TDM_RX_2),
+ Q6AFE_TDM_PB_DAI("Quinary", 3, QUINARY_TDM_RX_3),
+ Q6AFE_TDM_PB_DAI("Quinary", 4, QUINARY_TDM_RX_4),
+ Q6AFE_TDM_PB_DAI("Quinary", 5, QUINARY_TDM_RX_5),
+ Q6AFE_TDM_PB_DAI("Quinary", 6, QUINARY_TDM_RX_6),
+ Q6AFE_TDM_PB_DAI("Quinary", 7, QUINARY_TDM_RX_7),
+ Q6AFE_TDM_CAP_DAI("Quinary", 0, QUINARY_TDM_TX_0),
+ Q6AFE_TDM_CAP_DAI("Quinary", 1, QUINARY_TDM_TX_1),
+ Q6AFE_TDM_CAP_DAI("Quinary", 2, QUINARY_TDM_TX_2),
+ Q6AFE_TDM_CAP_DAI("Quinary", 3, QUINARY_TDM_TX_3),
+ Q6AFE_TDM_CAP_DAI("Quinary", 4, QUINARY_TDM_TX_4),
+ Q6AFE_TDM_CAP_DAI("Quinary", 5, QUINARY_TDM_TX_5),
+ Q6AFE_TDM_CAP_DAI("Quinary", 6, QUINARY_TDM_TX_6),
+ Q6AFE_TDM_CAP_DAI("Quinary", 7, QUINARY_TDM_TX_7),
};
static int q6afe_of_xlate_dai_name(struct snd_soc_component *component,
@@ -623,6 +991,171 @@ static const struct snd_soc_dapm_widget q6afe_dai_widgets[] = {
0, 0, 0, 0),
SND_SOC_DAPM_AIF_IN("PRI_MI2S_TX", "Primary MI2S Capture",
0, 0, 0, 0),
+
+ SND_SOC_DAPM_AIF_OUT("PRIMARY_TDM_RX_0", "Primary TDM0 Playback",
+ 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_OUT("PRIMARY_TDM_RX_1", "Primary TDM1 Playback",
+ 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_OUT("PRIMARY_TDM_RX_2", "Primary TDM2 Playback",
+ 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_OUT("PRIMARY_TDM_RX_3", "Primary TDM3 Playback",
+ 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_OUT("PRIMARY_TDM_RX_4", "Primary TDM4 Playback",
+ 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_OUT("PRIMARY_TDM_RX_5", "Primary TDM5 Playback",
+ 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_OUT("PRIMARY_TDM_RX_6", "Primary TDM6 Playback",
+ 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_OUT("PRIMARY_TDM_RX_7", "Primary TDM7 Playback",
+ 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_IN("PRIMARY_TDM_TX_0", "Primary TDM0 Capture",
+ 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_IN("PRIMARY_TDM_TX_1", "Primary TDM1 Capture",
+ 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_IN("PRIMARY_TDM_TX_2", "Primary TDM2 Capture",
+ 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_IN("PRIMARY_TDM_TX_3", "Primary TDM3 Capture",
+ 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_IN("PRIMARY_TDM_TX_4", "Primary TDM4 Capture",
+ 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_IN("PRIMARY_TDM_TX_5", "Primary TDM5 Capture",
+ 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_IN("PRIMARY_TDM_TX_6", "Primary TDM6 Capture",
+ 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_IN("PRIMARY_TDM_TX_7", "Primary TDM7 Capture",
+ 0, 0, 0, 0),
+
+ SND_SOC_DAPM_AIF_OUT("SEC_TDM_RX_0", "Secondary TDM0 Playback",
+ 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_OUT("SEC_TDM_RX_1", "Secondary TDM1 Playback",
+ 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_OUT("SEC_TDM_RX_2", "Secondary TDM2 Playback",
+ 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_OUT("SEC_TDM_RX_3", "Secondary TDM3 Playback",
+ 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_OUT("SEC_TDM_RX_4", "Secondary TDM4 Playback",
+ 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_OUT("SEC_TDM_RX_5", "Secondary TDM5 Playback",
+ 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_OUT("SEC_TDM_RX_6", "Secondary TDM6 Playback",
+ 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_OUT("SEC_TDM_RX_7", "Secondary TDM7 Playback",
+ 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_IN("SEC_TDM_TX_0", "Secondary TDM0 Capture",
+ 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_IN("SEC_TDM_TX_1", "Secondary TDM1 Capture",
+ 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_IN("SEC_TDM_TX_2", "Secondary TDM2 Capture",
+ 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_IN("SEC_TDM_TX_3", "Secondary TDM3 Capture",
+ 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_IN("SEC_TDM_TX_4", "Secondary TDM4 Capture",
+ 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_IN("SEC_TDM_TX_5", "Secondary TDM5 Capture",
+ 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_IN("SEC_TDM_TX_6", "Secondary TDM6 Capture",
+ 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_IN("SEC_TDM_TX_7", "Secondary TDM7 Capture",
+ 0, 0, 0, 0),
+
+ SND_SOC_DAPM_AIF_OUT("TERT_TDM_RX_0", "Tertiary TDM0 Playback",
+ 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_OUT("TERT_TDM_RX_1", "Tertiary TDM1 Playback",
+ 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_OUT("TERT_TDM_RX_2", "Tertiary TDM2 Playback",
+ 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_OUT("TERT_TDM_RX_3", "Tertiary TDM3 Playback",
+ 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_OUT("TERT_TDM_RX_4", "Tertiary TDM4 Playback",
+ 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_OUT("TERT_TDM_RX_5", "Tertiary TDM5 Playback",
+ 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_OUT("TERT_TDM_RX_6", "Tertiary TDM6 Playback",
+ 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_OUT("TERT_TDM_RX_7", "Tertiary TDM7 Playback",
+ 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_IN("TERT_TDM_TX_0", "Tertiary TDM0 Capture",
+ 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_IN("TERT_TDM_TX_1", "Tertiary TDM1 Capture",
+ 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_IN("TERT_TDM_TX_2", "Tertiary TDM2 Capture",
+ 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_IN("TERT_TDM_TX_3", "Tertiary TDM3 Capture",
+ 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_IN("TERT_TDM_TX_4", "Tertiary TDM4 Capture",
+ 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_IN("TERT_TDM_TX_5", "Tertiary TDM5 Capture",
+ 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_IN("TERT_TDM_TX_6", "Tertiary TDM6 Capture",
+ 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_IN("TERT_TDM_TX_7", "Tertiary TDM7 Capture",
+ 0, 0, 0, 0),
+
+ SND_SOC_DAPM_AIF_OUT("QUAT_TDM_RX_0", "Quaternary TDM0 Playback",
+ 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_OUT("QUAT_TDM_RX_1", "Quaternary TDM1 Playback",
+ 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_OUT("QUAT_TDM_RX_2", "Quaternary TDM2 Playback",
+ 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_OUT("QUAT_TDM_RX_3", "Quaternary TDM3 Playback",
+ 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_OUT("QUAT_TDM_RX_4", "Quaternary TDM4 Playback",
+ 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_OUT("QUAT_TDM_RX_5", "Quaternary TDM5 Playback",
+ 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_OUT("QUAT_TDM_RX_6", "Quaternary TDM6 Playback",
+ 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_OUT("QUAT_TDM_RX_7", "Quaternary TDM7 Playback",
+ 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_IN("QUAT_TDM_TX_0", "Quaternary TDM0 Capture",
+ 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_IN("QUAT_TDM_TX_1", "Quaternary TDM1 Capture",
+ 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_IN("QUAT_TDM_TX_2", "Quaternary TDM2 Capture",
+ 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_IN("QUAT_TDM_TX_3", "Quaternary TDM3 Capture",
+ 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_IN("QUAT_TDM_TX_4", "Quaternary TDM4 Capture",
+ 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_IN("QUAT_TDM_TX_5", "Quaternary TDM5 Capture",
+ 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_IN("QUAT_TDM_TX_6", "Quaternary TDM6 Capture",
+ 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_IN("QUAT_TDM_TX_7", "Quaternary TDM7 Capture",
+ 0, 0, 0, 0),
+
+ SND_SOC_DAPM_AIF_OUT("QUIN_TDM_RX_0", "Quinary TDM0 Playback",
+ 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_OUT("QUIN_TDM_RX_1", "Quinary TDM1 Playback",
+ 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_OUT("QUIN_TDM_RX_2", "Quinary TDM2 Playback",
+ 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_OUT("QUIN_TDM_RX_3", "Quinary TDM3 Playback",
+ 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_OUT("QUIN_TDM_RX_4", "Quinary TDM4 Playback",
+ 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_OUT("QUIN_TDM_RX_5", "Quinary TDM5 Playback",
+ 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_OUT("QUIN_TDM_RX_6", "Quinary TDM6 Playback",
+ 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_OUT("QUIN_TDM_RX_7", "Quinary TDM7 Playback",
+ 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_IN("QUIN_TDM_TX_0", "Quinary TDM0 Capture",
+ 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_IN("QUIN_TDM_TX_1", "Quinary TDM1 Capture",
+ 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_IN("QUIN_TDM_TX_2", "Quinary TDM2 Capture",
+ 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_IN("QUIN_TDM_TX_3", "Quinary TDM3 Capture",
+ 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_IN("QUIN_TDM_TX_4", "Quinary TDM4 Capture",
+ 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_IN("QUIN_TDM_TX_5", "Quinary TDM5 Capture",
+ 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_IN("QUIN_TDM_TX_6", "Quinary TDM6 Capture",
+ 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_IN("QUIN_TDM_TX_7", "Quinary TDM7 Capture",
+ 0, 0, 0, 0),
};
static const struct snd_soc_component_driver q6afe_dai_component = {
@@ -670,6 +1203,45 @@ static void of_q6afe_parse_dai_data(struct device *dev,
for (i = 0; i < num_lines; i++)
priv->sd_line_mask |= BIT(lines[i]);
+ break;
+ case PRIMARY_TDM_RX_0 ... QUINARY_TDM_TX_7:
+ priv = &data->priv[id];
+ ret = of_property_read_u32(node, "qcom,tdm-sync-mode",
+ &priv->sync_mode);
+ if (ret) {
+ dev_err(dev, "No Sync mode from DT\n");
+ break;
+ }
+ ret = of_property_read_u32(node, "qcom,tdm-sync-src",
+ &priv->sync_src);
+ if (ret) {
+ dev_err(dev, "No Sync Src from DT\n");
+ break;
+ }
+ ret = of_property_read_u32(node, "qcom,tdm-data-out",
+ &priv->data_out_enable);
+ if (ret) {
+ dev_err(dev, "No Data out enable from DT\n");
+ break;
+ }
+ ret = of_property_read_u32(node, "qcom,tdm-invert-sync",
+ &priv->invert_sync);
+ if (ret) {
+ dev_err(dev, "No Invert sync from DT\n");
+ break;
+ }
+ ret = of_property_read_u32(node, "qcom,tdm-data-delay",
+ &priv->data_delay);
+ if (ret) {
+ dev_err(dev, "No Data Delay from DT\n");
+ break;
+ }
+ ret = of_property_read_u32(node, "qcom,tdm-data-align",
+ &priv->data_align);
+ if (ret) {
+ dev_err(dev, "No Data align from DT\n");
+ break;
+ }
break;
default:
break;
--
2.16.2
^ permalink raw reply related
* [PATCH 3/6] ASoC: qdsp6: q6afe-dai: use q6afe_dai_prepare() for MI2S
From: Srinivas Kandagatla @ 2018-05-29 10:18 UTC (permalink / raw)
To: broonie, linux-arm-msm, alsa-devel, robh+dt, bgoswami
Cc: mark.rutland, devicetree, rohkumar, linux-kernel, plai, tiwai,
lgirdwood, Srinivas Kandagatla, spatakok, linux-arm-kernel
In-Reply-To: <20180529101833.30489-1-srinivas.kandagatla@linaro.org>
Use common q6afe_dai_prepare() for MI2S dais, this will remove
some code duplication. Also make the if statement to switch to
make the code look neater.
Signed-off-by: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
---
sound/soc/qcom/qdsp6/q6afe-dai.c | 53 ++++++++++++++--------------------------
1 file changed, 18 insertions(+), 35 deletions(-)
diff --git a/sound/soc/qcom/qdsp6/q6afe-dai.c b/sound/soc/qcom/qdsp6/q6afe-dai.c
index 4378e29a95c5..e529edfd8001 100644
--- a/sound/soc/qcom/qdsp6/q6afe-dai.c
+++ b/sound/soc/qcom/qdsp6/q6afe-dai.c
@@ -144,38 +144,6 @@ static void q6afe_dai_shutdown(struct snd_pcm_substream *substream,
}
-static int q6afe_mi2s_prepare(struct snd_pcm_substream *substream,
- struct snd_soc_dai *dai)
-{
- struct q6afe_dai_data *dai_data = dev_get_drvdata(dai->dev);
- int rc;
-
- if (dai_data->is_port_started[dai->id]) {
- /* stop the port and restart with new port config */
- rc = q6afe_port_stop(dai_data->port[dai->id]);
- if (rc < 0) {
- dev_err(dai->dev, "fail to close AFE port (%d)\n", rc);
- return rc;
- }
- }
-
- rc = q6afe_i2s_port_prepare(dai_data->port[dai->id],
- &dai_data->port_config[dai->id].i2s_cfg);
- if (rc < 0) {
- dev_err(dai->dev, "fail to prepare AFE port %x\n", dai->id);
- return rc;
- }
-
- rc = q6afe_port_start(dai_data->port[dai->id]);
- if (rc < 0) {
- dev_err(dai->dev, "fail to start AFE port %x\n", dai->id);
- return rc;
- }
- dai_data->is_port_started[dai->id] = true;
-
- return 0;
-}
-
static int q6afe_dai_prepare(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
@@ -191,12 +159,27 @@ static int q6afe_dai_prepare(struct snd_pcm_substream *substream,
}
}
- if (dai->id == HDMI_RX)
+ switch (dai->id) {
+ case HDMI_RX:
q6afe_hdmi_port_prepare(dai_data->port[dai->id],
&dai_data->port_config[dai->id].hdmi);
- else if (dai->id >= SLIMBUS_0_RX && dai->id <= SLIMBUS_6_TX)
+ break;
+ case SLIMBUS_0_RX ... SLIMBUS_6_TX:
q6afe_slim_port_prepare(dai_data->port[dai->id],
&dai_data->port_config[dai->id].slim);
+ break;
+ case PRIMARY_MI2S_RX ... QUATERNARY_MI2S_TX:
+ rc = q6afe_i2s_port_prepare(dai_data->port[dai->id],
+ &dai_data->port_config[dai->id].i2s_cfg);
+ if (rc < 0) {
+ dev_err(dai->dev, "fail to prepare AFE port %x\n",
+ dai->id);
+ return rc;
+ }
+ break;
+ default:
+ return -EINVAL;
+ }
rc = q6afe_port_start(dai_data->port[dai->id]);
if (rc < 0) {
@@ -289,7 +272,7 @@ static struct snd_soc_dai_ops q6hdmi_ops = {
};
static struct snd_soc_dai_ops q6i2s_ops = {
- .prepare = q6afe_mi2s_prepare,
+ .prepare = q6afe_dai_prepare,
.hw_params = q6i2s_hw_params,
.set_fmt = q6i2s_set_fmt,
.shutdown = q6afe_dai_shutdown,
--
2.16.2
^ permalink raw reply related
* [PATCH 2/6] ASoC: qdsp6: qdafe: add support to tdm ports
From: Srinivas Kandagatla @ 2018-05-29 10:18 UTC (permalink / raw)
To: broonie, linux-arm-msm, alsa-devel, robh+dt, bgoswami
Cc: mark.rutland, devicetree, rohkumar, linux-kernel, plai, tiwai,
lgirdwood, Srinivas Kandagatla, spatakok, linux-arm-kernel
In-Reply-To: <20180529101833.30489-1-srinivas.kandagatla@linaro.org>
This patch adds support to tdm ports in AFE.
Signed-off-by: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
---
sound/soc/qcom/qdsp6/q6afe.c | 429 ++++++++++++++++++++++++++++++++++++++++++-
sound/soc/qcom/qdsp6/q6afe.h | 20 +-
2 files changed, 447 insertions(+), 2 deletions(-)
diff --git a/sound/soc/qcom/qdsp6/q6afe.c b/sound/soc/qcom/qdsp6/q6afe.c
index de0030068ecb..01f43218984b 100644
--- a/sound/soc/qcom/qdsp6/q6afe.c
+++ b/sound/soc/qcom/qdsp6/q6afe.c
@@ -31,6 +31,7 @@
#define AFE_PORT_CMDRSP_GET_PARAM_V2 0x00010106
#define AFE_PARAM_ID_HDMI_CONFIG 0x00010210
#define AFE_MODULE_AUDIO_DEV_INTERFACE 0x0001020C
+#define AFE_MODULE_TDM 0x0001028A
#define AFE_PARAM_ID_CDC_SLIMBUS_SLAVE_CFG 0x00010235
@@ -39,6 +40,8 @@
#define AFE_PARAM_ID_SLIMBUS_CONFIG 0x00010212
#define AFE_PARAM_ID_I2S_CONFIG 0x0001020D
+#define AFE_PARAM_ID_TDM_CONFIG 0x0001029D
+#define AFE_PARAM_ID_PORT_SLOT_MAPPING_CONFIG 0x00010297
/* I2S config specific */
#define AFE_API_VERSION_I2S_CONFIG 0x1
@@ -113,10 +116,194 @@
#define AFE_PORT_ID_QUATERNARY_MI2S_RX 0x1006
#define AFE_PORT_ID_QUATERNARY_MI2S_TX 0x1007
+/* Start of the range of port IDs for TDM devices. */
+#define AFE_PORT_ID_TDM_PORT_RANGE_START 0x9000
+
+/* End of the range of port IDs for TDM devices. */
+#define AFE_PORT_ID_TDM_PORT_RANGE_END \
+ (AFE_PORT_ID_TDM_PORT_RANGE_START+0x50-1)
+
+/* Size of the range of port IDs for TDM ports. */
+#define AFE_PORT_ID_TDM_PORT_RANGE_SIZE \
+ (AFE_PORT_ID_TDM_PORT_RANGE_END - \
+ AFE_PORT_ID_TDM_PORT_RANGE_START+1)
+
+#define AFE_PORT_ID_PRIMARY_TDM_RX \
+ (AFE_PORT_ID_TDM_PORT_RANGE_START + 0x00)
+#define AFE_PORT_ID_PRIMARY_TDM_RX_1 \
+ (AFE_PORT_ID_PRIMARY_TDM_RX + 0x02)
+#define AFE_PORT_ID_PRIMARY_TDM_RX_2 \
+ (AFE_PORT_ID_PRIMARY_TDM_RX + 0x04)
+#define AFE_PORT_ID_PRIMARY_TDM_RX_3 \
+ (AFE_PORT_ID_PRIMARY_TDM_RX + 0x06)
+#define AFE_PORT_ID_PRIMARY_TDM_RX_4 \
+ (AFE_PORT_ID_PRIMARY_TDM_RX + 0x08)
+#define AFE_PORT_ID_PRIMARY_TDM_RX_5 \
+ (AFE_PORT_ID_PRIMARY_TDM_RX + 0x0A)
+#define AFE_PORT_ID_PRIMARY_TDM_RX_6 \
+ (AFE_PORT_ID_PRIMARY_TDM_RX + 0x0C)
+#define AFE_PORT_ID_PRIMARY_TDM_RX_7 \
+ (AFE_PORT_ID_PRIMARY_TDM_RX + 0x0E)
+
+#define AFE_PORT_ID_PRIMARY_TDM_TX \
+ (AFE_PORT_ID_TDM_PORT_RANGE_START + 0x01)
+#define AFE_PORT_ID_PRIMARY_TDM_TX_1 \
+ (AFE_PORT_ID_PRIMARY_TDM_TX + 0x02)
+#define AFE_PORT_ID_PRIMARY_TDM_TX_2 \
+ (AFE_PORT_ID_PRIMARY_TDM_TX + 0x04)
+#define AFE_PORT_ID_PRIMARY_TDM_TX_3 \
+ (AFE_PORT_ID_PRIMARY_TDM_TX + 0x06)
+#define AFE_PORT_ID_PRIMARY_TDM_TX_4 \
+ (AFE_PORT_ID_PRIMARY_TDM_TX + 0x08)
+#define AFE_PORT_ID_PRIMARY_TDM_TX_5 \
+ (AFE_PORT_ID_PRIMARY_TDM_TX + 0x0A)
+#define AFE_PORT_ID_PRIMARY_TDM_TX_6 \
+ (AFE_PORT_ID_PRIMARY_TDM_TX + 0x0C)
+#define AFE_PORT_ID_PRIMARY_TDM_TX_7 \
+ (AFE_PORT_ID_PRIMARY_TDM_TX + 0x0E)
+
+#define AFE_PORT_ID_SECONDARY_TDM_RX \
+ (AFE_PORT_ID_TDM_PORT_RANGE_START + 0x10)
+#define AFE_PORT_ID_SECONDARY_TDM_RX_1 \
+ (AFE_PORT_ID_SECONDARY_TDM_RX + 0x02)
+#define AFE_PORT_ID_SECONDARY_TDM_RX_2 \
+ (AFE_PORT_ID_SECONDARY_TDM_RX + 0x04)
+#define AFE_PORT_ID_SECONDARY_TDM_RX_3 \
+ (AFE_PORT_ID_SECONDARY_TDM_RX + 0x06)
+#define AFE_PORT_ID_SECONDARY_TDM_RX_4 \
+ (AFE_PORT_ID_SECONDARY_TDM_RX + 0x08)
+#define AFE_PORT_ID_SECONDARY_TDM_RX_5 \
+ (AFE_PORT_ID_SECONDARY_TDM_RX + 0x0A)
+#define AFE_PORT_ID_SECONDARY_TDM_RX_6 \
+ (AFE_PORT_ID_SECONDARY_TDM_RX + 0x0C)
+#define AFE_PORT_ID_SECONDARY_TDM_RX_7 \
+ (AFE_PORT_ID_SECONDARY_TDM_RX + 0x0E)
+
+#define AFE_PORT_ID_SECONDARY_TDM_TX \
+ (AFE_PORT_ID_TDM_PORT_RANGE_START + 0x11)
+#define AFE_PORT_ID_SECONDARY_TDM_TX_1 \
+ (AFE_PORT_ID_SECONDARY_TDM_TX + 0x02)
+#define AFE_PORT_ID_SECONDARY_TDM_TX_2 \
+ (AFE_PORT_ID_SECONDARY_TDM_TX + 0x04)
+#define AFE_PORT_ID_SECONDARY_TDM_TX_3 \
+ (AFE_PORT_ID_SECONDARY_TDM_TX + 0x06)
+#define AFE_PORT_ID_SECONDARY_TDM_TX_4 \
+ (AFE_PORT_ID_SECONDARY_TDM_TX + 0x08)
+#define AFE_PORT_ID_SECONDARY_TDM_TX_5 \
+ (AFE_PORT_ID_SECONDARY_TDM_TX + 0x0A)
+#define AFE_PORT_ID_SECONDARY_TDM_TX_6 \
+ (AFE_PORT_ID_SECONDARY_TDM_TX + 0x0C)
+#define AFE_PORT_ID_SECONDARY_TDM_TX_7 \
+ (AFE_PORT_ID_SECONDARY_TDM_TX + 0x0E)
+
+#define AFE_PORT_ID_TERTIARY_TDM_RX \
+ (AFE_PORT_ID_TDM_PORT_RANGE_START + 0x20)
+#define AFE_PORT_ID_TERTIARY_TDM_RX_1 \
+ (AFE_PORT_ID_TERTIARY_TDM_RX + 0x02)
+#define AFE_PORT_ID_TERTIARY_TDM_RX_2 \
+ (AFE_PORT_ID_TERTIARY_TDM_RX + 0x04)
+#define AFE_PORT_ID_TERTIARY_TDM_RX_3 \
+ (AFE_PORT_ID_TERTIARY_TDM_RX + 0x06)
+#define AFE_PORT_ID_TERTIARY_TDM_RX_4 \
+ (AFE_PORT_ID_TERTIARY_TDM_RX + 0x08)
+#define AFE_PORT_ID_TERTIARY_TDM_RX_5 \
+ (AFE_PORT_ID_TERTIARY_TDM_RX + 0x0A)
+#define AFE_PORT_ID_TERTIARY_TDM_RX_6 \
+ (AFE_PORT_ID_TERTIARY_TDM_RX + 0x0C)
+#define AFE_PORT_ID_TERTIARY_TDM_RX_7 \
+ (AFE_PORT_ID_TERTIARY_TDM_RX + 0x0E)
+
+#define AFE_PORT_ID_TERTIARY_TDM_TX \
+ (AFE_PORT_ID_TDM_PORT_RANGE_START + 0x21)
+#define AFE_PORT_ID_TERTIARY_TDM_TX_1 \
+ (AFE_PORT_ID_TERTIARY_TDM_TX + 0x02)
+#define AFE_PORT_ID_TERTIARY_TDM_TX_2 \
+ (AFE_PORT_ID_TERTIARY_TDM_TX + 0x04)
+#define AFE_PORT_ID_TERTIARY_TDM_TX_3 \
+ (AFE_PORT_ID_TERTIARY_TDM_TX + 0x06)
+#define AFE_PORT_ID_TERTIARY_TDM_TX_4 \
+ (AFE_PORT_ID_TERTIARY_TDM_TX + 0x08)
+#define AFE_PORT_ID_TERTIARY_TDM_TX_5 \
+ (AFE_PORT_ID_TERTIARY_TDM_TX + 0x0A)
+#define AFE_PORT_ID_TERTIARY_TDM_TX_6 \
+ (AFE_PORT_ID_TERTIARY_TDM_TX + 0x0C)
+#define AFE_PORT_ID_TERTIARY_TDM_TX_7 \
+ (AFE_PORT_ID_TERTIARY_TDM_TX + 0x0E)
+
+#define AFE_PORT_ID_QUATERNARY_TDM_RX \
+ (AFE_PORT_ID_TDM_PORT_RANGE_START + 0x30)
+#define AFE_PORT_ID_QUATERNARY_TDM_RX_1 \
+ (AFE_PORT_ID_QUATERNARY_TDM_RX + 0x02)
+#define AFE_PORT_ID_QUATERNARY_TDM_RX_2 \
+ (AFE_PORT_ID_QUATERNARY_TDM_RX + 0x04)
+#define AFE_PORT_ID_QUATERNARY_TDM_RX_3 \
+ (AFE_PORT_ID_QUATERNARY_TDM_RX + 0x06)
+#define AFE_PORT_ID_QUATERNARY_TDM_RX_4 \
+ (AFE_PORT_ID_QUATERNARY_TDM_RX + 0x08)
+#define AFE_PORT_ID_QUATERNARY_TDM_RX_5 \
+ (AFE_PORT_ID_QUATERNARY_TDM_RX + 0x0A)
+#define AFE_PORT_ID_QUATERNARY_TDM_RX_6 \
+ (AFE_PORT_ID_QUATERNARY_TDM_RX + 0x0C)
+#define AFE_PORT_ID_QUATERNARY_TDM_RX_7 \
+ (AFE_PORT_ID_QUATERNARY_TDM_RX + 0x0E)
+
+#define AFE_PORT_ID_QUATERNARY_TDM_TX \
+ (AFE_PORT_ID_TDM_PORT_RANGE_START + 0x31)
+#define AFE_PORT_ID_QUATERNARY_TDM_TX_1 \
+ (AFE_PORT_ID_QUATERNARY_TDM_TX + 0x02)
+#define AFE_PORT_ID_QUATERNARY_TDM_TX_2 \
+ (AFE_PORT_ID_QUATERNARY_TDM_TX + 0x04)
+#define AFE_PORT_ID_QUATERNARY_TDM_TX_3 \
+ (AFE_PORT_ID_QUATERNARY_TDM_TX + 0x06)
+#define AFE_PORT_ID_QUATERNARY_TDM_TX_4 \
+ (AFE_PORT_ID_QUATERNARY_TDM_TX + 0x08)
+#define AFE_PORT_ID_QUATERNARY_TDM_TX_5 \
+ (AFE_PORT_ID_QUATERNARY_TDM_TX + 0x0A)
+#define AFE_PORT_ID_QUATERNARY_TDM_TX_6 \
+ (AFE_PORT_ID_QUATERNARY_TDM_TX + 0x0C)
+#define AFE_PORT_ID_QUATERNARY_TDM_TX_7 \
+ (AFE_PORT_ID_QUATERNARY_TDM_TX + 0x0E)
+
+#define AFE_PORT_ID_QUINARY_TDM_RX \
+ (AFE_PORT_ID_TDM_PORT_RANGE_START + 0x40)
+#define AFE_PORT_ID_QUINARY_TDM_RX_1 \
+ (AFE_PORT_ID_QUINARY_TDM_RX + 0x02)
+#define AFE_PORT_ID_QUINARY_TDM_RX_2 \
+ (AFE_PORT_ID_QUINARY_TDM_RX + 0x04)
+#define AFE_PORT_ID_QUINARY_TDM_RX_3 \
+ (AFE_PORT_ID_QUINARY_TDM_RX + 0x06)
+#define AFE_PORT_ID_QUINARY_TDM_RX_4 \
+ (AFE_PORT_ID_QUINARY_TDM_RX + 0x08)
+#define AFE_PORT_ID_QUINARY_TDM_RX_5 \
+ (AFE_PORT_ID_QUINARY_TDM_RX + 0x0A)
+#define AFE_PORT_ID_QUINARY_TDM_RX_6 \
+ (AFE_PORT_ID_QUINARY_TDM_RX + 0x0C)
+#define AFE_PORT_ID_QUINARY_TDM_RX_7 \
+ (AFE_PORT_ID_QUINARY_TDM_RX + 0x0E)
+
+#define AFE_PORT_ID_QUINARY_TDM_TX \
+ (AFE_PORT_ID_TDM_PORT_RANGE_START + 0x41)
+#define AFE_PORT_ID_QUINARY_TDM_TX_1 \
+ (AFE_PORT_ID_QUINARY_TDM_TX + 0x02)
+#define AFE_PORT_ID_QUINARY_TDM_TX_2 \
+ (AFE_PORT_ID_QUINARY_TDM_TX + 0x04)
+#define AFE_PORT_ID_QUINARY_TDM_TX_3 \
+ (AFE_PORT_ID_QUINARY_TDM_TX + 0x06)
+#define AFE_PORT_ID_QUINARY_TDM_TX_4 \
+ (AFE_PORT_ID_QUINARY_TDM_TX + 0x08)
+#define AFE_PORT_ID_QUINARY_TDM_TX_5 \
+ (AFE_PORT_ID_QUINARY_TDM_TX + 0x0A)
+#define AFE_PORT_ID_QUINARY_TDM_TX_6 \
+ (AFE_PORT_ID_QUINARY_TDM_TX + 0x0C)
+#define AFE_PORT_ID_QUINARY_TDM_TX_7 \
+ (AFE_PORT_ID_QUINARY_TDM_TX + 0x0E)
+
#define Q6AFE_LPASS_MODE_CLK1_VALID 1
#define Q6AFE_LPASS_MODE_CLK2_VALID 2
#define Q6AFE_LPASS_CLK_SRC_INTERNAL 1
#define Q6AFE_LPASS_CLK_ROOT_DEFAULT 0
+#define AFE_API_VERSION_TDM_CONFIG 1
+#define AFE_API_VERSION_SLOT_MAPPING_CONFIG 1
#define TIMEOUT_MS 1000
#define AFE_CMD_RESP_AVAIL 0
@@ -245,10 +432,27 @@ struct afe_param_id_i2s_cfg {
u16 reserved;
} __packed;
+struct afe_param_id_tdm_cfg {
+ u32 tdm_cfg_minor_version;
+ u32 num_channels;
+ u32 sample_rate;
+ u32 bit_width;
+ u16 data_format;
+ u16 sync_mode;
+ u16 sync_src;
+ u16 nslots_per_frame;
+ u16 ctrl_data_out_enable;
+ u16 ctrl_invert_sync_pulse;
+ u16 ctrl_sync_data_delay;
+ u16 slot_width;
+ u32 slot_mask;
+} __packed;
+
union afe_port_config {
struct afe_param_id_hdmi_multi_chan_audio_cfg hdmi_multi_ch;
struct afe_param_id_slimbus_cfg slim_cfg;
struct afe_param_id_i2s_cfg i2s_cfg;
+ struct afe_param_id_tdm_cfg tdm_cfg;
} __packed;
@@ -261,9 +465,18 @@ struct afe_clk_set {
uint32_t enable;
};
+struct afe_param_id_slot_mapping_cfg {
+ u32 minor_version;
+ u16 num_channels;
+ u16 bitwidth;
+ u32 data_align_type;
+ u16 ch_mapping[AFE_PORT_MAX_AUDIO_CHAN_CNT];
+} __packed;
+
struct q6afe_port {
wait_queue_head_t wait;
union afe_port_config port_cfg;
+ struct afe_param_id_slot_mapping_cfg *scfg;
struct aprv2_ibasic_rsp_result_t result;
int token;
int id;
@@ -318,6 +531,166 @@ static struct afe_port_map port_maps[AFE_PORT_MAX] = {
QUATERNARY_MI2S_RX, 1, 1},
[QUATERNARY_MI2S_TX] = { AFE_PORT_ID_QUATERNARY_MI2S_TX,
QUATERNARY_MI2S_TX, 0, 1},
+ [PRIMARY_TDM_RX_0] = { AFE_PORT_ID_PRIMARY_TDM_RX,
+ PRIMARY_TDM_RX_0, 1, 1},
+ [PRIMARY_TDM_TX_0] = { AFE_PORT_ID_PRIMARY_TDM_TX,
+ PRIMARY_TDM_TX_0, 0, 1},
+ [PRIMARY_TDM_RX_1] = { AFE_PORT_ID_PRIMARY_TDM_RX_1,
+ PRIMARY_TDM_RX_1, 1, 1},
+ [PRIMARY_TDM_TX_1] = { AFE_PORT_ID_PRIMARY_TDM_TX_1,
+ PRIMARY_TDM_TX_1, 0, 1},
+ [PRIMARY_TDM_RX_2] = { AFE_PORT_ID_PRIMARY_TDM_RX_2,
+ PRIMARY_TDM_RX_2, 1, 1},
+ [PRIMARY_TDM_TX_2] = { AFE_PORT_ID_PRIMARY_TDM_TX_2,
+ PRIMARY_TDM_TX_2, 0, 1},
+ [PRIMARY_TDM_RX_3] = { AFE_PORT_ID_PRIMARY_TDM_RX_3,
+ PRIMARY_TDM_RX_3, 1, 1},
+ [PRIMARY_TDM_TX_3] = { AFE_PORT_ID_PRIMARY_TDM_TX_3,
+ PRIMARY_TDM_TX_3, 0, 1},
+ [PRIMARY_TDM_RX_4] = { AFE_PORT_ID_PRIMARY_TDM_RX_4,
+ PRIMARY_TDM_RX_4, 1, 1},
+ [PRIMARY_TDM_TX_4] = { AFE_PORT_ID_PRIMARY_TDM_TX_4,
+ PRIMARY_TDM_TX_4, 0, 1},
+ [PRIMARY_TDM_RX_5] = { AFE_PORT_ID_PRIMARY_TDM_RX_5,
+ PRIMARY_TDM_RX_5, 1, 1},
+ [PRIMARY_TDM_TX_5] = { AFE_PORT_ID_PRIMARY_TDM_TX_5,
+ PRIMARY_TDM_TX_5, 0, 1},
+ [PRIMARY_TDM_RX_6] = { AFE_PORT_ID_PRIMARY_TDM_RX_6,
+ PRIMARY_TDM_RX_6, 1, 1},
+ [PRIMARY_TDM_TX_6] = { AFE_PORT_ID_PRIMARY_TDM_TX_6,
+ PRIMARY_TDM_TX_6, 0, 1},
+ [PRIMARY_TDM_RX_7] = { AFE_PORT_ID_PRIMARY_TDM_RX_7,
+ PRIMARY_TDM_RX_7, 1, 1},
+ [PRIMARY_TDM_TX_7] = { AFE_PORT_ID_PRIMARY_TDM_TX_7,
+ PRIMARY_TDM_TX_7, 0, 1},
+ [SECONDARY_TDM_RX_0] = { AFE_PORT_ID_SECONDARY_TDM_RX,
+ SECONDARY_TDM_RX_0, 1, 1},
+ [SECONDARY_TDM_TX_0] = { AFE_PORT_ID_SECONDARY_TDM_TX,
+ SECONDARY_TDM_TX_0, 0, 1},
+ [SECONDARY_TDM_RX_1] = { AFE_PORT_ID_SECONDARY_TDM_RX_1,
+ SECONDARY_TDM_RX_1, 1, 1},
+ [SECONDARY_TDM_TX_1] = { AFE_PORT_ID_SECONDARY_TDM_TX_1,
+ SECONDARY_TDM_TX_1, 0, 1},
+ [SECONDARY_TDM_RX_2] = { AFE_PORT_ID_SECONDARY_TDM_RX_2,
+ SECONDARY_TDM_RX_2, 1, 1},
+ [SECONDARY_TDM_TX_2] = { AFE_PORT_ID_SECONDARY_TDM_TX_2,
+ SECONDARY_TDM_TX_2, 0, 1},
+ [SECONDARY_TDM_RX_3] = { AFE_PORT_ID_SECONDARY_TDM_RX_3,
+ SECONDARY_TDM_RX_3, 1, 1},
+ [SECONDARY_TDM_TX_3] = { AFE_PORT_ID_SECONDARY_TDM_TX_3,
+ SECONDARY_TDM_TX_3, 0, 1},
+ [SECONDARY_TDM_RX_4] = { AFE_PORT_ID_SECONDARY_TDM_RX_4,
+ SECONDARY_TDM_RX_4, 1, 1},
+ [SECONDARY_TDM_TX_4] = { AFE_PORT_ID_SECONDARY_TDM_TX_4,
+ SECONDARY_TDM_TX_4, 0, 1},
+ [SECONDARY_TDM_RX_5] = { AFE_PORT_ID_SECONDARY_TDM_RX_5,
+ SECONDARY_TDM_RX_5, 1, 1},
+ [SECONDARY_TDM_TX_5] = { AFE_PORT_ID_SECONDARY_TDM_TX_5,
+ SECONDARY_TDM_TX_5, 0, 1},
+ [SECONDARY_TDM_RX_6] = { AFE_PORT_ID_SECONDARY_TDM_RX_6,
+ SECONDARY_TDM_RX_6, 1, 1},
+ [SECONDARY_TDM_TX_6] = { AFE_PORT_ID_SECONDARY_TDM_TX_6,
+ SECONDARY_TDM_TX_6, 0, 1},
+ [SECONDARY_TDM_RX_7] = { AFE_PORT_ID_SECONDARY_TDM_RX_7,
+ SECONDARY_TDM_RX_7, 1, 1},
+ [SECONDARY_TDM_TX_7] = { AFE_PORT_ID_SECONDARY_TDM_TX_7,
+ SECONDARY_TDM_TX_7, 0, 1},
+ [TERTIARY_TDM_RX_0] = { AFE_PORT_ID_TERTIARY_TDM_RX,
+ TERTIARY_TDM_RX_0, 1, 1},
+ [TERTIARY_TDM_TX_0] = { AFE_PORT_ID_TERTIARY_TDM_TX,
+ TERTIARY_TDM_TX_0, 0, 1},
+ [TERTIARY_TDM_RX_1] = { AFE_PORT_ID_TERTIARY_TDM_RX_1,
+ TERTIARY_TDM_RX_1, 1, 1},
+ [TERTIARY_TDM_TX_1] = { AFE_PORT_ID_TERTIARY_TDM_TX_1,
+ TERTIARY_TDM_TX_1, 0, 1},
+ [TERTIARY_TDM_RX_2] = { AFE_PORT_ID_TERTIARY_TDM_RX_2,
+ TERTIARY_TDM_RX_2, 1, 1},
+ [TERTIARY_TDM_TX_2] = { AFE_PORT_ID_TERTIARY_TDM_TX_2,
+ TERTIARY_TDM_TX_2, 0, 1},
+ [TERTIARY_TDM_RX_3] = { AFE_PORT_ID_TERTIARY_TDM_RX_3,
+ TERTIARY_TDM_RX_3, 1, 1},
+ [TERTIARY_TDM_TX_3] = { AFE_PORT_ID_TERTIARY_TDM_TX_3,
+ TERTIARY_TDM_TX_3, 0, 1},
+ [TERTIARY_TDM_RX_4] = { AFE_PORT_ID_TERTIARY_TDM_RX_4,
+ TERTIARY_TDM_RX_4, 1, 1},
+ [TERTIARY_TDM_TX_4] = { AFE_PORT_ID_TERTIARY_TDM_TX_4,
+ TERTIARY_TDM_TX_4, 0, 1},
+ [TERTIARY_TDM_RX_5] = { AFE_PORT_ID_TERTIARY_TDM_RX_5,
+ TERTIARY_TDM_RX_5, 1, 1},
+ [TERTIARY_TDM_TX_5] = { AFE_PORT_ID_TERTIARY_TDM_TX_5,
+ TERTIARY_TDM_TX_5, 0, 1},
+ [TERTIARY_TDM_RX_6] = { AFE_PORT_ID_TERTIARY_TDM_RX_6,
+ TERTIARY_TDM_RX_6, 1, 1},
+ [TERTIARY_TDM_TX_6] = { AFE_PORT_ID_TERTIARY_TDM_TX_6,
+ TERTIARY_TDM_TX_6, 0, 1},
+ [TERTIARY_TDM_RX_7] = { AFE_PORT_ID_TERTIARY_TDM_RX_7,
+ TERTIARY_TDM_RX_7, 1, 1},
+ [TERTIARY_TDM_TX_7] = { AFE_PORT_ID_TERTIARY_TDM_TX_7,
+ TERTIARY_TDM_TX_7, 0, 1},
+ [QUATERNARY_TDM_RX_0] = { AFE_PORT_ID_QUATERNARY_TDM_RX,
+ QUATERNARY_TDM_RX_0, 1, 1},
+ [QUATERNARY_TDM_TX_0] = { AFE_PORT_ID_QUATERNARY_TDM_TX,
+ QUATERNARY_TDM_TX_0, 0, 1},
+ [QUATERNARY_TDM_RX_1] = { AFE_PORT_ID_QUATERNARY_TDM_RX_1,
+ QUATERNARY_TDM_RX_1, 1, 1},
+ [QUATERNARY_TDM_TX_1] = { AFE_PORT_ID_QUATERNARY_TDM_TX_1,
+ QUATERNARY_TDM_TX_1, 0, 1},
+ [QUATERNARY_TDM_RX_2] = { AFE_PORT_ID_QUATERNARY_TDM_RX_2,
+ QUATERNARY_TDM_RX_2, 1, 1},
+ [QUATERNARY_TDM_TX_2] = { AFE_PORT_ID_QUATERNARY_TDM_TX_2,
+ QUATERNARY_TDM_TX_2, 0, 1},
+ [QUATERNARY_TDM_RX_3] = { AFE_PORT_ID_QUATERNARY_TDM_RX_3,
+ QUATERNARY_TDM_RX_3, 1, 1},
+ [QUATERNARY_TDM_TX_3] = { AFE_PORT_ID_QUATERNARY_TDM_TX_3,
+ QUATERNARY_TDM_TX_3, 0, 1},
+ [QUATERNARY_TDM_RX_4] = { AFE_PORT_ID_QUATERNARY_TDM_RX_4,
+ QUATERNARY_TDM_RX_4, 1, 1},
+ [QUATERNARY_TDM_TX_4] = { AFE_PORT_ID_QUATERNARY_TDM_TX_4,
+ QUATERNARY_TDM_TX_4, 0, 1},
+ [QUATERNARY_TDM_RX_5] = { AFE_PORT_ID_QUATERNARY_TDM_RX_5,
+ QUATERNARY_TDM_RX_5, 1, 1},
+ [QUATERNARY_TDM_TX_5] = { AFE_PORT_ID_QUATERNARY_TDM_TX_5,
+ QUATERNARY_TDM_TX_5, 0, 1},
+ [QUATERNARY_TDM_RX_6] = { AFE_PORT_ID_QUATERNARY_TDM_RX_6,
+ QUATERNARY_TDM_RX_6, 1, 1},
+ [QUATERNARY_TDM_TX_6] = { AFE_PORT_ID_QUATERNARY_TDM_TX_6,
+ QUATERNARY_TDM_TX_6, 0, 1},
+ [QUATERNARY_TDM_RX_7] = { AFE_PORT_ID_QUATERNARY_TDM_RX_7,
+ QUATERNARY_TDM_RX_7, 1, 1},
+ [QUATERNARY_TDM_TX_7] = { AFE_PORT_ID_QUATERNARY_TDM_TX_7,
+ QUATERNARY_TDM_TX_7, 0, 1},
+ [QUINARY_TDM_RX_0] = { AFE_PORT_ID_QUINARY_TDM_RX,
+ QUINARY_TDM_RX_0, 1, 1},
+ [QUINARY_TDM_TX_0] = { AFE_PORT_ID_QUINARY_TDM_TX,
+ QUINARY_TDM_TX_0, 0, 1},
+ [QUINARY_TDM_RX_1] = { AFE_PORT_ID_QUINARY_TDM_RX_1,
+ QUINARY_TDM_RX_1, 1, 1},
+ [QUINARY_TDM_TX_1] = { AFE_PORT_ID_QUINARY_TDM_TX_1,
+ QUINARY_TDM_TX_1, 0, 1},
+ [QUINARY_TDM_RX_2] = { AFE_PORT_ID_QUINARY_TDM_RX_2,
+ QUINARY_TDM_RX_2, 1, 1},
+ [QUINARY_TDM_TX_2] = { AFE_PORT_ID_QUINARY_TDM_TX_2,
+ QUINARY_TDM_TX_2, 0, 1},
+ [QUINARY_TDM_RX_3] = { AFE_PORT_ID_QUINARY_TDM_RX_3,
+ QUINARY_TDM_RX_3, 1, 1},
+ [QUINARY_TDM_TX_3] = { AFE_PORT_ID_QUINARY_TDM_TX_3,
+ QUINARY_TDM_TX_3, 0, 1},
+ [QUINARY_TDM_RX_4] = { AFE_PORT_ID_QUINARY_TDM_RX_4,
+ QUINARY_TDM_RX_4, 1, 1},
+ [QUINARY_TDM_TX_4] = { AFE_PORT_ID_QUINARY_TDM_TX_4,
+ QUINARY_TDM_TX_4, 0, 1},
+ [QUINARY_TDM_RX_5] = { AFE_PORT_ID_QUINARY_TDM_RX_5,
+ QUINARY_TDM_RX_5, 1, 1},
+ [QUINARY_TDM_TX_5] = { AFE_PORT_ID_QUINARY_TDM_TX_5,
+ QUINARY_TDM_TX_5, 0, 1},
+ [QUINARY_TDM_RX_6] = { AFE_PORT_ID_QUINARY_TDM_RX_6,
+ QUINARY_TDM_RX_6, 1, 1},
+ [QUINARY_TDM_TX_6] = { AFE_PORT_ID_QUINARY_TDM_TX_6,
+ QUINARY_TDM_TX_6, 0, 1},
+ [QUINARY_TDM_RX_7] = { AFE_PORT_ID_QUINARY_TDM_RX_7,
+ QUINARY_TDM_RX_7, 1, 1},
+ [QUINARY_TDM_TX_7] = { AFE_PORT_ID_QUINARY_TDM_TX_7,
+ QUINARY_TDM_TX_7, 0, 1},
};
static void q6afe_port_free(struct kref *ref)
@@ -331,6 +704,7 @@ static void q6afe_port_free(struct kref *ref)
spin_lock_irqsave(&afe->port_list_lock, flags);
list_del(&port->node);
spin_unlock_irqrestore(&afe->port_list_lock, flags);
+ kfree(port->scfg);
kfree(port);
}
@@ -601,7 +975,9 @@ int q6afe_port_set_sysclk(struct q6afe_port *port, int clk_id,
ccfg.clk_set_mode = Q6AFE_LPASS_MODE_CLK2_VALID;
ret = q6afe_set_lpass_clock(port, &ccfg);
break;
- case Q6AFE_LPASS_CLK_ID_PRI_MI2S_IBIT ... Q6AFE_LPASS_CLK_ID_INT_MCLK_1:
+ case Q6AFE_LPASS_CLK_ID_PRI_MI2S_IBIT ... Q6AFE_LPASS_CLK_ID_QUI_MI2S_OSR:
+ case Q6AFE_LPASS_CLK_ID_MCLK_1 ... Q6AFE_LPASS_CLK_ID_INT_MCLK_1:
+ case Q6AFE_LPASS_CLK_ID_PRI_TDM_IBIT ... Q6AFE_LPASS_CLK_ID_QUIN_TDM_EBIT:
cset.clk_set_minor_version = AFE_API_VERSION_CLOCK_SET;
cset.clk_id = clk_id;
cset.clk_freq_in_hz = freq;
@@ -696,6 +1072,42 @@ void q6afe_slim_port_prepare(struct q6afe_port *port,
}
EXPORT_SYMBOL_GPL(q6afe_slim_port_prepare);
+/**
+ * q6afe_tdm_port_prepare() - Prepare tdm afe port.
+ *
+ * @port: Instance of afe port
+ * @cfg: TDM configuration for the afe port
+ *
+ */
+void q6afe_tdm_port_prepare(struct q6afe_port *port,
+ struct q6afe_tdm_cfg *cfg)
+{
+ union afe_port_config *pcfg = &port->port_cfg;
+
+ pcfg->tdm_cfg.tdm_cfg_minor_version = AFE_API_VERSION_TDM_CONFIG;
+ pcfg->tdm_cfg.num_channels = cfg->num_channels;
+ pcfg->tdm_cfg.sample_rate = cfg->sample_rate;
+ pcfg->tdm_cfg.bit_width = cfg->bit_width;
+ pcfg->tdm_cfg.data_format = cfg->data_format;
+ pcfg->tdm_cfg.sync_mode = cfg->sync_mode;
+ pcfg->tdm_cfg.sync_src = cfg->sync_src;
+ pcfg->tdm_cfg.nslots_per_frame = cfg->nslots_per_frame;
+
+ pcfg->tdm_cfg.slot_width = cfg->slot_width;
+ pcfg->tdm_cfg.slot_mask = cfg->slot_mask;
+ port->scfg = kzalloc(sizeof(*port->scfg), GFP_KERNEL);
+ if (!port->scfg)
+ return;
+
+ port->scfg->minor_version = AFE_API_VERSION_SLOT_MAPPING_CONFIG;
+ port->scfg->num_channels = cfg->num_channels;
+ port->scfg->bitwidth = cfg->bit_width;
+ port->scfg->data_align_type = cfg->data_align_type;
+ memcpy(port->scfg->ch_mapping, cfg->ch_mapping,
+ sizeof(u16) * AFE_PORT_MAX_AUDIO_CHAN_CNT);
+}
+EXPORT_SYMBOL_GPL(q6afe_tdm_port_prepare);
+
/**
* q6afe_hdmi_port_prepare() - Prepare hdmi afe port.
*
@@ -886,6 +1298,17 @@ int q6afe_port_start(struct q6afe_port *port)
return ret;
}
+ if (port->scfg) {
+ ret = q6afe_port_set_param_v2(port, port->scfg,
+ AFE_PARAM_ID_PORT_SLOT_MAPPING_CONFIG,
+ AFE_MODULE_TDM, sizeof(*port->scfg));
+ if (ret) {
+ dev_err(afe->dev, "AFE enable for port 0x%x failed %d\n",
+ port_id, ret);
+ return ret;
+ }
+ }
+
pkt_size = APR_HDR_SIZE + sizeof(*start);
p = kzalloc(pkt_size, GFP_KERNEL);
if (!p)
@@ -970,6 +1393,10 @@ struct q6afe_port *q6afe_port_get_from_id(struct device *dev, int id)
case AFE_PORT_ID_QUATERNARY_MI2S_TX:
cfg_type = AFE_PARAM_ID_I2S_CONFIG;
break;
+ case AFE_PORT_ID_PRIMARY_TDM_RX ... AFE_PORT_ID_QUINARY_TDM_TX_7:
+ cfg_type = AFE_PARAM_ID_TDM_CONFIG;
+ break;
+
default:
dev_err(dev, "Invalid port id 0x%x\n", port_id);
return ERR_PTR(-EINVAL);
diff --git a/sound/soc/qcom/qdsp6/q6afe.h b/sound/soc/qcom/qdsp6/q6afe.h
index 5ca54a9bdfd5..c7ed5422baff 100644
--- a/sound/soc/qcom/qdsp6/q6afe.h
+++ b/sound/soc/qcom/qdsp6/q6afe.h
@@ -5,7 +5,7 @@
#include <dt-bindings/sound/qcom,q6afe.h>
-#define AFE_PORT_MAX 48
+#define AFE_PORT_MAX 105
#define MSM_AFE_PORT_TYPE_RX 0
#define MSM_AFE_PORT_TYPE_TX 1
@@ -144,6 +144,8 @@
/* Clock attribute for invert and no couple case */
#define Q6AFE_LPASS_CLK_ATTRIBUTE_INVERT_COUPLE_NO 0x4
+#define Q6AFE_CMAP_INVALID 0xFFFF
+
struct q6afe_hdmi_cfg {
u16 datatype;
u16 channel_allocation;
@@ -168,10 +170,25 @@ struct q6afe_i2s_cfg {
int fmt;
};
+struct q6afe_tdm_cfg {
+ u16 num_channels;
+ u32 sample_rate;
+ u16 bit_width;
+ u16 data_format;
+ u16 sync_mode;
+ u16 sync_src;
+ u16 nslots_per_frame;
+ u16 slot_width;
+ u16 slot_mask;
+ u32 data_align_type;
+ u16 ch_mapping[AFE_MAX_CHAN_COUNT];
+};
+
struct q6afe_port_config {
struct q6afe_hdmi_cfg hdmi;
struct q6afe_slim_cfg slim;
struct q6afe_i2s_cfg i2s_cfg;
+ struct q6afe_tdm_cfg tdm;
};
struct q6afe_port;
@@ -186,6 +203,7 @@ void q6afe_hdmi_port_prepare(struct q6afe_port *port,
void q6afe_slim_port_prepare(struct q6afe_port *port,
struct q6afe_slim_cfg *cfg);
int q6afe_i2s_port_prepare(struct q6afe_port *port, struct q6afe_i2s_cfg *cfg);
+void q6afe_tdm_port_prepare(struct q6afe_port *port, struct q6afe_tdm_cfg *cfg);
int q6afe_port_set_sysclk(struct q6afe_port *port, int clk_id,
int clk_src, int clk_root,
--
2.16.2
^ permalink raw reply related
* [PATCH 1/6] ASoC: qdsp6: dt-bindings: Add q6afe tdm dt binding
From: Srinivas Kandagatla @ 2018-05-29 10:18 UTC (permalink / raw)
To: broonie, linux-arm-msm, alsa-devel, robh+dt, bgoswami
Cc: mark.rutland, devicetree, rohkumar, linux-kernel, plai, tiwai,
lgirdwood, Srinivas Kandagatla, spatakok, linux-arm-kernel
In-Reply-To: <20180529101833.30489-1-srinivas.kandagatla@linaro.org>
This patch adds bindings required for TDM ports on AFE.
Signed-off-by: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
---
.../devicetree/bindings/sound/qcom,q6afe.txt | 68 ++++++++++++++++++
include/dt-bindings/sound/qcom,q6afe.h | 80 ++++++++++++++++++++++
2 files changed, 148 insertions(+)
diff --git a/Documentation/devicetree/bindings/sound/qcom,q6afe.txt b/Documentation/devicetree/bindings/sound/qcom,q6afe.txt
index 14335a08b963..bdbf87df8c0b 100644
--- a/Documentation/devicetree/bindings/sound/qcom,q6afe.txt
+++ b/Documentation/devicetree/bindings/sound/qcom,q6afe.txt
@@ -46,6 +46,53 @@ configuration of each dai. Must contain the following properties.
Definition: Must be list of serial data lines used by this dai.
should be one or more of the 1-4 sd lines.
+ - qcom,tdm-sync-mode:
+ Usage: required for tdm interface
+ Value type: <prop-encoded-array>
+ Definition: Synchronization mode.
+ 0 - Short sync bit mode
+ 1 - Long sync mode
+ 2 - Short sync slot mode
+
+ - qcom,tdm-sync-src:
+ Usage: required for tdm interface
+ Value type: <prop-encoded-array>
+ Definition: Synchronization source.
+ 0 - External source
+ 1 - Internal source
+
+ - qcom,tdm-data-out:
+ Usage: required for tdm interface
+ Value type: <prop-encoded-array>
+ Definition: Data out signal to drive with other masters.
+ 0 - Disable
+ 1 - Enable
+
+ - qcom,tdm-invert-sync:
+ Usage: required for tdm interface
+ Value type: <prop-encoded-array>
+ Definition: Invert the sync.
+ 0 - Normal
+ 1 - Invert
+
+ - qcom,tdm-data-delay:
+ Usage: required for tdm interface
+ Value type: <prop-encoded-array>
+ Definition: Number of bit clock to delay data
+ with respect to sync edge.
+ 0 - 0 bit clock cycle
+ 1 - 1 bit clock cycle
+ 2 - 2 bit clock cycle
+
+ - qcom,tdm-data-align:
+ Usage: required for tdm interface
+ Value type: <prop-encoded-array>
+ Definition: Indicate how data is packed
+ within the slot. For example, 32 slot width in case of
+ sample bit width is 24.
+ 0 - MSB
+ 1 - LSB
+
= EXAMPLE
q6afe@4 {
@@ -61,6 +108,27 @@ q6afe@4 {
reg = <1>;
};
+ tdm@24 {
+ reg = <24>;
+ qcom,tdm-sync-mode = <1>:
+ qcom,tdm-sync-src = <1>;
+ qcom,tdm-data-out = <0>;
+ qcom,tdm-invert-sync = <1>;
+ qcom,tdm-data-delay = <1>;
+ qcom,tdm-data-align = <0>;
+
+ };
+
+ tdm@25 {
+ reg = <25>;
+ qcom,tdm-sync-mode = <1>:
+ qcom,tdm-sync-src = <1>;
+ qcom,tdm-data-out = <0>;
+ qcom,tdm-invert-sync = <1>;
+ qcom,tdm-data-delay <1>:
+ qcom,tdm-data-align = <0>;
+ };
+
prim-mi2s-rx@16 {
reg = <16>;
qcom,sd-lines = <1 3>;
diff --git a/include/dt-bindings/sound/qcom,q6afe.h b/include/dt-bindings/sound/qcom,q6afe.h
index e162045f5dc9..e2d3892240b8 100644
--- a/include/dt-bindings/sound/qcom,q6afe.h
+++ b/include/dt-bindings/sound/qcom,q6afe.h
@@ -26,6 +26,86 @@
#define TERTIARY_MI2S_TX 21
#define QUATERNARY_MI2S_RX 22
#define QUATERNARY_MI2S_TX 23
+#define PRIMARY_TDM_RX_0 24
+#define PRIMARY_TDM_TX_0 25
+#define PRIMARY_TDM_RX_1 26
+#define PRIMARY_TDM_TX_1 27
+#define PRIMARY_TDM_RX_2 28
+#define PRIMARY_TDM_TX_2 29
+#define PRIMARY_TDM_RX_3 30
+#define PRIMARY_TDM_TX_3 31
+#define PRIMARY_TDM_RX_4 32
+#define PRIMARY_TDM_TX_4 33
+#define PRIMARY_TDM_RX_5 34
+#define PRIMARY_TDM_TX_5 35
+#define PRIMARY_TDM_RX_6 36
+#define PRIMARY_TDM_TX_6 37
+#define PRIMARY_TDM_RX_7 38
+#define PRIMARY_TDM_TX_7 39
+#define SECONDARY_TDM_RX_0 40
+#define SECONDARY_TDM_TX_0 41
+#define SECONDARY_TDM_RX_1 42
+#define SECONDARY_TDM_TX_1 43
+#define SECONDARY_TDM_RX_2 44
+#define SECONDARY_TDM_TX_2 45
+#define SECONDARY_TDM_RX_3 46
+#define SECONDARY_TDM_TX_3 47
+#define SECONDARY_TDM_RX_4 48
+#define SECONDARY_TDM_TX_4 49
+#define SECONDARY_TDM_RX_5 50
+#define SECONDARY_TDM_TX_5 51
+#define SECONDARY_TDM_RX_6 52
+#define SECONDARY_TDM_TX_6 53
+#define SECONDARY_TDM_RX_7 54
+#define SECONDARY_TDM_TX_7 55
+#define TERTIARY_TDM_RX_0 56
+#define TERTIARY_TDM_TX_0 57
+#define TERTIARY_TDM_RX_1 58
+#define TERTIARY_TDM_TX_1 59
+#define TERTIARY_TDM_RX_2 60
+#define TERTIARY_TDM_TX_2 61
+#define TERTIARY_TDM_RX_3 62
+#define TERTIARY_TDM_TX_3 63
+#define TERTIARY_TDM_RX_4 64
+#define TERTIARY_TDM_TX_4 65
+#define TERTIARY_TDM_RX_5 66
+#define TERTIARY_TDM_TX_5 67
+#define TERTIARY_TDM_RX_6 68
+#define TERTIARY_TDM_TX_6 69
+#define TERTIARY_TDM_RX_7 70
+#define TERTIARY_TDM_TX_7 71
+#define QUATERNARY_TDM_RX_0 72
+#define QUATERNARY_TDM_TX_0 73
+#define QUATERNARY_TDM_RX_1 74
+#define QUATERNARY_TDM_TX_1 75
+#define QUATERNARY_TDM_RX_2 76
+#define QUATERNARY_TDM_TX_2 77
+#define QUATERNARY_TDM_RX_3 78
+#define QUATERNARY_TDM_TX_3 79
+#define QUATERNARY_TDM_RX_4 80
+#define QUATERNARY_TDM_TX_4 81
+#define QUATERNARY_TDM_RX_5 82
+#define QUATERNARY_TDM_TX_5 83
+#define QUATERNARY_TDM_RX_6 84
+#define QUATERNARY_TDM_TX_6 85
+#define QUATERNARY_TDM_RX_7 86
+#define QUATERNARY_TDM_TX_7 87
+#define QUINARY_TDM_RX_0 88
+#define QUINARY_TDM_TX_0 89
+#define QUINARY_TDM_RX_1 90
+#define QUINARY_TDM_TX_1 91
+#define QUINARY_TDM_RX_2 92
+#define QUINARY_TDM_TX_2 93
+#define QUINARY_TDM_RX_3 94
+#define QUINARY_TDM_TX_3 95
+#define QUINARY_TDM_RX_4 96
+#define QUINARY_TDM_TX_4 97
+#define QUINARY_TDM_RX_5 98
+#define QUINARY_TDM_TX_5 99
+#define QUINARY_TDM_RX_6 100
+#define QUINARY_TDM_TX_6 101
+#define QUINARY_TDM_RX_7 102
+#define QUINARY_TDM_TX_7 103
#endif /* __DT_BINDINGS_Q6_AFE_H__ */
--
2.16.2
^ permalink raw reply related
* [PATCH 0/6] ASoC: qdsp6: Add support to TDM ports
From: Srinivas Kandagatla @ 2018-05-29 10:18 UTC (permalink / raw)
To: broonie, linux-arm-msm, alsa-devel, robh+dt, bgoswami
Cc: mark.rutland, lgirdwood, plai, tiwai, perex, devicetree,
linux-kernel, linux-arm-kernel, rohkumar, spatakok,
Srinivas Kandagatla
This patchset adds supports to 40 TDM ports available in q6AFE module.
Among these 6 patches, there are 2 cleanup patches, first one which
makes i2s use common prepare function and the second one is add
macros for routings to make it easy to add new port routings.
Rest of the 4 patches are tdm dt-bindings, afe port prepare support
in afe, afe-dais support and adding tdm routing update.
These patches have been tested by Rohit on SDM845.
Thanks,
Srini
Srinivas Kandagatla (6):
ASoC: qdsp6: dt-bindings: Add q6afe tdm dt binding
ASoC: qdsp6: qdafe: add support to tdm ports
ASoC: qdsp6: q6afe-dai: use q6afe_dai_prepare() for MI2S
ASoC: qdsp6: q6afe-dai: add support to tdm dais
ASoC: qdsp6: q6routing: Add macros for mixers
ASoC: qdsp6: q6routing: Add support to all TDM Mixers
.../devicetree/bindings/sound/qcom,q6afe.txt | 68 ++
include/dt-bindings/sound/qcom,q6afe.h | 80 ++
sound/soc/qcom/qdsp6/q6afe-dai.c | 621 ++++++++++-
sound/soc/qcom/qdsp6/q6afe.c | 429 +++++++-
sound/soc/qcom/qdsp6/q6afe.h | 20 +-
sound/soc/qcom/qdsp6/q6routing.c | 1084 ++++++++++----------
6 files changed, 1733 insertions(+), 569 deletions(-)
--
2.16.2
^ permalink raw reply
* RE: [v5 1/6] dmaengine: fsldma: Replace DMA_IN/OUT by FSL_DMA_IN/OUT
From: Wen He @ 2018-05-29 10:14 UTC (permalink / raw)
To: Vinod
Cc: dmaengine@vger.kernel.org, robh+dt@kernel.org,
devicetree@vger.kernel.org, Leo Li, Jiafei Pan, Jiaheng Fan
In-Reply-To: <20180529044925.GD5666@vkoul-mobl>
> -----Original Message-----
> From: dmaengine-owner@vger.kernel.org
> [mailto:dmaengine-owner@vger.kernel.org] On Behalf Of Vinod
> Sent: 2018年5月29日 12:49
> To: Wen He <wen.he_1@nxp.com>
> Cc: dmaengine@vger.kernel.org; robh+dt@kernel.org;
> devicetree@vger.kernel.org; Leo Li <leoyang.li@nxp.com>; Jiafei Pan
> <jiafei.pan@nxp.com>; Jiaheng Fan <jiaheng.fan@nxp.com>
> Subject: Re: [v5 1/6] dmaengine: fsldma: Replace DMA_IN/OUT by
> FSL_DMA_IN/OUT
>
> On 25-05-18, 19:19, Wen He wrote:
> > This patch implenment a standard macro call functions is used to NXP
> > dma drivers.
>
> Well that patch seems to do a bit more than replace DMA_IN/OUT by
> FSL_DMA_IN/OUT care to explain those. best would be to do a patch which
> does replace and then add new things in separate patch, easier to review
>
What does means?
This also a patch.
Best Regards,
Wen
> --
> ~Vinod
> --
> To unsubscribe from this list: send the line "unsubscribe dmaengine" in the
> body of a message to majordomo@vger.kernel.org More majordomo info at
> https://emea01.safelinks.protection.outlook.com/?url=http%3A%2F%2Fvger.
> kernel.org%2Fmajordomo-info.html&data=02%7C01%7Cwen.he_1%40nxp.co
> m%7Cdacb8ef7648a4347203c08d5c51f907b%7C686ea1d3bc2b4c6fa92cd99
> c5c301635%7C0%7C0%7C636631661717012484&sdata=F4lY39RgFbR3707Vj
> DuCskaes3ppyu5kMD55wDjnCwk%3D&reserved=0
^ permalink raw reply
* [PATCH v2 6/9] PM / Domains: Don't attach devices in genpd with multi PM domains
From: Ulf Hansson @ 2018-05-29 10:04 UTC (permalink / raw)
To: Rafael J . Wysocki, linux-pm
Cc: Ulf Hansson, Greg Kroah-Hartman, Jon Hunter, Geert Uytterhoeven,
Todor Tomov, Rajendra Nayak, Viresh Kumar, Vincent Guittot,
Kevin Hilman, linux-kernel, linux-arm-kernel, linux-tegra,
Rob Herring, devicetree
In-Reply-To: <20180529100421.31022-1-ulf.hansson@linaro.org>
The power-domain DT property may now contain a list of PM domain
specifiers, which represents that a device are partitioned across multiple
PM domains. This leads to a new situation in genpd_dev_pm_attach(), as only
one PM domain can be attached per device.
To remain things simple for the most common configuration, when a single PM
domain is used, let's treat the multiple PM domain case as being specific.
In other words, let's change genpd_dev_pm_attach() to check for multiple PM
domains and prevent it from attach any PM domain for this case. Instead,
leave this to be managed separately, from following changes to genpd.
Cc: Rob Herring <robh+dt@kernel.org>
Cc: devicetree@vger.kernel.org
Suggested-by: Jon Hunter <jonathanh@nvidia.com>
Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org>
---
Changes in v2:
- Minor update to changelog to mention "PM domain specifiers" rather
than a "list of phandles".
---
drivers/base/power/domain.c | 18 +++++++++++++-----
1 file changed, 13 insertions(+), 5 deletions(-)
diff --git a/drivers/base/power/domain.c b/drivers/base/power/domain.c
index 7ebf7993273a..12a20f21974d 100644
--- a/drivers/base/power/domain.c
+++ b/drivers/base/power/domain.c
@@ -2229,10 +2229,10 @@ static void genpd_dev_pm_sync(struct device *dev)
* attaches the device to retrieved pm_domain ops.
*
* Returns 1 on successfully attached PM domain, 0 when the device don't need a
- * PM domain or a negative error code in case of failures. Note that if a
- * power-domain exists for the device, but it cannot be found or turned on,
- * then return -EPROBE_DEFER to ensure that the device is not probed and to
- * re-try again later.
+ * PM domain or when multiple power-domains exists for it, else a negative error
+ * code. Note that if a power-domain exists for the device, but it cannot be
+ * found or turned on, then return -EPROBE_DEFER to ensure that the device is
+ * not probed and to re-try again later.
*/
int genpd_dev_pm_attach(struct device *dev)
{
@@ -2243,10 +2243,18 @@ int genpd_dev_pm_attach(struct device *dev)
if (!dev->of_node)
return 0;
+ /*
+ * Devices with multiple PM domains must be attached separately, as we
+ * can only attach one PM domain per device.
+ */
+ if (of_count_phandle_with_args(dev->of_node, "power-domains",
+ "#power-domain-cells") != 1)
+ return 0;
+
ret = of_parse_phandle_with_args(dev->of_node, "power-domains",
"#power-domain-cells", 0, &pd_args);
if (ret < 0)
- return 0;
+ return ret;
mutex_lock(&gpd_list_lock);
pd = genpd_get_from_provider(&pd_args);
--
2.17.0
^ permalink raw reply related
* [PATCH v2 5/9] PM / Domains: dt: Allow power-domain property to be a list of specifiers
From: Ulf Hansson @ 2018-05-29 10:04 UTC (permalink / raw)
To: Rafael J . Wysocki, linux-pm
Cc: Ulf Hansson, Greg Kroah-Hartman, Jon Hunter, Geert Uytterhoeven,
Todor Tomov, Rajendra Nayak, Viresh Kumar, Vincent Guittot,
Kevin Hilman, linux-kernel, linux-arm-kernel, linux-tegra,
Rob Herring, devicetree
In-Reply-To: <20180529100421.31022-1-ulf.hansson@linaro.org>
To be able to describe topologies where devices are partitioned across
multiple power domains, let's extend the power-domain property to allow
being a list of PM domain specifiers.
Cc: Rob Herring <robh+dt@kernel.org>
Cc: devicetree@vger.kernel.org
Suggested-by: Jon Hunter <jonathanh@nvidia.com>
Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org>
---
Changes in v2:
- Fixed comments from Geert. Re-worded to "PM domain specifiers" and
clarified DT example.
---
.../bindings/power/power_domain.txt | 19 ++++++++++++++-----
1 file changed, 14 insertions(+), 5 deletions(-)
diff --git a/Documentation/devicetree/bindings/power/power_domain.txt b/Documentation/devicetree/bindings/power/power_domain.txt
index 4733f76cbe48..9b387f861aed 100644
--- a/Documentation/devicetree/bindings/power/power_domain.txt
+++ b/Documentation/devicetree/bindings/power/power_domain.txt
@@ -111,8 +111,8 @@ Example 3:
==PM domain consumers==
Required properties:
- - power-domains : A phandle and PM domain specifier as defined by bindings of
- the power controller specified by phandle.
+ - power-domains : A list of PM domain specifiers, as defined by bindings of
+ the power controller that is the PM domain provider.
Example:
@@ -122,9 +122,18 @@ Example:
power-domains = <&power 0>;
};
-The node above defines a typical PM domain consumer device, which is located
-inside a PM domain with index 0 of a power controller represented by a node
-with the label "power".
+ leaky-device@12351000 {
+ compatible = "foo,i-leak-current";
+ reg = <0x12351000 0x1000>;
+ power-domains = <&power 0>, <&power 1> ;
+ };
+
+The first example above defines a typical PM domain consumer device, which is
+located inside a PM domain with index 0 of a power controller represented by a
+node with the label "power".
+In the second example the consumer device are partitioned across two PM domains,
+the first with index 0 and the second with index 1, of a power controller that
+is represented by a node with the label "power.
Optional properties:
- required-opps: This contains phandle to an OPP node in another device's OPP
--
2.17.0
^ permalink raw reply related
* [PATCH v1 2/2] hwmon: npcm-pwm: add NPCM7xx PWM driver
From: Tomer Maimon @ 2018-05-29 10:02 UTC (permalink / raw)
To: robh+dt, mark.rutland, jdelvare, linux, avifishman70, yuenn,
brendanhiggins, venture, joel
Cc: devicetree, linux-kernel, linux-hwmon, openbmc, Tomer Maimon
In-Reply-To: <1527588141-18639-1-git-send-email-tmaimon77@gmail.com>
Add Nuvoton BMC NPCM7xx Pulse Width Modulation (PWM) driver.
The Nuvoton BMC NPCM7xx has two identical PWM controller modules,
each module has four PWM controller outputs.
Signed-off-by: Tomer Maimon <tmaimon77@gmail.com>
---
drivers/hwmon/Kconfig | 6 +
drivers/hwmon/Makefile | 1 +
drivers/hwmon/npcm7xx-pwm.c | 363 ++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 370 insertions(+)
create mode 100644 drivers/hwmon/npcm7xx-pwm.c
diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig
index 6ec307c93ece..693ba09cff8e 100644
--- a/drivers/hwmon/Kconfig
+++ b/drivers/hwmon/Kconfig
@@ -1891,6 +1891,12 @@ config SENSORS_XGENE
If you say yes here you get support for the temperature
and power sensors for APM X-Gene SoC.
+config SENSORS_NPCM7XX
+ tristate "Nuvoton NPCM7XX PWM driver"
+ help
+ This driver provides support for Nuvoton NPCM7XX PWM
+ controller.
+
if ACPI
comment "ACPI drivers"
diff --git a/drivers/hwmon/Makefile b/drivers/hwmon/Makefile
index e7d52a36e6c4..24aad895a3bb 100644
--- a/drivers/hwmon/Makefile
+++ b/drivers/hwmon/Makefile
@@ -174,6 +174,7 @@ obj-$(CONFIG_SENSORS_W83L786NG) += w83l786ng.o
obj-$(CONFIG_SENSORS_WM831X) += wm831x-hwmon.o
obj-$(CONFIG_SENSORS_WM8350) += wm8350-hwmon.o
obj-$(CONFIG_SENSORS_XGENE) += xgene-hwmon.o
+obj-$(CONFIG_SENSORS_NPCM7XX) += npcm7xx-pwm.o
obj-$(CONFIG_PMBUS) += pmbus/
diff --git a/drivers/hwmon/npcm7xx-pwm.c b/drivers/hwmon/npcm7xx-pwm.c
new file mode 100644
index 000000000000..6122ca82b94d
--- /dev/null
+++ b/drivers/hwmon/npcm7xx-pwm.c
@@ -0,0 +1,363 @@
+// SPDX-License-Identifier: GPL-2.0
+// Copyright (c) 2014-2018 Nuvoton Technology corporation.
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/device.h>
+#include <linux/clk.h>
+#include <linux/platform_device.h>
+#include <linux/hwmon.h>
+#include <linux/hwmon-sysfs.h>
+#include <linux/sysfs.h>
+#include <linux/of_irq.h>
+#include <linux/of_address.h>
+
+/* NPCM7XX PWM port base address */
+#define NPCM7XX_PWM_REG_PR 0x0
+#define NPCM7XX_PWM_REG_CSR 0x4
+#define NPCM7XX_PWM_REG_CR 0x8
+#define NPCM7XX_PWM_REG_CNRx(PORT) (0xC + (12 * PORT))
+#define NPCM7XX_PWM_REG_CMRx(PORT) (0x10 + (12 * PORT))
+#define NPCM7XX_PWM_REG_PDRx(PORT) (0x14 + (12 * PORT))
+#define NPCM7XX_PWM_REG_PIER 0x3C
+#define NPCM7XX_PWM_REG_PIIR 0x40
+
+#define NPCM7XX_PWM_CTRL_CH0_MODE_BIT BIT(3)
+#define NPCM7XX_PWM_CTRL_CH1_MODE_BIT BIT(11)
+#define NPCM7XX_PWM_CTRL_CH2_MODE_BIT BIT(15)
+#define NPCM7XX_PWM_CTRL_CH3_MODE_BIT BIT(19)
+
+#define NPCM7XX_PWM_CTRL_CH0_INV_BIT BIT(2)
+#define NPCM7XX_PWM_CTRL_CH1_INV_BIT BIT(10)
+#define NPCM7XX_PWM_CTRL_CH2_INV_BIT BIT(14)
+#define NPCM7XX_PWM_CTRL_CH3_INV_BIT BIT(18)
+
+#define NPCM7XX_PWM_CTRL_CH0_EN_BIT BIT(0)
+#define NPCM7XX_PWM_CTRL_CH1_EN_BIT BIT(8)
+#define NPCM7XX_PWM_CTRL_CH2_EN_BIT BIT(12)
+#define NPCM7XX_PWM_CTRL_CH3_EN_BIT BIT(16)
+
+/* Define the maximum PWM channel number */
+#define NPCM7XX_PWM_MAX_CHN_NUM 8
+#define NPCM7XX_PWM_MAX_CHN_NUM_IN_A_MODULE 4
+#define NPCM7XX_PWM_MAX_MODULES 2
+
+/* Define the Counter Register, value = 100 for match 100% */
+#define NPCM7XX_PWM_COUNTER_DEFALUT_NUM 255
+#define NPCM7XX_PWM_COMPARATOR_DEFALUT_NUM 127
+
+#define NPCM7XX_PWM_COMPARATOR_MAX 255
+
+
+/* default all PWM channels PRESCALE2 = 1 */
+#define NPCM7XX_PWM_PRESCALE2_DEFALUT_CH0 0x4
+#define NPCM7XX_PWM_PRESCALE2_DEFALUT_CH1 0x40
+#define NPCM7XX_PWM_PRESCALE2_DEFALUT_CH2 0x400
+#define NPCM7XX_PWM_PRESCALE2_DEFALUT_CH3 0x4000
+
+#define PWM_OUTPUT_FREQ_25KHZ 25000
+#define PWN_CNT_DEFAULT 256
+#define MIN_PRESCALE1 2
+#define NPCM7XX_PWM_PRESCALE_SHIFT_CH01 8
+
+#define NPCM7XX_PWM_PRESCALE2_DEFALUT (NPCM7XX_PWM_PRESCALE2_DEFALUT_CH0 | \
+ NPCM7XX_PWM_PRESCALE2_DEFALUT_CH1 | \
+ NPCM7XX_PWM_PRESCALE2_DEFALUT_CH2 | \
+ NPCM7XX_PWM_PRESCALE2_DEFALUT_CH3)
+
+#define NPCM7XX_PWM_CTRL_MODE_DEFALUT (NPCM7XX_PWM_CTRL_CH0_MODE_BIT | \
+ NPCM7XX_PWM_CTRL_CH1_MODE_BIT | \
+ NPCM7XX_PWM_CTRL_CH2_MODE_BIT | \
+ NPCM7XX_PWM_CTRL_CH3_MODE_BIT)
+
+#define NPCM7XX_PWM_CTRL_EN_DEFALUT (NPCM7XX_PWM_CTRL_CH0_EN_BIT | \
+ NPCM7XX_PWM_CTRL_CH1_EN_BIT | \
+ NPCM7XX_PWM_CTRL_CH2_EN_BIT | \
+ NPCM7XX_PWM_CTRL_CH3_EN_BIT)
+
+struct npcm7xx_pwm_data {
+ unsigned long clk_freq;
+ void __iomem *pwm_base[NPCM7XX_PWM_MAX_MODULES];
+ struct mutex npcm7xx_pwm_lock[NPCM7XX_PWM_MAX_CHN_NUM];
+};
+
+static const struct of_device_id pwm_dt_id[];
+
+static int npcm7xx_pwm_config_set(struct npcm7xx_pwm_data *data, int channel,
+ u16 val)
+{
+ u32 PWMChannel = (channel % NPCM7XX_PWM_MAX_CHN_NUM_IN_A_MODULE);
+ u32 n_module = (channel / NPCM7XX_PWM_MAX_CHN_NUM_IN_A_MODULE);
+ u32 u32TmpBuf = 0, ctrl_en_bit;
+
+ /*
+ * Config PWM Comparator register for setting duty cycle
+ */
+ if (val < 0 || val > NPCM7XX_PWM_COMPARATOR_MAX)
+ return -EINVAL;
+
+ /* write new CMR value */
+ iowrite32(val, data->pwm_base[n_module] +
+ NPCM7XX_PWM_REG_CMRx(PWMChannel));
+
+ u32TmpBuf = ioread32(data->pwm_base[n_module] + NPCM7XX_PWM_REG_CR);
+
+ switch (PWMChannel) {
+ case 0:
+ ctrl_en_bit = NPCM7XX_PWM_CTRL_CH0_EN_BIT;
+ break;
+ case 1:
+ ctrl_en_bit = NPCM7XX_PWM_CTRL_CH1_EN_BIT;
+ break;
+ case 2:
+ ctrl_en_bit = NPCM7XX_PWM_CTRL_CH2_EN_BIT;
+ break;
+ case 3:
+ ctrl_en_bit = NPCM7XX_PWM_CTRL_CH3_EN_BIT;
+ break;
+ default:
+ return -ENODEV;
+ }
+
+ if (val == 0)
+ /* Disable PWM */
+ u32TmpBuf &= ~(ctrl_en_bit);
+ else
+ /* Enable PWM */
+ u32TmpBuf |= ctrl_en_bit;
+
+ mutex_lock(&data->npcm7xx_pwm_lock[n_module]);
+ iowrite32(u32TmpBuf, data->pwm_base[n_module] + NPCM7XX_PWM_REG_CR);
+ mutex_unlock(&data->npcm7xx_pwm_lock[n_module]);
+
+ return 0;
+}
+
+static int npcm7xx_read_pwm(struct device *dev, u32 attr, int channel,
+ long *val)
+{
+ struct npcm7xx_pwm_data *data = dev_get_drvdata(dev);
+ u32 PWMChannel = (channel % NPCM7XX_PWM_MAX_CHN_NUM_IN_A_MODULE);
+ u32 n_module = (channel / NPCM7XX_PWM_MAX_CHN_NUM_IN_A_MODULE);
+
+ if (IS_ERR(data))
+ return PTR_ERR(data);
+
+ switch (attr) {
+ case hwmon_pwm_input:
+ *val = (long)ioread32(data->pwm_base[n_module] +
+ NPCM7XX_PWM_REG_CMRx(PWMChannel));
+ return 0;
+ default:
+ return -EOPNOTSUPP;
+ }
+}
+
+static int npcm7xx_write_pwm(struct device *dev, u32 attr, int channel,
+ long val)
+{
+ struct npcm7xx_pwm_data *data = dev_get_drvdata(dev);
+ int err = 0;
+
+ switch (attr) {
+ case hwmon_pwm_input:
+ err = npcm7xx_pwm_config_set(data, channel, (u16)val);
+ break;
+ default:
+ err = -EOPNOTSUPP;
+ break;
+ }
+
+ return err;
+}
+
+static umode_t npcm7xx_pwm_is_visible(const void *_data, u32 attr, int channel)
+{
+ switch (attr) {
+ case hwmon_pwm_input:
+ return 0644;
+ default:
+ return 0;
+ }
+}
+
+static int npcm7xx_read(struct device *dev, enum hwmon_sensor_types type,
+ u32 attr, int channel, long *val)
+{
+ switch (type) {
+ case hwmon_pwm:
+ return npcm7xx_read_pwm(dev, attr, channel, val);
+ default:
+ return -EOPNOTSUPP;
+ }
+}
+
+static int npcm7xx_write(struct device *dev, enum hwmon_sensor_types type,
+ u32 attr, int channel, long val)
+{
+ switch (type) {
+ case hwmon_pwm:
+ return npcm7xx_write_pwm(dev, attr, channel, val);
+ default:
+ return -EOPNOTSUPP;
+ }
+}
+
+static umode_t npcm7xx_is_visible(const void *data,
+ enum hwmon_sensor_types type,
+ u32 attr, int channel)
+{
+ switch (type) {
+ case hwmon_pwm:
+ return npcm7xx_pwm_is_visible(data, attr, channel);
+ default:
+ return 0;
+ }
+}
+
+static const u32 npcm7xx_pwm_config[] = {
+ HWMON_PWM_INPUT,
+ HWMON_PWM_INPUT,
+ HWMON_PWM_INPUT,
+ HWMON_PWM_INPUT,
+ HWMON_PWM_INPUT,
+ HWMON_PWM_INPUT,
+ HWMON_PWM_INPUT,
+ HWMON_PWM_INPUT,
+ 0
+};
+
+static const struct hwmon_channel_info npcm7xx_pwm = {
+ .type = hwmon_pwm,
+ .config = npcm7xx_pwm_config,
+};
+
+static const struct hwmon_channel_info *npcm7xx_info[] = {
+ &npcm7xx_pwm,
+ NULL
+};
+
+static const struct hwmon_ops npcm7xx_hwmon_ops = {
+ .is_visible = npcm7xx_is_visible,
+ .read = npcm7xx_read,
+ .write = npcm7xx_write,
+};
+
+static const struct hwmon_chip_info npcm7xx_chip_info = {
+ .ops = &npcm7xx_hwmon_ops,
+ .info = npcm7xx_info,
+};
+
+static int npcm7xx_pwm_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct npcm7xx_pwm_data *data;
+ struct resource res[NPCM7XX_PWM_MAX_MODULES];
+ struct device *hwmon;
+ struct clk *clk;
+ int m, ch, res_cnt, ret;
+ u32 Prescale_val, output_freq;
+
+ data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);
+ if (!data)
+ return -ENOMEM;
+
+ for (res_cnt = 0; res_cnt < NPCM7XX_PWM_MAX_MODULES ; res_cnt++) {
+ ret = of_address_to_resource(dev->of_node, res_cnt,
+ &res[res_cnt]);
+ if (ret) {
+ pr_err("PWM of_address_to_resource fail ret %d\n",
+ ret);
+ return -EINVAL;
+ }
+
+ data->pwm_base[res_cnt] =
+ devm_ioremap_resource(dev, &(res[res_cnt]));
+ pr_debug("pwm%d base is 0x%08X, res.start 0x%08X , size 0x%08X\n",
+ res_cnt, (u32)data->pwm_base[res_cnt],
+ res[res_cnt].start, resource_size(&(res[res_cnt])));
+
+ if (!data->pwm_base[res_cnt]) {
+ pr_err("pwm probe failed: can't read pwm base address for resource %d.\n",
+ res_cnt);
+ return -ENOMEM;
+ }
+
+ mutex_init(&data->npcm7xx_pwm_lock[res_cnt]);
+ }
+
+ clk = devm_clk_get(dev, NULL);
+ if (IS_ERR(clk))
+ return -ENODEV;
+
+ data->clk_freq = clk_get_rate(clk);
+
+ /* Adjust NPCM7xx PWMs output frequency to ~25Khz */
+ output_freq = data->clk_freq / PWN_CNT_DEFAULT;
+ Prescale_val = DIV_ROUND_CLOSEST(output_freq, PWM_OUTPUT_FREQ_25KHZ);
+
+ /* If Prescale_val = 0, then the prescale output clock is stopped */
+ if (Prescale_val < MIN_PRESCALE1)
+ Prescale_val = MIN_PRESCALE1;
+ /*
+ * Prescale_val need to decrement in one because in the PWM Prescale
+ * register the Prescale value increment by one
+ */
+ Prescale_val--;
+
+ /* Setting PWM Prescale Register value register to both modules */
+ Prescale_val |= (Prescale_val << NPCM7XX_PWM_PRESCALE_SHIFT_CH01);
+
+ for (m = 0; m < NPCM7XX_PWM_MAX_MODULES ; m++) {
+ iowrite32(Prescale_val,
+ data->pwm_base[m] + NPCM7XX_PWM_REG_PR);
+ iowrite32(NPCM7XX_PWM_PRESCALE2_DEFALUT,
+ data->pwm_base[m] + NPCM7XX_PWM_REG_CSR);
+ iowrite32(NPCM7XX_PWM_CTRL_MODE_DEFALUT,
+ data->pwm_base[m] + NPCM7XX_PWM_REG_CR);
+
+ for (ch = 0; ch < NPCM7XX_PWM_MAX_CHN_NUM; ch++) {
+ iowrite32(NPCM7XX_PWM_COUNTER_DEFALUT_NUM,
+ data->pwm_base[m] + NPCM7XX_PWM_REG_CNRx(ch));
+ iowrite32(NPCM7XX_PWM_COMPARATOR_DEFALUT_NUM,
+ data->pwm_base[m] + NPCM7XX_PWM_REG_CMRx(ch));
+ }
+
+ iowrite32(NPCM7XX_PWM_CTRL_MODE_DEFALUT |
+ NPCM7XX_PWM_CTRL_EN_DEFALUT,
+ data->pwm_base[m] + NPCM7XX_PWM_REG_CR);
+ }
+
+ hwmon = devm_hwmon_device_register_with_info(dev, "npcm7xx_pwm", data,
+ &npcm7xx_chip_info, NULL);
+
+ if (IS_ERR(hwmon)) {
+ pr_err("PWM Driver failed - devm_hwmon_device_register_with_groups failed\n");
+ return PTR_ERR(hwmon);
+ }
+
+ pr_info("NPCM7XX PWM Driver probed, PWM output Freq %dHz\n",
+ output_freq / ((Prescale_val & 0xf) + 1));
+
+ return 0;
+}
+
+static const struct of_device_id of_pwm_match_table[] = {
+ { .compatible = "nuvoton,npcm750-pwm", },
+ {},
+};
+MODULE_DEVICE_TABLE(of, of_pwm_match_table);
+
+static struct platform_driver npcm7xx_pwm_driver = {
+ .probe = npcm7xx_pwm_probe,
+ .driver = {
+ .name = "npcm7xx_pwm",
+ .of_match_table = of_pwm_match_table,
+ },
+};
+
+module_platform_driver(npcm7xx_pwm_driver);
+
+MODULE_DESCRIPTION("Nuvoton NPCM7XX PWM Driver");
+MODULE_AUTHOR("Tomer Maimon <tomer.maimon@nuvoton.com>");
+MODULE_LICENSE("GPL v2");
--
2.14.1
^ permalink raw reply related
* [PATCH v1 1/2] dt-binding: hwmon: Add NPCM7xx PWM documentation
From: Tomer Maimon @ 2018-05-29 10:02 UTC (permalink / raw)
To: robh+dt, mark.rutland, jdelvare, linux, avifishman70, yuenn,
brendanhiggins, venture, joel
Cc: devicetree, linux-kernel, linux-hwmon, openbmc, Tomer Maimon
In-Reply-To: <1527588141-18639-1-git-send-email-tmaimon77@gmail.com>
Added device tree binding documentation for Nuvoton BMC
NPCM7xx Pulse Width Modulation (PWM) controller.
Signed-off-by: Tomer Maimon <tmaimon77@gmail.com>
---
.../devicetree/bindings/hwmon/npcm7xx-pwm.txt | 25 ++++++++++++++++++++++
1 file changed, 25 insertions(+)
create mode 100644 Documentation/devicetree/bindings/hwmon/npcm7xx-pwm.txt
diff --git a/Documentation/devicetree/bindings/hwmon/npcm7xx-pwm.txt b/Documentation/devicetree/bindings/hwmon/npcm7xx-pwm.txt
new file mode 100644
index 000000000000..2d8a7ccdc8cf
--- /dev/null
+++ b/Documentation/devicetree/bindings/hwmon/npcm7xx-pwm.txt
@@ -0,0 +1,25 @@
+Nuvoton NPCM7xx Pulse-width modulation (PWM) controller device driver
+
+The NPCM7xx has two identical PWM controller modules,
+Each module has four PWM controller outputs.
+NPCM7xx PWM controller module 0 outputs PWM0-3 and NPCM7xx PWM controller
+module 1 outputs PWM4-7.
+
+Required properties:
+- compatible : "nuvoton,npcm750-pwm" for Poleg NPCM7XX.
+- reg : Offset and length of the registers set for the device.
+- clocks : phandle of pwm reference clock.
+- pinctrl-names : a pinctrl state named "default" must be defined.
+- pinctrl-0 : phandle referencing pin configuration of the PWM ports.
+
+pwm:pwm@f0103000 {
+ compatible = "nuvoton,npcm750-pwm";
+ reg = <0xf0103000 0x50
+ 0xf0104000 0x50>;
+ clocks = <&clk NPCM7XX_CLK_APB3>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&pwm0_pins &pwm1_pins
+ &pwm2_pins &pwm3_pins
+ &pwm4_pins &pwm5_pins
+ &pwm6_pins &pwm7_pins>;
+};
--
2.14.1
^ permalink raw reply related
* [PATCH v1 0/2] hwmon: Add NPCM7xx PWM driver support
From: Tomer Maimon @ 2018-05-29 10:02 UTC (permalink / raw)
To: robh+dt, mark.rutland, jdelvare, linux, avifishman70, yuenn,
brendanhiggins, venture, joel
Cc: devicetree, linux-kernel, linux-hwmon, openbmc, Tomer Maimon
This patch set adds Pulse Width Modulation (PWM) support
for the Nuvoton NPCM7xx Baseboard Management Controller (BMC).
The NPCM7xx PWM controller can support 8 PWM output ports.
The hwmon driver provides sysfs entries through which the user can
configure and get the duty cycle between 0 (disable the specific PWM)
to 255 of particular PWM output port.
The NPCM7xx PWM driver tested on NPCM750 evaluation board.
Tomer Maimon (2):
dt-binding: hwmon: Add NPCM7xx PWM documentation
hwmon: npcm-pwm: add NPCM7xx PWM driver
.../devicetree/bindings/hwmon/npcm7xx-pwm.txt | 25 ++
drivers/hwmon/Kconfig | 6 +
drivers/hwmon/Makefile | 1 +
drivers/hwmon/npcm7xx-pwm.c | 363 +++++++++++++++++++++
4 files changed, 395 insertions(+)
create mode 100644 Documentation/devicetree/bindings/hwmon/npcm7xx-pwm.txt
create mode 100644 drivers/hwmon/npcm7xx-pwm.c
--
2.14.1
^ permalink raw reply
* [PATCH v3 6/6] regulator: bd71837: BD71837 PMIC regulator driver
From: Matti Vaittinen @ 2018-05-29 10:02 UTC (permalink / raw)
To: mturquette, sboyd, robh+dt, mark.rutland, lee.jones, lgirdwood,
broonie, mazziesaccount
Cc: linux-clk, devicetree, linux-kernel, mikko.mutanen,
heikki.haikola
In-Reply-To: <cover.1527587295.git.matti.vaittinen@fi.rohmeurope.com>
Support for controlling the 8 bucks and 7 LDOs the PMIC contains.
Signed-off-by: Matti Vaittinen <matti.vaittinen@fi.rohmeurope.com>
---
drivers/regulator/Kconfig | 11 +
drivers/regulator/Makefile | 1 +
drivers/regulator/bd71837-regulator.c | 677 ++++++++++++++++++++++++++++++++++
3 files changed, 689 insertions(+)
create mode 100644 drivers/regulator/bd71837-regulator.c
diff --git a/drivers/regulator/Kconfig b/drivers/regulator/Kconfig
index 097f61784a7d..139f4b53fea0 100644
--- a/drivers/regulator/Kconfig
+++ b/drivers/regulator/Kconfig
@@ -180,6 +180,17 @@ config REGULATOR_BCM590XX
BCM590xx PMUs. This will enable support for the software
controllable LDO/Switching regulators.
+config REGULATOR_BD71837
+ tristate "ROHM BD71837 Power Regulator"
+ depends on MFD_BD71837
+ help
+ This driver supports voltage regulators on ROHM BD71837 PMIC.
+ This will enable support for the software controllable buck
+ and LDO regulators.
+
+ This driver can also be built as a module. If so, the module
+ will be called bd71837-regulator.
+
config REGULATOR_BD9571MWV
tristate "ROHM BD9571MWV Regulators"
depends on MFD_BD9571MWV
diff --git a/drivers/regulator/Makefile b/drivers/regulator/Makefile
index 590674fbecd7..1b4d8ec416c2 100644
--- a/drivers/regulator/Makefile
+++ b/drivers/regulator/Makefile
@@ -27,6 +27,7 @@ obj-$(CONFIG_REGULATOR_AS3711) += as3711-regulator.o
obj-$(CONFIG_REGULATOR_AS3722) += as3722-regulator.o
obj-$(CONFIG_REGULATOR_AXP20X) += axp20x-regulator.o
obj-$(CONFIG_REGULATOR_BCM590XX) += bcm590xx-regulator.o
+obj-$(CONFIG_REGULATOR_BD71837) += bd71837-regulator.o
obj-$(CONFIG_REGULATOR_BD9571MWV) += bd9571mwv-regulator.o
obj-$(CONFIG_REGULATOR_DA903X) += da903x.o
obj-$(CONFIG_REGULATOR_DA9052) += da9052-regulator.o
diff --git a/drivers/regulator/bd71837-regulator.c b/drivers/regulator/bd71837-regulator.c
new file mode 100644
index 000000000000..826c1ce3c6d6
--- /dev/null
+++ b/drivers/regulator/bd71837-regulator.c
@@ -0,0 +1,677 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Copyright (C) 2018 ROHM Semiconductors */
+/*
+ * bd71837-regulator.c ROHM BD71837MWV regulator driver
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/err.h>
+#include <linux/interrupt.h>
+#include <linux/platform_device.h>
+#include <linux/regulator/driver.h>
+#include <linux/regulator/machine.h>
+#include <linux/delay.h>
+#include <linux/slab.h>
+#include <linux/gpio.h>
+#include <linux/mfd/bd71837.h>
+#include <linux/regulator/of_regulator.h>
+
+struct bd71837_pmic {
+ struct regulator_desc descs[BD71837_REGULATOR_CNT];
+ struct bd71837 *mfd;
+ struct platform_device *pdev;
+ struct regulator_dev *rdev[BD71837_REGULATOR_CNT];
+ struct mutex mtx;
+};
+
+/*
+ * BUCK1/2/3/4
+ * BUCK1RAMPRATE[1:0] BUCK1 DVS ramp rate setting
+ * 00: 10.00mV/usec 10mV 1uS
+ * 01: 5.00mV/usec 10mV 2uS
+ * 10: 2.50mV/usec 10mV 4uS
+ * 11: 1.25mV/usec 10mV 8uS
+ */
+static int bd71837_buck1234_set_ramp_delay(struct regulator_dev *rdev,
+ int ramp_delay)
+{
+ struct bd71837_pmic *pmic = rdev_get_drvdata(rdev);
+ struct bd71837 *mfd = pmic->mfd;
+ int id = rdev->desc->id;
+ unsigned int ramp_value = BUCK_RAMPRATE_10P00MV;
+
+ dev_dbg(&(pmic->pdev->dev), "Buck[%d] Set Ramp = %d\n", id + 1,
+ ramp_delay);
+ switch (ramp_delay) {
+ case 1 ... 1250:
+ ramp_value = BUCK_RAMPRATE_1P25MV;
+ break;
+ case 1251 ... 2500:
+ ramp_value = BUCK_RAMPRATE_2P50MV;
+ break;
+ case 2501 ... 5000:
+ ramp_value = BUCK_RAMPRATE_5P00MV;
+ break;
+ case 5001 ... 10000:
+ ramp_value = BUCK_RAMPRATE_10P00MV;
+ break;
+ default:
+ ramp_value = BUCK_RAMPRATE_10P00MV;
+ dev_err(&pmic->pdev->dev,
+ "%s: ramp_delay: %d not supported, setting 10000mV//us\n",
+ rdev->desc->name, ramp_delay);
+ }
+
+ return regmap_update_bits(mfd->regmap, BD71837_REG_BUCK1_CTRL + id,
+ BUCK_RAMPRATE_MASK, ramp_value << 6);
+}
+
+static int bd71837_regulator_set_regmap(struct regulator_dev *rdev, int set)
+{
+ int ret = -EINVAL;
+ struct bd71837_pmic *pmic = rdev->reg_data;
+
+ /* According to the data sheet we must not change regulator voltage
+ * when it is enabled. Thus we need to check if regulator is enabled
+ * before changing the voltage. This mutex is used to avoid race where
+ * we might enable regulator after it's state has been checked but
+ * before the voltage is changed
+ */
+ mutex_lock(&pmic->mtx);
+ if (!set)
+ ret = regulator_disable_regmap(rdev);
+ else
+ ret = regulator_enable_regmap(rdev);
+ mutex_unlock(&pmic->mtx);
+
+ return ret;
+}
+
+static int bd71837_regulator_enable_regmap(struct regulator_dev *rdev)
+{
+ return bd71837_regulator_set_regmap(rdev, 1);
+}
+
+static int bd71837_regulator_disable_regmap(struct regulator_dev *rdev)
+{
+ return bd71837_regulator_set_regmap(rdev, 0);
+}
+
+static int bd71837_regulator_set_voltage_sel_regmap(struct regulator_dev *rdev,
+ unsigned int sel)
+{
+ int ret;
+ struct bd71837_pmic *pmic = rdev->reg_data;
+
+ /* According to the data sheet we must not change regulator voltage
+ * when it is enabled. Error out if regulator is enabled.
+ */
+ mutex_lock(&pmic->mtx);
+ ret = regulator_is_enabled_regmap(rdev);
+ if (!ret)
+ ret = regulator_set_voltage_sel_regmap(rdev, sel);
+ else if (ret == 1)
+ ret = -EBUSY;
+ mutex_unlock(&pmic->mtx);
+ return ret;
+}
+
+static struct regulator_ops bd71837_ldo_regulator_ops = {
+ .enable = bd71837_regulator_enable_regmap,
+ .disable = bd71837_regulator_disable_regmap,
+ .is_enabled = regulator_is_enabled_regmap,
+ .list_voltage = regulator_list_voltage_linear_range,
+ .set_voltage_sel = bd71837_regulator_set_voltage_sel_regmap,
+ .get_voltage_sel = regulator_get_voltage_sel_regmap,
+};
+
+static struct regulator_ops bd71837_ldo_regulator_nolinear_ops = {
+ .enable = bd71837_regulator_enable_regmap,
+ .disable = bd71837_regulator_disable_regmap,
+ .is_enabled = regulator_is_enabled_regmap,
+ .list_voltage = regulator_list_voltage_table,
+ .set_voltage_sel = bd71837_regulator_set_voltage_sel_regmap,
+ .get_voltage_sel = regulator_get_voltage_sel_regmap,
+};
+
+static struct regulator_ops bd71837_buck_regulator_ops = {
+ .enable = bd71837_regulator_enable_regmap,
+ .disable = bd71837_regulator_disable_regmap,
+ .is_enabled = regulator_is_enabled_regmap,
+ .list_voltage = regulator_list_voltage_linear_range,
+ .set_voltage_sel = bd71837_regulator_set_voltage_sel_regmap,
+ .get_voltage_sel = regulator_get_voltage_sel_regmap,
+ .set_voltage_time_sel = regulator_set_voltage_time_sel,
+};
+
+static struct regulator_ops bd71837_buck_regulator_nolinear_ops = {
+ .enable = bd71837_regulator_enable_regmap,
+ .disable = bd71837_regulator_disable_regmap,
+ .is_enabled = regulator_is_enabled_regmap,
+ .list_voltage = regulator_list_voltage_table,
+ .set_voltage_sel = bd71837_regulator_set_voltage_sel_regmap,
+ .get_voltage_sel = regulator_get_voltage_sel_regmap,
+ .set_voltage_time_sel = regulator_set_voltage_time_sel,
+};
+
+static struct regulator_ops bd71837_buck1234_regulator_ops = {
+ .enable = bd71837_regulator_enable_regmap,
+ .disable = bd71837_regulator_disable_regmap,
+ .is_enabled = regulator_is_enabled_regmap,
+ .list_voltage = regulator_list_voltage_linear_range,
+ .set_voltage_sel = bd71837_regulator_set_voltage_sel_regmap,
+ .get_voltage_sel = regulator_get_voltage_sel_regmap,
+ .set_voltage_time_sel = regulator_set_voltage_time_sel,
+ .set_ramp_delay = bd71837_buck1234_set_ramp_delay,
+};
+
+/*
+ * BUCK1/2/3/4
+ * 0.70 to 1.30V (10mV step)
+ */
+static const struct regulator_linear_range bd71837_buck1234_voltage_ranges[] = {
+ REGULATOR_LINEAR_RANGE(700000, 0x00, 0x3C, 10000),
+ REGULATOR_LINEAR_RANGE(1300000, 0x3D, 0x3F, 0),
+};
+
+/*
+ * BUCK5
+ * 0.9V to 1.35V ()
+ */
+static const struct regulator_linear_range bd71837_buck5_voltage_ranges[] = {
+ REGULATOR_LINEAR_RANGE(700000, 0x00, 0x03, 100000),
+ REGULATOR_LINEAR_RANGE(1050000, 0x04, 0x05, 50000),
+ REGULATOR_LINEAR_RANGE(1200000, 0x06, 0x07, 150000),
+};
+
+/*
+ * BUCK6
+ * 3.0V to 3.3V (step 100mV)
+ */
+static const struct regulator_linear_range bd71837_buck6_voltage_ranges[] = {
+ REGULATOR_LINEAR_RANGE(3000000, 0x00, 0x03, 100000),
+};
+
+/*
+ * BUCK7
+ * 000 = 1.605V
+ * 001 = 1.695V
+ * 010 = 1.755V
+ * 011 = 1.8V (Initial)
+ * 100 = 1.845V
+ * 101 = 1.905V
+ * 110 = 1.95V
+ * 111 = 1.995V
+ */
+static const unsigned int buck_7_volts[] = {
+ 1605000, 1695000, 1755000, 1800000, 1845000, 1905000, 1950000, 1995000
+};
+
+/*
+ * BUCK8
+ * 0.8V to 1.40V (step 10mV)
+ */
+static const struct regulator_linear_range bd71837_buck8_voltage_ranges[] = {
+ REGULATOR_LINEAR_RANGE(800000, 0x00, 0x3C, 10000),
+ REGULATOR_LINEAR_RANGE(1400000, 0x3D, 0x3F, 0),
+};
+
+/*
+ * LDO1
+ * 3.0 to 3.3V (100mV step)
+ */
+static const struct regulator_linear_range bd71837_ldo1_voltage_ranges[] = {
+ REGULATOR_LINEAR_RANGE(3000000, 0x00, 0x03, 100000),
+};
+
+/*
+ * LDO2
+ * 0.8 or 0.9V
+ */
+const unsigned int ldo_2_volts[] = {
+ 900000, 800000
+};
+
+/*
+ * LDO3
+ * 1.8 to 3.3V (100mV step)
+ */
+static const struct regulator_linear_range bd71837_ldo3_voltage_ranges[] = {
+ REGULATOR_LINEAR_RANGE(1800000, 0x00, 0x0F, 100000),
+};
+
+/*
+ * LDO4
+ * 0.9 to 1.8V (100mV step)
+ */
+static const struct regulator_linear_range bd71837_ldo4_voltage_ranges[] = {
+ REGULATOR_LINEAR_RANGE(900000, 0x00, 0x09, 100000),
+ REGULATOR_LINEAR_RANGE(1800000, 0x0A, 0x0F, 0),
+};
+
+/*
+ * LDO5
+ * 1.8 to 3.3V (100mV step)
+ */
+static const struct regulator_linear_range bd71837_ldo5_voltage_ranges[] = {
+ REGULATOR_LINEAR_RANGE(1800000, 0x00, 0x0F, 100000),
+};
+
+/*
+ * LDO6
+ * 0.9 to 1.8V (100mV step)
+ */
+static const struct regulator_linear_range bd71837_ldo6_voltage_ranges[] = {
+ REGULATOR_LINEAR_RANGE(900000, 0x00, 0x09, 100000),
+ REGULATOR_LINEAR_RANGE(1800000, 0x0A, 0x0F, 0),
+};
+
+/*
+ * LDO7
+ * 1.8 to 3.3V (100mV step)
+ */
+static const struct regulator_linear_range bd71837_ldo7_voltage_ranges[] = {
+ REGULATOR_LINEAR_RANGE(1800000, 0x00, 0x0F, 100000),
+};
+
+static const struct regulator_desc bd71837_regulators[] = {
+ {
+ .name = "buck1",
+ .of_match = of_match_ptr("BUCK1"),
+ .regulators_node = of_match_ptr("regulators"),
+ .id = BD71837_BUCK1,
+ .ops = &bd71837_buck1234_regulator_ops,
+ .type = REGULATOR_VOLTAGE,
+ .n_voltages = BD71837_BUCK1_VOLTAGE_NUM,
+ .linear_ranges = bd71837_buck1234_voltage_ranges,
+ .n_linear_ranges = ARRAY_SIZE(bd71837_buck1234_voltage_ranges),
+ .vsel_reg = BD71837_REG_BUCK1_VOLT_RUN,
+ .vsel_mask = BUCK1_RUN_MASK,
+ .enable_reg = BD71837_REG_BUCK1_CTRL,
+ .enable_mask = BD71837_BUCK_EN,
+ .owner = THIS_MODULE,
+ },
+ {
+ .name = "buck2",
+ .of_match = of_match_ptr("BUCK2"),
+ .regulators_node = of_match_ptr("regulators"),
+ .id = BD71837_BUCK2,
+ .ops = &bd71837_buck1234_regulator_ops,
+ .type = REGULATOR_VOLTAGE,
+ .n_voltages = BD71837_BUCK2_VOLTAGE_NUM,
+ .linear_ranges = bd71837_buck1234_voltage_ranges,
+ .n_linear_ranges = ARRAY_SIZE(bd71837_buck1234_voltage_ranges),
+ .vsel_reg = BD71837_REG_BUCK2_VOLT_RUN,
+ .vsel_mask = BUCK2_RUN_MASK,
+ .enable_reg = BD71837_REG_BUCK2_CTRL,
+ .enable_mask = BD71837_BUCK_EN,
+ .owner = THIS_MODULE,
+ },
+ {
+ .name = "buck3",
+ .of_match = of_match_ptr("BUCK3"),
+ .regulators_node = of_match_ptr("regulators"),
+ .id = BD71837_BUCK3,
+ .ops = &bd71837_buck1234_regulator_ops,
+ .type = REGULATOR_VOLTAGE,
+ .n_voltages = BD71837_BUCK3_VOLTAGE_NUM,
+ .linear_ranges = bd71837_buck1234_voltage_ranges,
+ .n_linear_ranges = ARRAY_SIZE(bd71837_buck1234_voltage_ranges),
+ .vsel_reg = BD71837_REG_BUCK3_VOLT_RUN,
+ .vsel_mask = BUCK3_RUN_MASK,
+ .enable_reg = BD71837_REG_BUCK3_CTRL,
+ .enable_mask = BD71837_BUCK_EN,
+ .owner = THIS_MODULE,
+ },
+ {
+ .name = "buck4",
+ .of_match = of_match_ptr("BUCK4"),
+ .regulators_node = of_match_ptr("regulators"),
+ .id = BD71837_BUCK4,
+ .ops = &bd71837_buck1234_regulator_ops,
+ .type = REGULATOR_VOLTAGE,
+ .n_voltages = BD71837_BUCK4_VOLTAGE_NUM,
+ .linear_ranges = bd71837_buck1234_voltage_ranges,
+ .n_linear_ranges = ARRAY_SIZE(bd71837_buck1234_voltage_ranges),
+ .vsel_reg = BD71837_REG_BUCK4_VOLT_RUN,
+ .vsel_mask = BUCK4_RUN_MASK,
+ .enable_reg = BD71837_REG_BUCK4_CTRL,
+ .enable_mask = BD71837_BUCK_EN,
+ .owner = THIS_MODULE,
+ },
+ {
+ .name = "buck5",
+ .of_match = of_match_ptr("BUCK5"),
+ .regulators_node = of_match_ptr("regulators"),
+ .id = BD71837_BUCK5,
+ .ops = &bd71837_buck_regulator_ops,
+ .type = REGULATOR_VOLTAGE,
+ .n_voltages = BD71837_BUCK5_VOLTAGE_NUM,
+ .linear_ranges = bd71837_buck5_voltage_ranges,
+ .n_linear_ranges = ARRAY_SIZE(bd71837_buck5_voltage_ranges),
+ .vsel_reg = BD71837_REG_BUCK5_VOLT,
+ .vsel_mask = BUCK5_MASK,
+ .enable_reg = BD71837_REG_BUCK5_CTRL,
+ .enable_mask = BD71837_BUCK_EN,
+ .owner = THIS_MODULE,
+ },
+ {
+ .name = "buck6",
+ .of_match = of_match_ptr("BUCK6"),
+ .regulators_node = of_match_ptr("regulators"),
+ .id = BD71837_BUCK6,
+ .ops = &bd71837_buck_regulator_ops,
+ .type = REGULATOR_VOLTAGE,
+ .n_voltages = BD71837_BUCK6_VOLTAGE_NUM,
+ .linear_ranges = bd71837_buck6_voltage_ranges,
+ .n_linear_ranges = ARRAY_SIZE(bd71837_buck6_voltage_ranges),
+ .vsel_reg = BD71837_REG_BUCK6_VOLT,
+ .vsel_mask = BUCK6_MASK,
+ .enable_reg = BD71837_REG_BUCK6_CTRL,
+ .enable_mask = BD71837_BUCK_EN,
+ .owner = THIS_MODULE,
+ },
+ {
+ .name = "buck7",
+ .of_match = of_match_ptr("BUCK7"),
+ .regulators_node = of_match_ptr("regulators"),
+ .id = BD71837_BUCK7,
+ .ops = &bd71837_buck_regulator_nolinear_ops,
+ .type = REGULATOR_VOLTAGE,
+ .volt_table = &buck_7_volts[0],
+ .n_voltages = ARRAY_SIZE(buck_7_volts),
+ .vsel_reg = BD71837_REG_BUCK7_VOLT,
+ .vsel_mask = BUCK7_MASK,
+ .enable_reg = BD71837_REG_BUCK7_CTRL,
+ .enable_mask = BD71837_BUCK_EN,
+ .owner = THIS_MODULE,
+ },
+ {
+ .name = "buck8",
+ .of_match = of_match_ptr("BUCK8"),
+ .regulators_node = of_match_ptr("regulators"),
+ .id = BD71837_BUCK8,
+ .ops = &bd71837_buck_regulator_ops,
+ .type = REGULATOR_VOLTAGE,
+ .n_voltages = BD71837_BUCK8_VOLTAGE_NUM,
+ .linear_ranges = bd71837_buck8_voltage_ranges,
+ .n_linear_ranges = ARRAY_SIZE(bd71837_buck8_voltage_ranges),
+ .vsel_reg = BD71837_REG_BUCK8_VOLT,
+ .vsel_mask = BUCK8_MASK,
+ .enable_reg = BD71837_REG_BUCK8_CTRL,
+ .enable_mask = BD71837_BUCK_EN,
+ .owner = THIS_MODULE,
+ },
+ {
+ .name = "ldo1",
+ .of_match = of_match_ptr("LDO1"),
+ .regulators_node = of_match_ptr("regulators"),
+ .id = BD71837_LDO1,
+ .ops = &bd71837_ldo_regulator_ops,
+ .type = REGULATOR_VOLTAGE,
+ .n_voltages = BD71837_LDO1_VOLTAGE_NUM,
+ .linear_ranges = bd71837_ldo1_voltage_ranges,
+ .n_linear_ranges = ARRAY_SIZE(bd71837_ldo1_voltage_ranges),
+ .vsel_reg = BD71837_REG_LDO1_VOLT,
+ .vsel_mask = LDO1_MASK,
+ .enable_reg = BD71837_REG_LDO1_VOLT,
+ .enable_mask = BD71837_LDO_EN,
+ .owner = THIS_MODULE,
+ },
+ {
+ .name = "ldo2",
+ .of_match = of_match_ptr("LDO2"),
+ .regulators_node = of_match_ptr("regulators"),
+ .id = BD71837_LDO2,
+ .ops = &bd71837_ldo_regulator_nolinear_ops,
+ .type = REGULATOR_VOLTAGE,
+ .volt_table = &ldo_2_volts[0],
+ .vsel_reg = BD71837_REG_LDO2_VOLT,
+ .vsel_mask = LDO2_MASK,
+ .n_voltages = ARRAY_SIZE(ldo_2_volts),
+ .n_voltages = BD71837_LDO2_VOLTAGE_NUM,
+ .enable_reg = BD71837_REG_LDO2_VOLT,
+ .enable_mask = BD71837_LDO_EN,
+ .owner = THIS_MODULE,
+ },
+ {
+ .name = "ldo3",
+ .of_match = of_match_ptr("LDO3"),
+ .regulators_node = of_match_ptr("regulators"),
+ .id = BD71837_LDO3,
+ .ops = &bd71837_ldo_regulator_ops,
+ .type = REGULATOR_VOLTAGE,
+ .n_voltages = BD71837_LDO3_VOLTAGE_NUM,
+ .linear_ranges = bd71837_ldo3_voltage_ranges,
+ .n_linear_ranges = ARRAY_SIZE(bd71837_ldo3_voltage_ranges),
+ .vsel_reg = BD71837_REG_LDO3_VOLT,
+ .vsel_mask = LDO3_MASK,
+ .enable_reg = BD71837_REG_LDO3_VOLT,
+ .enable_mask = BD71837_LDO_EN,
+ .owner = THIS_MODULE,
+ },
+ {
+ .name = "ldo4",
+ .of_match = of_match_ptr("LDO4"),
+ .regulators_node = of_match_ptr("regulators"),
+ .id = BD71837_LDO4,
+ .ops = &bd71837_ldo_regulator_ops,
+ .type = REGULATOR_VOLTAGE,
+ .n_voltages = BD71837_LDO4_VOLTAGE_NUM,
+ .linear_ranges = bd71837_ldo4_voltage_ranges,
+ .n_linear_ranges = ARRAY_SIZE(bd71837_ldo4_voltage_ranges),
+ .vsel_reg = BD71837_REG_LDO4_VOLT,
+ .vsel_mask = LDO4_MASK,
+ .enable_reg = BD71837_REG_LDO4_VOLT,
+ .enable_mask = BD71837_LDO_EN,
+ .owner = THIS_MODULE,
+ },
+ {
+ .name = "ldo5",
+ .of_match = of_match_ptr("LDO5"),
+ .regulators_node = of_match_ptr("regulators"),
+ .id = BD71837_LDO5,
+ .ops = &bd71837_ldo_regulator_ops,
+ .type = REGULATOR_VOLTAGE,
+ .n_voltages = BD71837_LDO5_VOLTAGE_NUM,
+ .linear_ranges = bd71837_ldo5_voltage_ranges,
+ .n_linear_ranges = ARRAY_SIZE(bd71837_ldo5_voltage_ranges),
+ /* LDO5 is supplied by buck6 */
+ .supply_name = "buck6",
+ .vsel_reg = BD71837_REG_LDO5_VOLT,
+ .vsel_mask = LDO5_MASK,
+ .enable_reg = BD71837_REG_LDO5_VOLT,
+ .enable_mask = BD71837_LDO_EN,
+ .owner = THIS_MODULE,
+ },
+ {
+ .name = "ldo6",
+ .of_match = of_match_ptr("LDO6"),
+ .regulators_node = of_match_ptr("regulators"),
+ .id = BD71837_LDO6,
+ .ops = &bd71837_ldo_regulator_ops,
+ .type = REGULATOR_VOLTAGE,
+ .n_voltages = BD71837_LDO6_VOLTAGE_NUM,
+ .linear_ranges = bd71837_ldo6_voltage_ranges,
+ .n_linear_ranges = ARRAY_SIZE(bd71837_ldo6_voltage_ranges),
+ /* LDO6 is supplied by buck7 */
+ .supply_name = "buck7",
+ .vsel_reg = BD71837_REG_LDO6_VOLT,
+ .vsel_mask = LDO6_MASK,
+ .enable_reg = BD71837_REG_LDO6_VOLT,
+ .enable_mask = BD71837_LDO_EN,
+ .owner = THIS_MODULE,
+ },
+ {
+ .name = "ldo7",
+ .of_match = of_match_ptr("LDO7"),
+ .regulators_node = of_match_ptr("regulators"),
+ .id = BD71837_LDO7,
+ .ops = &bd71837_ldo_regulator_ops,
+ .type = REGULATOR_VOLTAGE,
+ .n_voltages = BD71837_LDO7_VOLTAGE_NUM,
+ .linear_ranges = bd71837_ldo7_voltage_ranges,
+ .n_linear_ranges = ARRAY_SIZE(bd71837_ldo7_voltage_ranges),
+ .vsel_reg = BD71837_REG_LDO7_VOLT,
+ .vsel_mask = LDO7_MASK,
+ .enable_reg = BD71837_REG_LDO7_VOLT,
+ .enable_mask = BD71837_LDO_EN,
+ .owner = THIS_MODULE,
+ },
+};
+
+struct reg_init {
+ unsigned int reg;
+ unsigned int mask;
+};
+
+static int bd71837_probe(struct platform_device *pdev)
+{
+ struct bd71837_pmic *pmic;
+ struct bd71837_board *pdata;
+ struct regulator_config config = { 0 };
+ struct reg_init pmic_regulator_inits[] = {
+ {
+ .reg = BD71837_REG_BUCK1_CTRL,
+ .mask = BD71837_BUCK_SEL,
+ }, {
+ .reg = BD71837_REG_BUCK2_CTRL,
+ .mask = BD71837_BUCK_SEL,
+ }, {
+ .reg = BD71837_REG_BUCK3_CTRL,
+ .mask = BD71837_BUCK_SEL,
+ }, {
+ .reg = BD71837_REG_BUCK4_CTRL,
+ .mask = BD71837_BUCK_SEL,
+ }, {
+ .reg = BD71837_REG_BUCK5_CTRL,
+ .mask = BD71837_BUCK_SEL,
+ }, {
+ .reg = BD71837_REG_BUCK6_CTRL,
+ .mask = BD71837_BUCK_SEL,
+ }, {
+ .reg = BD71837_REG_BUCK7_CTRL,
+ .mask = BD71837_BUCK_SEL,
+ }, {
+ .reg = BD71837_REG_BUCK8_CTRL,
+ .mask = BD71837_BUCK_SEL,
+ }, {
+ .reg = BD71837_REG_LDO1_VOLT,
+ .mask = BD71837_LDO_SEL,
+ }, {
+ .reg = BD71837_REG_LDO2_VOLT,
+ .mask = BD71837_LDO_SEL,
+ }, {
+ .reg = BD71837_REG_LDO3_VOLT,
+ .mask = BD71837_LDO_SEL,
+ }, {
+ .reg = BD71837_REG_LDO4_VOLT,
+ .mask = BD71837_LDO_SEL,
+ }, {
+ .reg = BD71837_REG_LDO5_VOLT,
+ .mask = BD71837_LDO_SEL,
+ }, {
+ .reg = BD71837_REG_LDO6_VOLT,
+ .mask = BD71837_LDO_SEL,
+ }, {
+ .reg = BD71837_REG_LDO7_VOLT,
+ .mask = BD71837_LDO_SEL,
+ }
+ };
+
+ int i, err;
+
+ pmic = devm_kzalloc(&pdev->dev, sizeof(struct bd71837_pmic),
+ GFP_KERNEL);
+ if (!pmic)
+ return -ENOMEM;
+
+ mutex_init(&pmic->mtx);
+
+ memcpy(pmic->descs, bd71837_regulators, sizeof(pmic->descs));
+
+ pmic->pdev = pdev;
+ pmic->mfd = dev_get_drvdata(pdev->dev.parent);
+
+ if (!pmic->mfd) {
+ dev_err(&pdev->dev, "No MFD driver data\n");
+ err = -EINVAL;
+ goto err;
+ }
+ platform_set_drvdata(pdev, pmic);
+ pdata = dev_get_platdata(pmic->mfd->dev);
+
+ /* Register LOCK release */
+ err = regmap_update_bits(pmic->mfd->regmap, BD71837_REG_REGLOCK,
+ (REGLOCK_PWRSEQ | REGLOCK_VREG), 0);
+ if (err) {
+ dev_err(&pmic->pdev->dev, "Failed to unlock PMIC (%d)\n", err);
+ goto err;
+ } else {
+ dev_dbg(&pmic->pdev->dev, "%s: Unlocked lock register 0x%x\n",
+ __func__, BD71837_REG_REGLOCK);
+ }
+
+ for (i = 0; i < ARRAY_SIZE(pmic_regulator_inits); i++) {
+
+ struct regulator_desc *desc;
+ struct regulator_dev *rdev;
+
+ desc = &pmic->descs[i];
+
+ if (pdata)
+ config.init_data = pdata->init_data[i];
+
+ config.dev = pdev->dev.parent;
+ config.driver_data = pmic;
+ config.regmap = pmic->mfd->regmap;
+
+ rdev = devm_regulator_register(&pdev->dev, desc, &config);
+ if (IS_ERR(rdev)) {
+ dev_err(pmic->mfd->dev,
+ "failed to register %s regulator\n",
+ desc->name);
+ err = PTR_ERR(rdev);
+ goto err;
+ }
+ /* Regulator register gets the regulator constraints and
+ * applies them (set_machine_constraints). This should have
+ * turned the control register(s) to correct values and we
+ * can now switch the control from PMIC state machine to the
+ * register interface
+ */
+ err = regmap_update_bits(pmic->mfd->regmap,
+ pmic_regulator_inits[i].reg,
+ pmic_regulator_inits[i].mask,
+ 0xFFFFFFFF);
+ if (err) {
+ dev_err(&pmic->pdev->dev,
+ "Failed to write BUCK/LDO SEL bit for (%s)\n",
+ desc->name);
+ goto err;
+ }
+
+ pmic->rdev[i] = rdev;
+ }
+
+ return 0;
+
+err:
+ return err;
+}
+
+static struct platform_driver bd71837_regulator = {
+ .driver = {
+ .name = "bd71837-pmic",
+ .owner = THIS_MODULE,
+ },
+ .probe = bd71837_probe,
+};
+
+module_platform_driver(bd71837_regulator);
+
+MODULE_AUTHOR("Matti Vaittinen <matti.vaittinen@fi.rohmeurope.com>");
+MODULE_DESCRIPTION("BD71837 voltage regulator driver");
+MODULE_LICENSE("GPL");
--
2.14.3
^ 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