]> git.baikalelectronics.ru Git - kernel.git/commitdiff
soundwire: intel: Add stream initialization
authorVinod Koul <vkoul@kernel.org>
Thu, 26 Apr 2018 13:08:58 +0000 (18:38 +0530)
committerVinod Koul <vkoul@kernel.org>
Fri, 11 May 2018 16:18:07 +0000 (21:48 +0530)
Add Intel stream init routines which initialize the Physical
Data Interface (PDI), Audio Link Hub (ALH) and Audio shim.
Also add bank switch routines.

Signed-off-by: Hardik T Shah <hardik.t.shah@intel.com>
Signed-off-by: Sanyog Kale <sanyog.r.kale@intel.com>
Signed-off-by: Shreyas NC <shreyas.nc@intel.com>
Signed-off-by: Vinod Koul <vkoul@kernel.org>
drivers/soundwire/intel.c

index a64f87a08cfd60aa1e40fc38c364eb156b56201d..707e435b5da1bc6c86acadeb55668cc1a5b2cab7 100644 (file)
@@ -9,6 +9,8 @@
 #include <linux/delay.h>
 #include <linux/interrupt.h>
 #include <linux/platform_device.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
 #include <linux/soundwire/sdw_registers.h>
 #include <linux/soundwire/sdw.h>
 #include <linux/soundwire/sdw_intel.h>
@@ -234,6 +236,149 @@ static int intel_shim_init(struct sdw_intel *sdw)
        return ret;
 }
 
+/*
+ * PDI routines
+ */
+static void intel_pdi_init(struct sdw_intel *sdw,
+                       struct sdw_cdns_stream_config *config)
+{
+       void __iomem *shim = sdw->res->shim;
+       unsigned int link_id = sdw->instance;
+       int pcm_cap, pdm_cap;
+
+       /* PCM Stream Capability */
+       pcm_cap = intel_readw(shim, SDW_SHIM_PCMSCAP(link_id));
+
+       config->pcm_bd = (pcm_cap & SDW_SHIM_PCMSCAP_BSS) >>
+                                       SDW_REG_SHIFT(SDW_SHIM_PCMSCAP_BSS);
+       config->pcm_in = (pcm_cap & SDW_SHIM_PCMSCAP_ISS) >>
+                                       SDW_REG_SHIFT(SDW_SHIM_PCMSCAP_ISS);
+       config->pcm_out = (pcm_cap & SDW_SHIM_PCMSCAP_OSS) >>
+                                       SDW_REG_SHIFT(SDW_SHIM_PCMSCAP_OSS);
+
+       /* PDM Stream Capability */
+       pdm_cap = intel_readw(shim, SDW_SHIM_PDMSCAP(link_id));
+
+       config->pdm_bd = (pdm_cap & SDW_SHIM_PDMSCAP_BSS) >>
+                                       SDW_REG_SHIFT(SDW_SHIM_PDMSCAP_BSS);
+       config->pdm_in = (pdm_cap & SDW_SHIM_PDMSCAP_ISS) >>
+                                       SDW_REG_SHIFT(SDW_SHIM_PDMSCAP_ISS);
+       config->pdm_out = (pdm_cap & SDW_SHIM_PDMSCAP_OSS) >>
+                                       SDW_REG_SHIFT(SDW_SHIM_PDMSCAP_OSS);
+}
+
+static int
+intel_pdi_get_ch_cap(struct sdw_intel *sdw, unsigned int pdi_num, bool pcm)
+{
+       void __iomem *shim = sdw->res->shim;
+       unsigned int link_id = sdw->instance;
+       int count;
+
+       if (pcm) {
+               count = intel_readw(shim, SDW_SHIM_PCMSYCHC(link_id, pdi_num));
+       } else {
+               count = intel_readw(shim, SDW_SHIM_PDMSCAP(link_id));
+               count = ((count & SDW_SHIM_PDMSCAP_CPSS) >>
+                                       SDW_REG_SHIFT(SDW_SHIM_PDMSCAP_CPSS));
+       }
+
+       /* zero based values for channel count in register */
+       count++;
+
+       return count;
+}
+
+static int intel_pdi_get_ch_update(struct sdw_intel *sdw,
+                               struct sdw_cdns_pdi *pdi,
+                               unsigned int num_pdi,
+                               unsigned int *num_ch, bool pcm)
+{
+       int i, ch_count = 0;
+
+       for (i = 0; i < num_pdi; i++) {
+               pdi->ch_count = intel_pdi_get_ch_cap(sdw, pdi->num, pcm);
+               ch_count += pdi->ch_count;
+               pdi++;
+       }
+
+       *num_ch = ch_count;
+       return 0;
+}
+
+static int intel_pdi_stream_ch_update(struct sdw_intel *sdw,
+                               struct sdw_cdns_streams *stream, bool pcm)
+{
+       intel_pdi_get_ch_update(sdw, stream->bd, stream->num_bd,
+                       &stream->num_ch_bd, pcm);
+
+       intel_pdi_get_ch_update(sdw, stream->in, stream->num_in,
+                       &stream->num_ch_in, pcm);
+
+       intel_pdi_get_ch_update(sdw, stream->out, stream->num_out,
+                       &stream->num_ch_out, pcm);
+
+       return 0;
+}
+
+static int intel_pdi_ch_update(struct sdw_intel *sdw)
+{
+       /* First update PCM streams followed by PDM streams */
+       intel_pdi_stream_ch_update(sdw, &sdw->cdns.pcm, true);
+       intel_pdi_stream_ch_update(sdw, &sdw->cdns.pdm, false);
+
+       return 0;
+}
+
+static void
+intel_pdi_shim_configure(struct sdw_intel *sdw, struct sdw_cdns_pdi *pdi)
+{
+       void __iomem *shim = sdw->res->shim;
+       unsigned int link_id = sdw->instance;
+       int pdi_conf = 0;
+
+       pdi->intel_alh_id = (link_id * 16) + pdi->num + 5;
+
+       /*
+        * Program stream parameters to stream SHIM register
+        * This is applicable for PCM stream only.
+        */
+       if (pdi->type != SDW_STREAM_PCM)
+               return;
+
+       if (pdi->dir == SDW_DATA_DIR_RX)
+               pdi_conf |= SDW_SHIM_PCMSYCM_DIR;
+       else
+               pdi_conf &= ~(SDW_SHIM_PCMSYCM_DIR);
+
+       pdi_conf |= (pdi->intel_alh_id <<
+                       SDW_REG_SHIFT(SDW_SHIM_PCMSYCM_STREAM));
+       pdi_conf |= (pdi->l_ch_num << SDW_REG_SHIFT(SDW_SHIM_PCMSYCM_LCHN));
+       pdi_conf |= (pdi->h_ch_num << SDW_REG_SHIFT(SDW_SHIM_PCMSYCM_HCHN));
+
+       intel_writew(shim, SDW_SHIM_PCMSYCHM(link_id, pdi->num), pdi_conf);
+}
+
+static void
+intel_pdi_alh_configure(struct sdw_intel *sdw, struct sdw_cdns_pdi *pdi)
+{
+       void __iomem *alh = sdw->res->alh;
+       unsigned int link_id = sdw->instance;
+       unsigned int conf;
+
+       pdi->intel_alh_id = (link_id * 16) + pdi->num + 5;
+
+       /* Program Stream config ALH register */
+       conf = intel_readl(alh, SDW_ALH_STRMZCFG(pdi->intel_alh_id));
+
+       conf |= (SDW_ALH_STRMZCFG_DMAT_VAL <<
+                       SDW_REG_SHIFT(SDW_ALH_STRMZCFG_DMAT));
+
+       conf |= ((pdi->ch_count - 1) <<
+                       SDW_REG_SHIFT(SDW_ALH_STRMZCFG_CHN));
+
+       intel_writel(alh, SDW_ALH_STRMZCFG(pdi->intel_alh_id), conf);
+}
+
 static int intel_prop_read(struct sdw_bus *bus)
 {
        /* Initialize with default handler to read all DisCo properties */
@@ -265,6 +410,7 @@ static struct sdw_master_ops sdw_intel_ops = {
  */
 static int intel_probe(struct platform_device *pdev)
 {
+       struct sdw_cdns_stream_config config;
        struct sdw_intel *sdw;
        int ret;
 
@@ -287,6 +433,9 @@ static int intel_probe(struct platform_device *pdev)
        sdw_intel_ops.read_prop = intel_prop_read;
        sdw->cdns.bus.ops = &sdw_intel_ops;
 
+       sdw_intel_ops.read_prop = intel_prop_read;
+       sdw->cdns.bus.ops = &sdw_intel_ops;
+
        platform_set_drvdata(pdev, sdw);
 
        ret = sdw_add_bus_master(&sdw->cdns.bus);
@@ -304,9 +453,15 @@ static int intel_probe(struct platform_device *pdev)
                goto err_init;
 
        ret = sdw_cdns_enable_interrupt(&sdw->cdns);
+
+       /* Read the PDI config and initialize cadence PDI */
+       intel_pdi_init(sdw, &config);
+       ret = sdw_cdns_pdi_init(&sdw->cdns, config);
        if (ret)
                goto err_init;
 
+       intel_pdi_ch_update(sdw);
+
        /* Acquire IRQ */
        ret = request_threaded_irq(sdw->res->irq, sdw_cdns_irq,
                        sdw_cdns_thread, IRQF_SHARED, KBUILD_MODNAME,