* RE: [PATCH v6 1/2] ASoC: fsl: Add S/PDIF CPU DAI driver
From: Bhushan Bharat-R65777 @ 2013-08-16 18:24 UTC (permalink / raw)
To: Chen Guangyu-B42378, broonie@kernel.org, lars@metafoo.de,
p.zabel@pengutronix.de, s.hauer@pengutronix.de
Cc: mark.rutland@arm.com, devicetree@vger.kernel.org,
alsa-devel@alsa-project.org, swarren@wwwdotorg.org,
linuxppc-dev@lists.ozlabs.org, timur@tabi.org,
rob.herring@calxeda.com, tomasz.figa@gmail.com,
shawn.guo@linaro.org, festevam@gmail.com
In-Reply-To: <df3c09cd5679649b144bb45dfd5fc746628266d4.1376657643.git.b42378@freescale.com>
> -----Original Message-----
> From: Linuxppc-dev [mailto:linuxppc-dev-
> bounces+bharat.bhushan=3Dfreescale.com@lists.ozlabs.org] On Behalf Of Nic=
olin Chen
> Sent: Friday, August 16, 2013 6:27 PM
> To: broonie@kernel.org; lars@metafoo.de; p.zabel@pengutronix.de;
> s.hauer@pengutronix.de
> Cc: mark.rutland@arm.com; devicetree@vger.kernel.org; alsa-devel@alsa-
> project.org; swarren@wwwdotorg.org; festevam@gmail.com; timur@tabi.org;
> rob.herring@calxeda.com; tomasz.figa@gmail.com; shawn.guo@linaro.org; lin=
uxppc-
> dev@lists.ozlabs.org
> Subject: [PATCH v6 1/2] ASoC: fsl: Add S/PDIF CPU DAI driver
>=20
> This patch add S/PDIF controller driver for Freescale SoC.
Please give some more description of the driver?
>=20
> Signed-off-by: Nicolin Chen <b42378@freescale.com>
> ---
> .../devicetree/bindings/sound/fsl,spdif.txt | 56 +
> sound/soc/fsl/Kconfig | 3 +
> sound/soc/fsl/Makefile | 2 +
> sound/soc/fsl/fsl_spdif.c | 1272 ++++++++++++++=
++++++
> sound/soc/fsl/fsl_spdif.h | 224 ++++
> 5 files changed, 1557 insertions(+), 0 deletions(-)
> create mode 100644 Documentation/devicetree/bindings/sound/fsl,spdif.txt
> create mode 100644 sound/soc/fsl/fsl_spdif.c
> create mode 100644 sound/soc/fsl/fsl_spdif.h
>=20
> diff --git a/Documentation/devicetree/bindings/sound/fsl,spdif.txt
> b/Documentation/devicetree/bindings/sound/fsl,spdif.txt
> new file mode 100644
> index 0000000..5549ce3
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/sound/fsl,spdif.txt
> @@ -0,0 +1,56 @@
> +Freescale Sony/Philips Digital Interface Format (S/PDIF) Controller
> +
> +The Freescale S/PDIF audio block is a stereo transceiver that allows the
> +processor to receive and transmit digital audio via an coaxial cable or
> +a fibre cable.
> +
> +Required properties:
> +
> + - compatible : Compatible list, contains "fsl,<chip>-spdif".
> +
> + - reg : Offset and length of the register set for the device.
> +
> + - interrupts : Contains spdif interrupt.
> +
> + - dmas : Generic dma devicetree binding as described in
> + Documentation/devicetree/bindings/dma/dma.txt.
> +
> + - dma-names : Two dmas have to be defined, "tx" and "rx".
> +
> + - clocks : Contains an entry for each entry in clock-names.
> +
> + - clock-names : Includes the following entries:
> + name comments
> + "core" The core clock of spdif controller
> + "rxtx<0-7>" Clock source list for tx and rx clock.
> + This clock list should be identical to
> + the source list connecting to the spdif
> + clock mux in "SPDIF Transceiver Clock
> + Diagram" of SoC reference manual. It
> + can also be referred to TxClk_Source
> + bit of register SPDIF_STC.
> +
> +Example:
> +
> +spdif: spdif@02004000 {
> + compatible =3D "fsl,imx6q-spdif",
> + "fsl,imx35-spdif";
> + reg =3D <0x02004000 0x4000>;
> + interrupts =3D <0 52 0x04>;
> + dmas =3D <&sdma 14 18 0>,
> + <&sdma 15 18 0>;
> + dma-names =3D "rx", "tx";
> +
> + clocks =3D <&clks 197>, <&clks 3>,
> + <&clks 197>, <&clks 107>,
> + <&clks 0>, <&clks 118>,
> + <&clks 62>, <&clks 139>,
> + <&clks 0>;
> + clock-names =3D "core", "rxtx0",
> + "rxtx1", "rxtx2",
> + "rxtx3", "rxtx4",
> + "rxtx5", "rxtx6",
> + "rxtx7";
> +
> + status =3D "okay";
> +};
> diff --git a/sound/soc/fsl/Kconfig b/sound/soc/fsl/Kconfig
> index e15f771..2c518db 100644
> --- a/sound/soc/fsl/Kconfig
> +++ b/sound/soc/fsl/Kconfig
> @@ -1,6 +1,9 @@
> config SND_SOC_FSL_SSI
> tristate
>=20
> +config SND_SOC_FSL_SPDIF
> + tristate
> +
> config SND_SOC_FSL_UTILS
> tristate
>=20
> diff --git a/sound/soc/fsl/Makefile b/sound/soc/fsl/Makefile
> index d4b4aa8..4b5970e 100644
> --- a/sound/soc/fsl/Makefile
> +++ b/sound/soc/fsl/Makefile
> @@ -12,9 +12,11 @@ obj-$(CONFIG_SND_SOC_P1022_RDK) +=3D snd-soc-p1022-rdk=
.o
>=20
> # Freescale PowerPC SSI/DMA Platform Support
> snd-soc-fsl-ssi-objs :=3D fsl_ssi.o
> +snd-soc-fsl-spdif-objs :=3D fsl_spdif.o
> snd-soc-fsl-utils-objs :=3D fsl_utils.o
> snd-soc-fsl-dma-objs :=3D fsl_dma.o
> obj-$(CONFIG_SND_SOC_FSL_SSI) +=3D snd-soc-fsl-ssi.o
> +obj-$(CONFIG_SND_SOC_FSL_SPDIF) +=3D snd-soc-fsl-spdif.o
> obj-$(CONFIG_SND_SOC_FSL_UTILS) +=3D snd-soc-fsl-utils.o
> obj-$(CONFIG_SND_SOC_POWERPC_DMA) +=3D snd-soc-fsl-dma.o
>=20
> diff --git a/sound/soc/fsl/fsl_spdif.c b/sound/soc/fsl/fsl_spdif.c
> new file mode 100644
> index 0000000..e00125e
> --- /dev/null
> +++ b/sound/soc/fsl/fsl_spdif.c
> @@ -0,0 +1,1272 @@
> +/*
> + * Freescale S/PDIF ALSA SoC Digital Audio Interface (DAI) driver
> + *
> + * Copyright (C) 2013 Freescale Semiconductor, Inc.
> + *
> + * Based on stmp3xxx_spdif_dai.c
> + * Vladimir Barinov <vbarinov@embeddedalley.com>
> + * Copyright 2008 SigmaTel, Inc
> + * Copyright 2008 Embedded Alley Solutions, Inc
> + *
> + * This file is licensed under the terms of the GNU General Public Licen=
se
> + * version 2. This program is licensed "as is" without any warranty of=
any
> + * kind, whether express or implied.
> + */
> +
> +#include <linux/module.h>
> +#include <linux/clk.h>
> +#include <linux/clk-private.h>
> +#include <linux/regmap.h>
> +#include <linux/of_address.h>
> +#include <linux/of_device.h>
> +#include <linux/of_irq.h>
> +
> +#include <sound/asoundef.h>
> +#include <sound/soc.h>
> +#include <sound/dmaengine_pcm.h>
> +
> +#include "fsl_spdif.h"
> +#include "imx-pcm.h"
> +
> +#define FSL_SPDIF_TXFIFO_WML 0x8
> +#define FSL_SPDIF_RXFIFO_WML 0x8
> +
> +#define INTR_FOR_PLAYBACK (INT_TXFIFO_RESYNC)
> +#define INTR_FOR_CAPTURE (INT_SYM_ERR | INT_BIT_ERR | INT_URX_FUL |
> INT_URX_OV|\
> + INT_QRX_FUL | INT_QRX_OV | INT_UQ_SYNC | INT_UQ_ERR |\
> + INT_RXFIFO_RESYNC | INT_LOSS_LOCK | INT_DPLL_LOCKED)
> +
> +/* Index list for the values that has if (DPLL Locked) condition */
> +static u8 srpc_dpll_locked[] =3D { 0x0, 0x1, 0x2, 0x3, 0x4, 0xa, 0xb, };
^
^ un-n=
ecessary comma.
> +#define SRPC_NODPLL_START1 0x5
> +#define SRPC_NODPLL_START2 0xc
> +
> +/*
> + * SPDIF control structure
> + * Defines channel status, subcode and Q sub
> + */
> +struct spdif_mixer_control {
> + /* spinlock to access control data */
> + spinlock_t ctl_lock;
> +
> + /* IEC958 channel tx status bit */
> + unsigned char ch_status[4];
> +
> + /* User bits */
> + unsigned char subcode[2 * SPDIF_UBITS_SIZE];
> +
> + /* Q subcode part of user bits */
> + unsigned char qsub[2 * SPDIF_QSUB_SIZE];
> +
> + /* buffer ptrs for writer */
> + u32 upos;
> + u32 qpos;
They does not look like pointer?
> +
> + /* ready buffer index of the two buffers */
> + u32 ready_buf;
> +};
> +
> +struct fsl_spdif_priv {
> + struct spdif_mixer_control fsl_spdif_control;
> + struct snd_soc_dai_driver cpu_dai_drv;
> + struct platform_device *pdev;
> + struct regmap *regmap;
> + atomic_t dpll_locked;
> + u8 txclk_div[SPDIF_TXRATE_MAX];
> + u8 txclk_src[SPDIF_TXRATE_MAX];
> + u8 rxclk_src;
> + struct clk *txclk[SPDIF_TXRATE_MAX];
> + struct clk *rxclk;
> + struct snd_dmaengine_dai_dma_data dma_params_tx;
> + struct snd_dmaengine_dai_dma_data dma_params_rx;
> +
> + /* The name space will be allocated dynamically */
> + char name[0];
> +};
> +
> +
> +#ifdef DEBUG
> +static void dumpregs(struct fsl_spdif_priv *spdif_priv)
> +{
> + struct regmap *regmap =3D spdif_priv->regmap;
> + struct platform_device *pdev =3D spdif_priv->pdev;
> + u32 val, i;
> + int ret;
> +
> + /* Valid address set of SPDIF is {[0x0-0x38], 0x44, 0x50} */
> + for (i =3D 0 ; i <=3D REG_SPDIF_STC; i +=3D 4) {
> + ret =3D regmap_read(regmap, REG_SPDIF_SCR + i, &val);
> + if (!ret)
> + dev_dbg(&pdev->dev, "REG 0x%02x =3D 0x%06x\n", i, val);
> + }
> +}
> +#else
> +static void dumpregs(struct fsl_spdif_priv *spdif_priv) {}
> +#endif
> +
> +
> +/* DPLL locked and lock loss interrupt handler */
> +static void spdif_irq_dpll_lock(struct fsl_spdif_priv *spdif_priv)
> +{
> + struct regmap *regmap =3D spdif_priv->regmap;
> + struct platform_device *pdev =3D spdif_priv->pdev;
> + u32 locked;
> +
> + regmap_read(regmap, REG_SPDIF_SRPC, &locked);
> + locked &=3D SRPC_DPLL_LOCKED;
> +
> + dev_dbg(&pdev->dev, "isr: Rx dpll %s \n",
> + locked ? "locked" : "loss lock");
> +
> + atomic_set(&spdif_priv->dpll_locked, locked ? 1 : 0);
> +}
> +
> +/* Receiver found illegal symbol interrupt handler */
> +static void spdif_irq_sym_error(struct fsl_spdif_priv *spdif_priv)
> +{
> + struct regmap *regmap =3D spdif_priv->regmap;
> + struct platform_device *pdev =3D spdif_priv->pdev;
> +
> + dev_dbg(&pdev->dev, "isr: receiver found illegal symbol\n");
> +
> + if (!atomic_read(&spdif_priv->dpll_locked)) {
> + /* dpll unlocked seems no audio stream */
> + regmap_update_bits(regmap, REG_SPDIF_SIE, INT_SYM_ERR, 0);
> + }
> +}
> +
> +/* U/Q Channel receive register full */
> +static void spdif_irq_uqrx_full(struct fsl_spdif_priv *spdif_priv, char =
name)
> +{
> + struct spdif_mixer_control *ctrl =3D &spdif_priv->fsl_spdif_control;
> + struct regmap *regmap =3D spdif_priv->regmap;
> + struct platform_device *pdev =3D spdif_priv->pdev;
> + u32 *pos, size, val, reg;
> +
> + switch (name) {
> + case 'U':
> + pos =3D &ctrl->upos;
> + size =3D SPDIF_UBITS_SIZE;
> + reg =3D REG_SPDIF_SRU;
> + break;
> + case 'Q':
> + pos =3D &ctrl->qpos;
> + size =3D SPDIF_QSUB_SIZE;
> + reg =3D REG_SPDIF_SRQ;
> + break;
> + default:
> + return;
Should return error.
> + }
> +
> + dev_dbg(&pdev->dev, "isr: %c Channel receive register full\n", name);
> +
> + if (*pos >=3D size * 2) {
> + *pos =3D 0;
> + } else if (unlikely((*pos % size) + 3 > size)) {
> + dev_err(&pdev->dev, "User bit receivce buffer overflow\n");
> + return;
Should return error.
> + }
> +
> + regmap_read(regmap, reg, &val);
> + ctrl->subcode[*pos++] =3D val >> 16;
> + ctrl->subcode[*pos++] =3D val >> 8;
> + ctrl->subcode[*pos++] =3D val;
> +}
> +
> +/* U/Q Channel sync found */
> +static void spdif_irq_uq_sync(struct fsl_spdif_priv *spdif_priv)
> +{
> + struct spdif_mixer_control *ctrl =3D &spdif_priv->fsl_spdif_control;
> + struct platform_device *pdev =3D spdif_priv->pdev;
> +
> + dev_dbg(&pdev->dev, "isr: U/Q Channel sync found\n");
> +
> + /* U/Q buffer reset */
> + if (ctrl->qpos =3D=3D 0)
> + return;
> +
> + /* set ready to this buffer */
> + ctrl->ready_buf =3D (ctrl->qpos - 1) / SPDIF_QSUB_SIZE + 1;
> +}
> +
> +/* U/Q Channel framing error */
> +static void spdif_irq_uq_err(struct fsl_spdif_priv *spdif_priv)
> +{
> + struct spdif_mixer_control *ctrl =3D &spdif_priv->fsl_spdif_control;
> + struct regmap *regmap =3D spdif_priv->regmap;
> + struct platform_device *pdev =3D spdif_priv->pdev;
> + u32 val;
> +
> + dev_dbg(&pdev->dev, "isr: U/Q Channel framing error\n");
> +
> + /* read U/Q data and do buffer reset */
> + regmap_read(regmap, REG_SPDIF_SRU, &val);
> + regmap_read(regmap, REG_SPDIF_SRQ, &val);
Above prints says read u/q data and buffer reset, what is buffer reset? Is =
that read on clear?
> +
> + /* drop this U/Q buffer */
> + ctrl->ready_buf =3D 0;
> + ctrl->upos =3D 0;
> + ctrl->qpos =3D 0;
> +}
> +
> +/* Get spdif interrupt status and clear the interrupt */
> +static u32 spdif_intr_status_clear(struct fsl_spdif_priv *spdif_priv)
> +{
> + struct regmap *regmap =3D spdif_priv->regmap;
> + u32 val, val2;
> +
> + regmap_read(regmap, REG_SPDIF_SIS, &val);
> + regmap_read(regmap, REG_SPDIF_SIE, &val2);
> +
> + regmap_write(regmap, REG_SPDIF_SIC, val & val2);
> +
> + return val;
> +}
> +
> +static irqreturn_t spdif_isr(int irq, void *devid)
> +{
> + struct fsl_spdif_priv *spdif_priv =3D (struct fsl_spdif_priv *)devid;
> + struct platform_device *pdev =3D spdif_priv->pdev;
> + u32 sis;
> +
> + sis =3D spdif_intr_status_clear(spdif_priv);
> +
> + if (sis & INT_DPLL_LOCKED)
> + spdif_irq_dpll_lock(spdif_priv);
> +
> + if (sis & INT_TXFIFO_UNOV)
> + dev_dbg(&pdev->dev, "isr: Tx FIFO under/overrun\n");
> +
> + if (sis & INT_TXFIFO_RESYNC)
> + dev_dbg(&pdev->dev, "isr: Tx FIFO resync\n");
> +
> + if (sis & INT_CNEW)
> + dev_dbg(&pdev->dev, "isr: cstatus new\n");
> +
> + if (sis & INT_VAL_NOGOOD)
> + dev_dbg(&pdev->dev, "isr: validity flag no good\n");
> +
> + if (sis & INT_SYM_ERR)
> + spdif_irq_sym_error(spdif_priv);
> +
> + if (sis & INT_BIT_ERR)
> + dev_dbg(&pdev->dev, "isr: receiver found parity bit error\n");
> +
> + if (sis & INT_URX_FUL)
> + spdif_irq_uqrx_full(spdif_priv, 'U');
> +
> + if (sis & INT_URX_OV)
> + dev_dbg(&pdev->dev, "isr: U Channel receive register overrun\n");
> +
> + if (sis & INT_QRX_FUL)
> + spdif_irq_uqrx_full(spdif_priv, 'Q');
> +
> + if (sis & INT_QRX_OV)
> + dev_dbg(&pdev->dev, "isr: Q Channel receive register overrun\n");
> +
> + if (sis & INT_UQ_SYNC)
> + spdif_irq_uq_sync(spdif_priv);
> +
> + if (sis & INT_UQ_ERR)
> + spdif_irq_uq_err(spdif_priv);
> +
> + if (sis & INT_RXFIFO_UNOV)
> + dev_dbg(&pdev->dev, "isr: Rx FIFO under/overrun\n");
> +
> + if (sis & INT_RXFIFO_RESYNC)
> + dev_dbg(&pdev->dev, "isr: Rx FIFO resync\n");
> +
> + if (sis & INT_LOSS_LOCK)
> + spdif_irq_dpll_lock(spdif_priv);
> +
> + /* FIXME: Write Tx FIFO to clear TxEm */
> + if (sis & INT_TX_EM)
> + dev_dbg(&pdev->dev, "isr: Tx FIFO empty\n");
> +
> + /* FIXME: Read Rx FIFO to clear RxFIFOFul */
> + if (sis & INT_RXFIFO_FUL)
> + dev_dbg(&pdev->dev, "isr: Rx FIFO full\n");
> +
> + return IRQ_HANDLED;
> +}
> +
> +static void spdif_softreset(struct fsl_spdif_priv *spdif_priv)
> +{
> + struct regmap *regmap =3D spdif_priv->regmap;
> + u32 val, cycle =3D 1000;
> +
> + regmap_write(regmap, REG_SPDIF_SCR, SCR_SOFT_RESET);
> + regcache_sync(regmap);
> +
> + /* RESET bit would be cleared after finishing its reset procedure */
> + do {
> + regmap_read(regmap, REG_SPDIF_SCR, &val);
> + } while ((val & SCR_SOFT_RESET) && cycle--);
What if reset is not cleared and timeout happen?
> +}
> +
> +static void spdif_set_cstatus(struct spdif_mixer_control *ctrl,
> + u8 mask, u8 cstatus)
> +{
> + ctrl->ch_status[3] &=3D ~mask;
> + ctrl->ch_status[3] |=3D cstatus & mask;
> +}
> +
> +static u8 reverse_bits(u8 input)
> +{
> + u8 tmp =3D input;
> +
> + tmp =3D ((tmp & 0b10101010) >> 1) | ((tmp << 1) & 0b10101010);
> + tmp =3D ((tmp & 0b11001100) >> 2) | ((tmp << 2) & 0b11001100);
> + tmp =3D ((tmp & 0b11110000) >> 4) | ((tmp << 4) & 0b11110000);
What is this logic, can the hardcoding be removed and some description on a=
bove calculation?
> +
> + return tmp;
> +}
> +
> +static void spdif_write_channel_status(struct fsl_spdif_priv *spdif_priv=
)
> +{
> + struct spdif_mixer_control *ctrl =3D &spdif_priv->fsl_spdif_control;
> + struct regmap *regmap =3D spdif_priv->regmap;
> + struct platform_device *pdev =3D spdif_priv->pdev;
> + u32 ch_status;
> +
> + ch_status =3D (reverse_bits(ctrl->ch_status[0]) << 16) |
> + (reverse_bits(ctrl->ch_status[1]) << 8) |
> + reverse_bits(ctrl->ch_status[2]);
> + regmap_write(regmap, REG_SPDIF_STCSCH, ch_status);
> +
> + dev_dbg(&pdev->dev, "STCSCH: 0x%06x\n", ch_status);
> +
> + ch_status =3D reverse_bits(ctrl->ch_status[3]) << 16;
> + regmap_write(regmap, REG_SPDIF_STCSCL, ch_status);
> +
> + dev_dbg(&pdev->dev, "STCSCL: 0x%06x\n", ch_status);
> +}
> +
> +/* Set SPDIF PhaseConfig register for rx clock */
> +static int spdif_set_rx_clksrc(struct fsl_spdif_priv *spdif_priv,
> + enum spdif_gainsel gainsel, int dpll_locked)
> +{
> + enum spdif_rxclk_src clksrc =3D spdif_priv->rxclk_src;
> + struct regmap *regmap =3D spdif_priv->regmap;
> +
> + if (clksrc >=3D SRPC_CLKSRC_MAX || gainsel >=3D GAINSEL_MULTI_MAX)
> + return -EINVAL;
> +
> + regmap_update_bits(regmap, REG_SPDIF_SRPC,
> + SRPC_CLKSRC_SEL_MASK | SRPC_GAINSEL_MASK,
> + SRPC_CLKSRC_SEL_SET(clksrc) | SRPC_GAINSEL_SET(gainsel));
> +
> + return 0;
> +}
> +
> +static int spdif_clk_set_rate(struct clk *clk, unsigned long rate)
> +{
> + unsigned long rate_actual;
> +
> + rate_actual =3D clk_round_rate(clk, rate);
> + clk_set_rate(clk, rate_actual);
> +
> + return 0;
> +}
> +
> +static int spdif_set_sample_rate(struct snd_pcm_substream *substream,
> + int sample_rate)
> +{
> + struct snd_soc_pcm_runtime *rtd =3D substream->private_data;
> + struct fsl_spdif_priv *spdif_priv =3D snd_soc_dai_get_drvdata(rtd->cpu_=
dai);
> + struct spdif_mixer_control *ctrl =3D &spdif_priv->fsl_spdif_control;
> + struct regmap *regmap =3D spdif_priv->regmap;
> + struct platform_device *pdev =3D spdif_priv->pdev;
> + unsigned long csfs =3D 0;
> + u8 clk =3D -1, div =3D 1;
Not signed type?
> + u32 stc, mask, rate;
> +
> + switch (sample_rate) {
> + case 32000:
> + rate =3D SPDIF_TXRATE_32000;
> + csfs =3D IEC958_AES3_CON_FS_32000;
> + break;
> + case 44100:
> + rate =3D SPDIF_TXRATE_44100;
> + csfs =3D IEC958_AES3_CON_FS_44100;
> + break;
> + case 48000:
> + rate =3D SPDIF_TXRATE_48000;
> + csfs =3D IEC958_AES3_CON_FS_48000;
> + break;
> + default:
> + dev_err(&pdev->dev, "unsupported samplerate %d\n", sample_rate);
> + return -EINVAL;
> + }
> +
> + clk =3D spdif_priv->txclk_src[rate];
> + div =3D spdif_priv->txclk_div[rate];
> +
> + /*
> + * The S/PDIF block needs a clock of 64 * fs * div. The S/PDIF block
> + * will divide by (div). So request 64 * fs * (div+1) which will
> + * get rounded.
> + */
> + spdif_clk_set_rate(spdif_priv->txclk[rate], 64 * sample_rate * (div + 1=
));
> +
> + dev_dbg(&pdev->dev, "expected clock rate =3D %d\n",
> + (int)(64 * sample_rate * div));
> + dev_dbg(&pdev->dev, "acutal clock rate =3D %d\n",
> + (int)clk_get_rate(spdif_priv->txclk[rate]));
> +
> + /* set fs field in consumer channel status */
> + spdif_set_cstatus(ctrl, IEC958_AES3_CON_FS, csfs);
> +
> + /* select clock source and divisor */
> + stc =3D STC_TXCLK_ALL_EN | STC_TXCLK_SRC_SET(clk) | STC_TXCLK_DIV(div);
> + mask =3D STC_TXCLK_ALL_EN_MASK | STC_TXCLK_SRC_MASK | STC_TXCLK_DIV_MAS=
K;
> + regmap_update_bits(regmap, REG_SPDIF_STC, mask, stc);
> +
> + dev_dbg(&pdev->dev, "set sample rate to %d\n", sample_rate);
> +
> + return 0;
> +}
> +
> +int fsl_spdif_startup(struct snd_pcm_substream *substream,
> + struct snd_soc_dai *cpu_dai)
> +{
> + struct snd_soc_pcm_runtime *rtd =3D substream->private_data;
> + struct fsl_spdif_priv *spdif_priv =3D snd_soc_dai_get_drvdata(rtd->cpu_=
dai);
> + struct regmap *regmap =3D spdif_priv->regmap;
> + u32 scr, mask, i;
> +
> + /* Reset module and interrupts only for first initialization */
> + if (!cpu_dai->active) {
> + spdif_softreset(spdif_priv);
> +
> + /* disable all the interrupts */
> + regmap_update_bits(regmap, REG_SPDIF_SIE, 0xffffff, 0);
> + }
> +
> + if (substream->stream =3D=3D SNDRV_PCM_STREAM_PLAYBACK) {
> + scr =3D SCR_TXFIFO_AUTOSYNC | SCR_TXFIFO_CTRL_NORMAL |
> + SCR_TXSEL_NORMAL | SCR_USRC_SEL_CHIP |
> + SCR_TXFIFO_FSEL_IF8;
> + mask =3D SCR_TXFIFO_AUTOSYNC_MASK | SCR_TXFIFO_CTRL_MASK |
> + SCR_TXSEL_MASK | SCR_USRC_SEL_MASK |
> + SCR_TXFIFO_FSEL_MASK;
> + for (i =3D 0; i < SPDIF_TXRATE_MAX; i++)
> + clk_enable(spdif_priv->txclk[i]);
> + } else {
> + scr =3D SCR_RXFIFO_FSEL_IF8 | SCR_RXFIFO_AUTOSYNC;
> + mask =3D SCR_RXFIFO_FSEL_MASK | SCR_RXFIFO_AUTOSYNC_MASK|
> + SCR_RXFIFO_CTL_MASK | SCR_RXFIFO_OFF_MASK;
> + clk_enable(spdif_priv->rxclk);
> + }
> + regmap_update_bits(regmap, REG_SPDIF_SCR, mask, scr);
> +
> + /* Power up SPDIF module */
> + regmap_update_bits(regmap, REG_SPDIF_SCR, SCR_LOW_POWER, 0);
> +
> + return 0;
> +}
> +
> +static void fsl_spdif_shutdown(struct snd_pcm_substream *substream,
> + struct snd_soc_dai *cpu_dai)
> +{
> + struct snd_soc_pcm_runtime *rtd =3D substream->private_data;
> + struct fsl_spdif_priv *spdif_priv =3D snd_soc_dai_get_drvdata(rtd->cpu_=
dai);
> + struct regmap *regmap =3D spdif_priv->regmap;
> + u32 scr, mask, i;
> +
> + if (substream->stream =3D=3D SNDRV_PCM_STREAM_PLAYBACK) {
> + scr =3D 0;
> + mask =3D SCR_TXFIFO_AUTOSYNC_MASK | SCR_TXFIFO_CTRL_MASK |
> + SCR_TXSEL_MASK | SCR_USRC_SEL_MASK |
> + SCR_TXFIFO_FSEL_MASK;
> + for (i =3D 0; i < SPDIF_TXRATE_MAX; i++)
> + clk_disable(spdif_priv->txclk[i]);
> + } else {
> + scr =3D SCR_RXFIFO_OFF | SCR_RXFIFO_CTL_ZERO;
> + mask =3D SCR_RXFIFO_FSEL_MASK | SCR_RXFIFO_AUTOSYNC_MASK|
> + SCR_RXFIFO_CTL_MASK | SCR_RXFIFO_OFF_MASK;
> + clk_disable(spdif_priv->rxclk);
> + }
> + regmap_update_bits(regmap, REG_SPDIF_SCR, mask, scr);
> +
> + /* Power down SPDIF module only if tx&rx are both inactive */
> + if (!cpu_dai->active) {
> + spdif_intr_status_clear(spdif_priv);
> + regmap_update_bits(regmap, REG_SPDIF_SCR,
> + SCR_LOW_POWER, SCR_LOW_POWER);
> + }
> +}
> +
> +static int fsl_spdif_hw_params(struct snd_pcm_substream *substream,
> + struct snd_pcm_hw_params *params,
> + struct snd_soc_dai *dai)
> +{
> + struct snd_soc_pcm_runtime *rtd =3D substream->private_data;
> + struct fsl_spdif_priv *spdif_priv =3D snd_soc_dai_get_drvdata(rtd->cpu_=
dai);
> + struct spdif_mixer_control *ctrl =3D &spdif_priv->fsl_spdif_control;
> + struct platform_device *pdev =3D spdif_priv->pdev;
> + u32 sample_rate =3D params_rate(params);
> + int ret =3D 0;
> +
> + if (substream->stream =3D=3D SNDRV_PCM_STREAM_PLAYBACK) {
> + ret =3D spdif_set_sample_rate(substream, sample_rate);
> + if (ret) {
> + dev_err(&pdev->dev, "%s: set sample rate failed: %d\n",
> + __func__, sample_rate);
> + return ret;
> + }
> + spdif_set_cstatus(ctrl, IEC958_AES3_CON_CLOCK,
> + IEC958_AES3_CON_CLOCK_1000PPM);
> + spdif_write_channel_status(spdif_priv);
> + } else {
> + /* setup rx clock source */
> + ret =3D spdif_set_rx_clksrc(spdif_priv, SPDIF_DEFAULT_GAINSEL, 1);
> + }
> +
> + return ret;
> +}
> +
> +static int fsl_spdif_trigger(struct snd_pcm_substream *substream,
> + int cmd, struct snd_soc_dai *dai)
> +{
> + struct snd_soc_pcm_runtime *rtd =3D substream->private_data;
> + struct fsl_spdif_priv *spdif_priv =3D snd_soc_dai_get_drvdata(rtd->cpu_=
dai);
> + struct regmap *regmap =3D spdif_priv->regmap;
> + int is_playack =3D (substream->stream =3D=3D SNDRV_PCM_STREAM_PLAYBACK)=
;
> + u32 intr =3D is_playack ? INTR_FOR_PLAYBACK : INTR_FOR_CAPTURE;
> + u32 dmaen =3D is_playack ? SCR_DMA_TX_EN : SCR_DMA_RX_EN;;
> +
> + switch (cmd) {
> + case SNDRV_PCM_TRIGGER_START:
> + case SNDRV_PCM_TRIGGER_RESUME:
> + case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
> + regmap_update_bits(regmap, REG_SPDIF_SIE, intr, intr);
> + regmap_update_bits(regmap, REG_SPDIF_SCR, dmaen, dmaen);
> + dumpregs(spdif_priv);
> + break;
> + case SNDRV_PCM_TRIGGER_STOP:
> + case SNDRV_PCM_TRIGGER_SUSPEND:
> + case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
> + regmap_update_bits(regmap, REG_SPDIF_SCR, dmaen, 0);
> + regmap_update_bits(regmap, REG_SPDIF_SIE, intr, 0);
> + break;
> + default:
> + return -EINVAL;
> + }
> +
> + return 0;
> +}
> +
> +struct snd_soc_dai_ops fsl_spdif_dai_ops =3D {
> + .startup =3D fsl_spdif_startup,
> + .hw_params =3D fsl_spdif_hw_params,
> + .trigger =3D fsl_spdif_trigger,
> + .shutdown =3D fsl_spdif_shutdown,
> +};
> +
> +
> +/*
> + * =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D
> + * FSL SPDIF IEC958 controller(mixer) functions
> + *
> + * Channel status get/put control
> + * User bit value get/put control
> + * Valid bit value get control
> + * DPLL lock status get control
> + * User bit sync mode selection control
> + * =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D
> + */
> +
> +static int fsl_spdif_info(struct snd_kcontrol *kcontrol,
> + struct snd_ctl_elem_info *uinfo)
> +{
> + uinfo->type =3D SNDRV_CTL_ELEM_TYPE_IEC958;
> + uinfo->count =3D 1;
> +
> + return 0;
> +}
> +
> +static int fsl_spdif_pb_get(struct snd_kcontrol *kcontrol,
> + struct snd_ctl_elem_value *uvalue)
> +{
> + struct snd_soc_dai *cpu_dai =3D snd_kcontrol_chip(kcontrol);
> + struct fsl_spdif_priv *spdif_priv =3D snd_soc_dai_get_drvdata(cpu_dai);
> + struct spdif_mixer_control *ctrl =3D &spdif_priv->fsl_spdif_control;
> +
> + uvalue->value.iec958.status[0] =3D ctrl->ch_status[0];
> + uvalue->value.iec958.status[1] =3D ctrl->ch_status[1];
> + uvalue->value.iec958.status[2] =3D ctrl->ch_status[2];
> + uvalue->value.iec958.status[3] =3D ctrl->ch_status[3];
> +
> + return 0;
> +}
> +
> +static int fsl_spdif_pb_put(struct snd_kcontrol *kcontrol,
> + struct snd_ctl_elem_value *uvalue)
> +{
> + struct snd_soc_dai *cpu_dai =3D snd_kcontrol_chip(kcontrol);
> + struct fsl_spdif_priv *spdif_priv =3D snd_soc_dai_get_drvdata(cpu_dai);
> + struct spdif_mixer_control *ctrl =3D &spdif_priv->fsl_spdif_control;
> +
> + ctrl->ch_status[0] =3D uvalue->value.iec958.status[0];
> + ctrl->ch_status[1] =3D uvalue->value.iec958.status[1];
> + ctrl->ch_status[2] =3D uvalue->value.iec958.status[2];
> + ctrl->ch_status[3] =3D uvalue->value.iec958.status[3];
> +
> + spdif_write_channel_status(spdif_priv);
> +
> + return 0;
> +}
> +
> +/* Get channel status from SPDIF_RX_CCHAN register */
> +static int fsl_spdif_capture_get(struct snd_kcontrol *kcontrol,
> + struct snd_ctl_elem_value *ucontrol)
> +{
> + struct snd_soc_dai *cpu_dai =3D snd_kcontrol_chip(kcontrol);
> + struct fsl_spdif_priv *spdif_priv =3D snd_soc_dai_get_drvdata(cpu_dai);
> + struct regmap *regmap =3D spdif_priv->regmap;
> + u32 cstatus, val;
> +
> + regmap_read(regmap, REG_SPDIF_SIS, &val);
> + if (!(val & INT_CNEW)) {
> + return -EAGAIN;
> + }
> +
> + regmap_read(regmap, REG_SPDIF_SRCSH, &cstatus);
> + ucontrol->value.iec958.status[0] =3D (cstatus >> 16) & 0xFF;
> + ucontrol->value.iec958.status[1] =3D (cstatus >> 8) & 0xFF;
> + ucontrol->value.iec958.status[2] =3D cstatus & 0xFF;
> +
> + regmap_read(regmap, REG_SPDIF_SRCSL, &cstatus);
> + ucontrol->value.iec958.status[3] =3D (cstatus >> 16) & 0xFF;
> + ucontrol->value.iec958.status[4] =3D (cstatus >> 8) & 0xFF;
> + ucontrol->value.iec958.status[5] =3D cstatus & 0xFF;
> +
> + /* clear intr */
> + regmap_write(regmap, REG_SPDIF_SIC, INT_CNEW);
> +
> + return 0;
> +}
> +
> +/*
> + * Get User bits (subcode) from chip value which readed out
> + * in UChannel register.
> + */
> +static int fsl_spdif_subcode_get(struct snd_kcontrol *kcontrol,
> + struct snd_ctl_elem_value *ucontrol)
> +{
> + struct snd_soc_dai *cpu_dai =3D snd_kcontrol_chip(kcontrol);
> + struct fsl_spdif_priv *spdif_priv =3D snd_soc_dai_get_drvdata(cpu_dai);
> + struct spdif_mixer_control *ctrl =3D &spdif_priv->fsl_spdif_control;
> + unsigned long flags;
> + int ret =3D 0;
> +
> + spin_lock_irqsave(&ctrl->ctl_lock, flags);
> + if (ctrl->ready_buf) {
> + int idx =3D (ctrl->ready_buf - 1) * SPDIF_UBITS_SIZE;
> + memcpy(&ucontrol->value.iec958.subcode[0],
> + &ctrl->subcode[idx], SPDIF_UBITS_SIZE);
> + } else {
> + ret =3D -EAGAIN;
> + }
> + spin_unlock_irqrestore(&ctrl->ctl_lock, flags);
> +
> + return ret;
> +}
> +
> +/* Q-subcode infomation. The byte size is SPDIF_UBITS_SIZE/8 */
> +static int fsl_spdif_qinfo(struct snd_kcontrol *kcontrol,
> + struct snd_ctl_elem_info *uinfo)
> +{
> + uinfo->type =3D SNDRV_CTL_ELEM_TYPE_BYTES;
> + uinfo->count =3D SPDIF_QSUB_SIZE;
> +
> + return 0;
> +}
> +
> +/* Get Q subcode from chip value which readed out in QChannel register *=
/
> +static int fsl_spdif_qget(struct snd_kcontrol *kcontrol,
> + struct snd_ctl_elem_value *ucontrol)
> +{
> + struct snd_soc_dai *cpu_dai =3D snd_kcontrol_chip(kcontrol);
> + struct fsl_spdif_priv *spdif_priv =3D snd_soc_dai_get_drvdata(cpu_dai);
> + struct spdif_mixer_control *ctrl =3D &spdif_priv->fsl_spdif_control;
> + unsigned long flags;
> + int ret =3D 0;
> +
> + spin_lock_irqsave(&ctrl->ctl_lock, flags);
> + if (ctrl->ready_buf) {
> + int idx =3D (ctrl->ready_buf - 1) * SPDIF_QSUB_SIZE;
> + memcpy(&ucontrol->value.bytes.data[0],
> + &ctrl->qsub[idx], SPDIF_QSUB_SIZE);
> + } else {
> + ret =3D -EAGAIN;
> + }
> + spin_unlock_irqrestore(&ctrl->ctl_lock, flags);
> +
> + return ret;
> +}
> +
> +/* Valid bit infomation */
> +static int fsl_spdif_vbit_info(struct snd_kcontrol *kcontrol,
> + struct snd_ctl_elem_info *uinfo)
> +{
> + uinfo->type =3D SNDRV_CTL_ELEM_TYPE_BOOLEAN;
> + uinfo->count =3D 1;
> + uinfo->value.integer.min =3D 0;
> + uinfo->value.integer.max =3D 1;
> +
> + return 0;
> +}
> +
> +/* Get valid good bit from interrupt status register */
> +static int fsl_spdif_vbit_get(struct snd_kcontrol *kcontrol,
> + struct snd_ctl_elem_value *ucontrol)
> +{
> + struct snd_soc_dai *cpu_dai =3D snd_kcontrol_chip(kcontrol);
> + struct fsl_spdif_priv *spdif_priv =3D snd_soc_dai_get_drvdata(cpu_dai);
> + struct regmap *regmap =3D spdif_priv->regmap;
> + u32 val;
> +
> + val =3D regmap_read(regmap, REG_SPDIF_SIS, &val);
> + ucontrol->value.integer.value[0] =3D (val & INT_VAL_NOGOOD) !=3D 0;
> + regmap_write(regmap, REG_SPDIF_SIC, INT_VAL_NOGOOD);
> +
> + return 0;
> +}
> +
> +/* DPLL lock infomation */
> +static int fsl_spdif_rxrate_info(struct snd_kcontrol *kcontrol,
> + struct snd_ctl_elem_info *uinfo)
> +{
> + uinfo->type =3D SNDRV_CTL_ELEM_TYPE_INTEGER;
> + uinfo->count =3D 1;
> + uinfo->value.integer.min =3D 16000;
> + uinfo->value.integer.max =3D 96000;
> +
> + return 0;
> +}
> +
> +static u32 gainsel_multi[GAINSEL_MULTI_MAX] =3D {
> + 24, 16, 12, 8, 6, 4, 3,
> +};
> +
> +/* Get RX data clock rate given the SPDIF bus_clk */
> +static int spdif_get_rxclk_rate(struct fsl_spdif_priv *spdif_priv,
> + enum spdif_gainsel gainsel)
> +{
> + struct regmap *regmap =3D spdif_priv->regmap;
> + struct platform_device *pdev =3D spdif_priv->pdev;
> + u64 tmpval64, busclk_freq =3D 0;
> + u32 freqmeas, phaseconf;
> + enum spdif_rxclk_src clksrc;
> +
> + regmap_read(regmap, REG_SPDIF_SRFM, &freqmeas);
> + regmap_read(regmap, REG_SPDIF_SRPC, &phaseconf);
> +
> + clksrc =3D (phaseconf >> SRPC_CLKSRC_SEL_OFFSET) & 0xf;
> + if (srpc_dpll_locked[clksrc] && (phaseconf & SRPC_DPLL_LOCKED)) {
> + /* get bus clock from system */
> + busclk_freq =3D clk_get_rate(spdif_priv->rxclk);
> + }
> +
> + /* FreqMeas_CLK =3D (BUS_CLK * FreqMeas) / 2 ^ 10 / GAINSEL / 128 */
> + tmpval64 =3D (u64) busclk_freq * freqmeas;
> + do_div(tmpval64, gainsel_multi[gainsel] * 1024);
> + do_div(tmpval64, 128 * 1024);
> +
> + dev_dbg(&pdev->dev, "FreqMeas: %d\n", (int)freqmeas);
> + dev_dbg(&pdev->dev, "BusclkFreq: %d\n", (int)busclk_freq);
> + dev_dbg(&pdev->dev, "RxRate: %d\n", (int)tmpval64);
> +
> + return (int)tmpval64;
> +}
> +
> +/*
> + * Get DPLL lock or not info from stable interrupt status register.
> + * User application must use this control to get locked,
> + * then can do next PCM operation
> + */
> +static int fsl_spdif_rxrate_get(struct snd_kcontrol *kcontrol,
> + struct snd_ctl_elem_value *ucontrol)
> +{
> + struct snd_soc_dai *cpu_dai =3D snd_kcontrol_chip(kcontrol);
> + struct fsl_spdif_priv *spdif_priv =3D snd_soc_dai_get_drvdata(cpu_dai);
> + int rate =3D spdif_get_rxclk_rate(spdif_priv, SPDIF_DEFAULT_GAINSEL);
> +
> + if (atomic_read(&spdif_priv->dpll_locked))
> + ucontrol->value.integer.value[0] =3D rate;
> + else
> + ucontrol->value.integer.value[0] =3D 0;
> +
> + return 0;
> +}
> +
> +/* User bit sync mode info */
> +static int fsl_spdif_usync_info(struct snd_kcontrol *kcontrol,
> + struct snd_ctl_elem_info *uinfo)
> +{
> + uinfo->type =3D SNDRV_CTL_ELEM_TYPE_BOOLEAN;
> + uinfo->count =3D 1;
> + uinfo->value.integer.min =3D 0;
> + uinfo->value.integer.max =3D 1;
> +
> + return 0;
> +}
> +
> +/*
> + * User bit sync mode:
> + * 1 CD User channel subcode
> + * 0 Non-CD data
> + */
> +static int fsl_spdif_usync_get(struct snd_kcontrol *kcontrol,
> + struct snd_ctl_elem_value *ucontrol)
> +{
> + struct snd_soc_dai *cpu_dai =3D snd_kcontrol_chip(kcontrol);
> + struct fsl_spdif_priv *spdif_priv =3D snd_soc_dai_get_drvdata(cpu_dai);
> + struct regmap *regmap =3D spdif_priv->regmap;
> + u32 val;
> +
> + regmap_read(regmap, REG_SPDIF_SRCD, &val);
> + ucontrol->value.integer.value[0] =3D (val & SRCD_CD_USER) !=3D 0;
> +
> + return 0;
> +}
> +
> +/*
> + * User bit sync mode:
> + * 1 CD User channel subcode
> + * 0 Non-CD data
> + */
> +static int fsl_spdif_usync_put(struct snd_kcontrol *kcontrol,
> + struct snd_ctl_elem_value *ucontrol)
> +{
> + struct snd_soc_dai *cpu_dai =3D snd_kcontrol_chip(kcontrol);
> + struct fsl_spdif_priv *spdif_priv =3D snd_soc_dai_get_drvdata(cpu_dai);
> + struct regmap *regmap =3D spdif_priv->regmap;
> + u32 val =3D ucontrol->value.integer.value[0] << SRCD_CD_USER_OFFSET;
> +
> + regmap_update_bits(regmap, REG_SPDIF_SRCD, SRCD_CD_USER, val);
> +
> + return 0;
> +}
> +
> +/* FSL SPDIF IEC958 controller defines */
> +static struct snd_kcontrol_new fsl_spdif_ctrls[] =3D {
> + /* status cchanel controller */
> + {
> + .iface =3D SNDRV_CTL_ELEM_IFACE_MIXER,
> + .name =3D SNDRV_CTL_NAME_IEC958("", PLAYBACK, DEFAULT),
> + .access =3D SNDRV_CTL_ELEM_ACCESS_READ |
> + SNDRV_CTL_ELEM_ACCESS_WRITE |
> + SNDRV_CTL_ELEM_ACCESS_VOLATILE,
> + .info =3D fsl_spdif_info,
> + .get =3D fsl_spdif_pb_get,
> + .put =3D fsl_spdif_pb_put,
> + },
> + {
> + .iface =3D SNDRV_CTL_ELEM_IFACE_PCM,
> + .name =3D SNDRV_CTL_NAME_IEC958("", CAPTURE, DEFAULT),
> + .access =3D SNDRV_CTL_ELEM_ACCESS_READ |
> + SNDRV_CTL_ELEM_ACCESS_VOLATILE,
> + .info =3D fsl_spdif_info,
> + .get =3D fsl_spdif_capture_get,
> + },
> + /* user bits controller */
> + {
> + .iface =3D SNDRV_CTL_ELEM_IFACE_PCM,
> + .name =3D "IEC958 Subcode Capture Default",
> + .access =3D SNDRV_CTL_ELEM_ACCESS_READ |
> + SNDRV_CTL_ELEM_ACCESS_VOLATILE,
> + .info =3D fsl_spdif_info,
> + .get =3D fsl_spdif_subcode_get,
> + },
> + {
> + .iface =3D SNDRV_CTL_ELEM_IFACE_PCM,
> + .name =3D "IEC958 Q-subcode Capture Default",
> + .access =3D SNDRV_CTL_ELEM_ACCESS_READ |
> + SNDRV_CTL_ELEM_ACCESS_VOLATILE,
> + .info =3D fsl_spdif_qinfo,
> + .get =3D fsl_spdif_qget,
> + },
> + /* valid bit error controller */
> + {
> + .iface =3D SNDRV_CTL_ELEM_IFACE_PCM,
> + .name =3D "IEC958 V-Bit Errors",
> + .access =3D SNDRV_CTL_ELEM_ACCESS_READ |
> + SNDRV_CTL_ELEM_ACCESS_VOLATILE,
> + .info =3D fsl_spdif_vbit_info,
> + .get =3D fsl_spdif_vbit_get,
> + },
> + /* DPLL lock info get controller */
> + {
> + .iface =3D SNDRV_CTL_ELEM_IFACE_PCM,
> + .name =3D "RX Sample Rate",
> + .access =3D SNDRV_CTL_ELEM_ACCESS_READ |
> + SNDRV_CTL_ELEM_ACCESS_VOLATILE,
> + .info =3D fsl_spdif_rxrate_info,
> + .get =3D fsl_spdif_rxrate_get,
> + },
> + /* User bit sync mode set/get controller */
> + {
> + .iface =3D SNDRV_CTL_ELEM_IFACE_PCM,
> + .name =3D "IEC958 USyncMode CDText",
> + .access =3D SNDRV_CTL_ELEM_ACCESS_READ |
> + SNDRV_CTL_ELEM_ACCESS_WRITE |
> + SNDRV_CTL_ELEM_ACCESS_VOLATILE,
> + .info =3D fsl_spdif_usync_info,
> + .get =3D fsl_spdif_usync_get,
> + .put =3D fsl_spdif_usync_put,
> + },
> +};
> +
> +static int fsl_spdif_dai_probe(struct snd_soc_dai *dai)
> +{
> + struct fsl_spdif_priv *spdif_private =3D snd_soc_dai_get_drvdata(dai);
> +
> + dai->playback_dma_data =3D &spdif_private->dma_params_tx;
> + dai->capture_dma_data =3D &spdif_private->dma_params_rx;
> +
> + snd_soc_add_dai_controls(dai, fsl_spdif_ctrls,
> ARRAY_SIZE(fsl_spdif_ctrls));
> +
> + return 0;
> +}
> +
> +struct snd_soc_dai_driver fsl_spdif_dai =3D {
> + .probe =3D &fsl_spdif_dai_probe,
> + .playback =3D {
> + .channels_min =3D 2,
> + .channels_max =3D 2,
> + .rates =3D FSL_SPDIF_RATES_PLAYBACK,
> + .formats =3D FSL_SPDIF_FORMATS_PLAYBACK,
> + },
> + .capture =3D {
> + .channels_min =3D 2,
> + .channels_max =3D 2,
> + .rates =3D FSL_SPDIF_RATES_CAPTURE,
> + .formats =3D FSL_SPDIF_FORMATS_CAPTURE,
> + },
> + .ops =3D &fsl_spdif_dai_ops,
> +};
> +
> +static const struct snd_soc_component_driver fsl_spdif_component =3D {
> + .name =3D "fsl-spdif",
> +};
> +
> +/*
> + * =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D
> + * FSL SPDIF REGMAP
> + * =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D
> + */
> +
> +static bool fsl_spdif_readable_reg(struct device *dev, unsigned int reg)
> +{
> + switch (reg) {
> + case REG_SPDIF_SCR:
> + case REG_SPDIF_SRCD:
> + case REG_SPDIF_SRPC:
> + case REG_SPDIF_SIE:
> + case REG_SPDIF_SIS:
> + case REG_SPDIF_SRL:
> + case REG_SPDIF_SRR:
> + case REG_SPDIF_SRCSH:
> + case REG_SPDIF_SRCSL:
> + case REG_SPDIF_SRU:
> + case REG_SPDIF_SRQ:
> + case REG_SPDIF_STCSCH:
> + case REG_SPDIF_STCSCL:
> + case REG_SPDIF_SRFM:
> + case REG_SPDIF_STC:
> + return true;
> + default:
> + return false;
> + };
> +}
> +
> +static bool fsl_spdif_writeable_reg(struct device *dev, unsigned int reg=
)
> +{
> + switch (reg) {
> + case REG_SPDIF_SCR:
> + case REG_SPDIF_SRCD:
> + case REG_SPDIF_SRPC:
> + case REG_SPDIF_SIE:
> + case REG_SPDIF_SIC:
> + case REG_SPDIF_STL:
> + case REG_SPDIF_STR:
> + case REG_SPDIF_STCSCH:
> + case REG_SPDIF_STCSCL:
> + case REG_SPDIF_STC:
> + return true;
> + default:
> + return false;
> + };
> +}
> +
> +static bool fsl_spdif_volatile_reg(struct device *dev, unsigned int reg)
> +{
> + /* Sync all registers after reset */
Where us sync :) ?
-Bharat
> + return true;
> +}
> +
> +static const struct regmap_config fsl_spdif_regmap_config =3D {
> + .reg_bits =3D 32,
> + .reg_stride =3D 4,
> + .val_bits =3D 32,
> +
> + .max_register =3D REG_SPDIF_STC,
> + .readable_reg =3D fsl_spdif_readable_reg,
> + .writeable_reg =3D fsl_spdif_writeable_reg,
> + .volatile_reg =3D fsl_spdif_volatile_reg,
> + .cache_type =3D REGCACHE_RBTREE,
> +};
> +
> +static u32 fsl_spdif_txclk_caldiv(struct fsl_spdif_priv *spdif_priv,
> + struct clk *clk, u64 savesub,
> + enum spdif_txrate index)
> +{
> + const u32 rate[] =3D { 32000, 44100, 48000, };
> + u64 rate_ideal, rate_actual, sub;
> + u32 div, arate;
> +
> + for (div =3D 1; div <=3D 128; div++) {
> + rate_ideal =3D rate[index] * (div + 1) * 64;
> + rate_actual =3D clk_round_rate(clk, rate_ideal);
> +
> + arate =3D rate_actual / 64;
> + arate /=3D div;
> +
> + if (arate =3D=3D rate[index]) {
> + /* We are lucky */
> + savesub =3D 0;
> + spdif_priv->txclk_div[index] =3D div;
> + break;
> + } else if (arate / rate[index] =3D=3D 1) {
> + /* A little bigger than expect */
> + sub =3D (arate - rate[index]) * 100000;
> + do_div(sub, rate[index]);
> + if (sub < savesub) {
> + savesub =3D sub;
> + spdif_priv->txclk_div[index] =3D div;
> + }
> + } else if (rate[index] / arate =3D=3D 1) {
> + /* A little smaller than expect */
> + sub =3D (rate[index] - arate) * 100000;
> + do_div(sub, rate[index]);
> + if (sub < savesub) {
> + savesub =3D sub;
> + spdif_priv->txclk_div[index] =3D div;
> + }
> + }
> + }
> +
> + return savesub;
> +}
> +
> +static int fsl_spdif_probe_txclk(struct fsl_spdif_priv *spdif_priv,
> + enum spdif_txrate index)
> +{
> + const u32 rate[] =3D { 32000, 44100, 48000, };
> + struct platform_device *pdev =3D spdif_priv->pdev;
> + struct device *dev =3D &pdev->dev;
> + u64 savesub =3D 100000, ret;
> + struct clk *clk;
> + char tmp[16];
> + int i;
> +
> + for (i =3D 0; i < STC_TXCLK_SRC_MAX; i++) {
> + sprintf(tmp, "rxtx%d", i);
> + clk =3D devm_clk_get(&pdev->dev, tmp);
> + if (IS_ERR(clk)) {
> + dev_err(dev, "no rxtx%d property in devicetree\n", i);
> + return PTR_ERR(clk);
> + }
> + if (!clk_get_rate(clk))
> + continue;
> +
> + ret =3D fsl_spdif_txclk_caldiv(spdif_priv, clk, savesub, index);
> + if (savesub =3D=3D ret)
> + continue;
> +
> + savesub =3D ret;
> + spdif_priv->txclk[index] =3D clk;
> + spdif_priv->txclk_src[index] =3D i;
> +
> + /* To quick catch a divisor, we allow a 0.1% deviation */
> + if (savesub < 100)
> + break;
> + }
> +
> + dev_dbg(&pdev->dev, "use rxtx%d as tx clock source for %dHz sample rate=
",
> + spdif_priv->txclk_src[index], rate[index]);
> + dev_dbg(&pdev->dev, "use divisor %d for %dHz sample rate",
> + spdif_priv->txclk_div[index], rate[index]);
> +
> + return 0;
> +}
> +
> +static int fsl_spdif_probe(struct platform_device *pdev)
> +{
> + struct device_node *np =3D pdev->dev.of_node;
> + struct fsl_spdif_priv *spdif_priv;
> + struct spdif_mixer_control *ctrl;
> + struct resource *res;
> + void __iomem *regs;
> + int irq, ret, i;
> +
> + if (!np)
> + return -ENODEV;
> +
> + spdif_priv =3D devm_kzalloc(&pdev->dev,
> + sizeof(struct fsl_spdif_priv) + strlen(np->name) + 1,
> GFP_KERNEL);
> + if (!spdif_priv) {
> + dev_err(&pdev->dev, "could not allocate DAI object\n");
> + return -ENOMEM;
> + }
> +
> + strcpy(spdif_priv->name, np->name);
> +
> + spdif_priv->pdev =3D pdev;
> +
> + /* Initialize this copy of the CPU DAI driver structure */
> + memcpy(&spdif_priv->cpu_dai_drv, &fsl_spdif_dai, sizeof(fsl_spdif_dai))=
;
> + spdif_priv->cpu_dai_drv.name =3D spdif_priv->name;
> +
> + /* Get the addresses and IRQ */
> + res =3D platform_get_resource(pdev, IORESOURCE_MEM, 0);
> + if (IS_ERR(res)) {
> + dev_err(&pdev->dev, "could not determine device resources\n");
> + return PTR_ERR(res);
> + }
> +
> + regs =3D devm_ioremap_resource(&pdev->dev, res);
> + if (IS_ERR(regs)) {
> + dev_err(&pdev->dev, "could not map device resources\n");
> + return PTR_ERR(regs);
> + }
> +
> + spdif_priv->regmap =3D devm_regmap_init_mmio_clk(&pdev->dev,
> + "core", regs, &fsl_spdif_regmap_config);
> + if (IS_ERR(spdif_priv->regmap)) {
> + dev_err(&pdev->dev, "regmap init failed\n");
> + return PTR_ERR(spdif_priv->regmap);
> + }
> +
> + irq =3D platform_get_irq(pdev, 0);
> + if (irq < 0) {
> + dev_err(&pdev->dev, "no irq for node %s\n", np->full_name);
> + return irq;
> + }
> +
> + ret =3D devm_request_irq(&pdev->dev, irq, spdif_isr, 0,
> + spdif_priv->name, spdif_priv);
> + if (ret) {
> + dev_err(&pdev->dev, "could not claim irq %u\n", irq);
> + return ret;
> + }
> +
> + /* Select clock source for rx/tx clock */
> + spdif_priv->rxclk =3D devm_clk_get(&pdev->dev, "rxtx1");
> + if (IS_ERR(spdif_priv->rxclk)) {
> + dev_err(&pdev->dev, "no rxtx1 property in devicetree\n");
> + return PTR_ERR(spdif_priv->rxclk);
> + }
> + spdif_priv->rxclk_src =3D DEFAULT_RXCLK_SRC;
> +
> + for (i =3D 0; i < SPDIF_TXRATE_MAX; i++) {
> + ret =3D fsl_spdif_probe_txclk(spdif_priv, i);
> + if (ret)
> + return ret;
> + }
> +
> + /* Prepare rx/tx clock */
> + clk_prepare(spdif_priv->rxclk);
> + for (i =3D 0; i < SPDIF_TXRATE_MAX; i++)
> + clk_prepare(spdif_priv->txclk[i]);
> +
> + /* initial spinlock for control data */
> + ctrl =3D &spdif_priv->fsl_spdif_control;
> + spin_lock_init(&ctrl->ctl_lock);
> +
> + /* init tx channel status default value */
> + ctrl->ch_status[0] =3D
> + IEC958_AES0_CON_NOT_COPYRIGHT | IEC958_AES0_CON_EMPHASIS_5015;
> + ctrl->ch_status[1] =3D IEC958_AES1_CON_DIGDIGCONV_ID;
> + ctrl->ch_status[2] =3D 0x00;
> + ctrl->ch_status[3] =3D
> + IEC958_AES3_CON_FS_44100 | IEC958_AES3_CON_CLOCK_1000PPM;
> +
> + atomic_set(&spdif_priv->dpll_locked, 0);
> +
> + spdif_priv->dma_params_tx.maxburst =3D FSL_SPDIF_TXFIFO_WML;
> + spdif_priv->dma_params_rx.maxburst =3D FSL_SPDIF_RXFIFO_WML;
> + spdif_priv->dma_params_tx.addr =3D res->start + REG_SPDIF_STL;
> + spdif_priv->dma_params_rx.addr =3D res->start + REG_SPDIF_SRL;
> +
> + /* Register with ASoC */
> + dev_set_drvdata(&pdev->dev, spdif_priv);
> +
> + ret =3D snd_soc_register_component(&pdev->dev, &fsl_spdif_component,
> + &spdif_priv->cpu_dai_drv, 1);
> + if (ret) {
> + dev_err(&pdev->dev, "failed to register DAI: %d\n", ret);
> + goto error_dev;
> + }
> +
> + ret =3D imx_pcm_dma_init(pdev);
> + if (ret) {
> + dev_err(&pdev->dev, "imx_pcm_dma_init failed: %d\n", ret);
> + goto error_component;
> + }
> +
> + return ret;
> +
> +error_component:
> + snd_soc_unregister_component(&pdev->dev);
> +error_dev:
> + dev_set_drvdata(&pdev->dev, NULL);
> + for (i =3D 0; i < SPDIF_TXRATE_MAX; i++)
> + clk_unprepare(spdif_priv->txclk[i]);
> + clk_unprepare(spdif_priv->rxclk);
> +
> + return ret;
> +}
> +
> +static int fsl_spdif_remove(struct platform_device *pdev)
> +{
> + struct fsl_spdif_priv *spdif_priv =3D platform_get_drvdata(pdev);
> + int i;
> +
> + imx_pcm_dma_exit(pdev);
> + snd_soc_unregister_component(&pdev->dev);
> +
> + for (i =3D 0; i < SPDIF_TXRATE_MAX; i++)
> + clk_unprepare(spdif_priv->txclk[i]);
> + clk_unprepare(spdif_priv->rxclk);
> +
> + dev_set_drvdata(&pdev->dev, NULL);
> +
> + return 0;
> +}
> +
> +static const struct of_device_id fsl_spdif_dt_ids[] =3D {
> + { .compatible =3D "fsl,imx35-spdif", },
> + {}
> +};
> +MODULE_DEVICE_TABLE(of, fsl_spdif_dt_ids);
> +
> +static struct platform_driver fsl_spdif_driver =3D {
> + .driver =3D {
> + .name =3D "fsl-spdif-dai",
> + .owner =3D THIS_MODULE,
> + .of_match_table =3D fsl_spdif_dt_ids,
> + },
> + .probe =3D fsl_spdif_probe,
> + .remove =3D fsl_spdif_remove,
> +};
> +
> +module_platform_driver(fsl_spdif_driver);
> +
> +MODULE_AUTHOR("Freescale Semiconductor, Inc.");
> +MODULE_DESCRIPTION("Freescale S/PDIF CPU DAI Driver");
> +MODULE_LICENSE("GPL v2");
> +MODULE_ALIAS("platform:fsl-spdif-dai");
> diff --git a/sound/soc/fsl/fsl_spdif.h b/sound/soc/fsl/fsl_spdif.h
> new file mode 100644
> index 0000000..f8357f6
> --- /dev/null
> +++ b/sound/soc/fsl/fsl_spdif.h
> @@ -0,0 +1,224 @@
> +/*
> + * fsl_spdif.h - ALSA S/PDIF interface for the Freescale i.MX SoC
> + *
> + * Copyright (C) 2013 Freescale Semiconductor, Inc.
> + *
> + * Author: Nicolin Chen <b42378@freescale.com>
> + *
> + * Based on fsl_ssi.h
> + * Author: Timur Tabi <timur@freescale.com>
> + * Copyright 2007-2008 Freescale Semiconductor, Inc.
> + *
> + * This file is licensed under the terms of the GNU General Public Licen=
se
> + * version 2. This program is licensed "as is" without any warranty of=
any
> + * kind, whether express or implied.
> + */
> +
> +#ifndef _FSL_SPDIF_DAI_H
> +#define _FSL_SPDIF_DAI_H
> +
> +/* S/PDIF Register Map */
> +#define REG_SPDIF_SCR 0x0 /* SPDIF Configuration Register */
> +#define REG_SPDIF_SRCD 0x4 /* CDText Control Register */
> +#define REG_SPDIF_SRPC 0x8 /* PhaseConfig Register */
> +#define REG_SPDIF_SIE 0xc /* InterruptEn Register */
> +#define REG_SPDIF_SIS 0x10 /* InterruptStat Register */
> +#define REG_SPDIF_SIC 0x10 /* InterruptClear Register */
> +#define REG_SPDIF_SRL 0x14 /* SPDIFRxLeft Register */
> +#define REG_SPDIF_SRR 0x18 /* SPDIFRxRight Register */
> +#define REG_SPDIF_SRCSH 0x1c /* SPDIFRxCChannel_h Register */
> +#define REG_SPDIF_SRCSL 0x20 /* SPDIFRxCChannel_l Register */
> +#define REG_SPDIF_SRU 0x24 /* UchannelRx Register */
> +#define REG_SPDIF_SRQ 0x28 /* QchannelRx Register */
> +#define REG_SPDIF_STL 0x2C /* SPDIFTxLeft Register */
> +#define REG_SPDIF_STR 0x30 /* SPDIFTxRight Register */
> +#define REG_SPDIF_STCSCH 0x34 /* SPDIFTxCChannelCons_h Register */
> +#define REG_SPDIF_STCSCL 0x38 /* SPDIFTxCChannelCons_l Register */
> +#define REG_SPDIF_SRFM 0x44 /* FreqMeas Register */
> +#define REG_SPDIF_STC 0x50 /* SPDIFTxClk Register */
> +
> +
> +/* SPDIF Configuration register */
> +#define SCR_RXFIFO_CTL_OFFSET 23
> +#define SCR_RXFIFO_CTL_MASK (1 << SCR_RXFIFO_CTL_OFFSET)
> +#define SCR_RXFIFO_CTL_ZERO (1 << SCR_RXFIFO_CTL_OFFSET)
> +#define SCR_RXFIFO_OFF_OFFSET 22
> +#define SCR_RXFIFO_OFF_MASK (1 << SCR_RXFIFO_OFF_OFFSET)
> +#define SCR_RXFIFO_OFF (1 << SCR_RXFIFO_OFF_OFFSET)
> +#define SCR_RXFIFO_RST_OFFSET 21
> +#define SCR_RXFIFO_RST_MASK (1 << SCR_RXFIFO_RST_OFFSET)
> +#define SCR_RXFIFO_RST (1 << SCR_RXFIFO_RST_OFFSET)
> +#define SCR_RXFIFO_FSEL_OFFSET 19
> +#define SCR_RXFIFO_FSEL_MASK (0x3 << SCR_RXFIFO_FSEL_OFFSET)
> +#define SCR_RXFIFO_FSEL_IF0 (0x0 << SCR_RXFIFO_FSEL_OFFSET)
> +#define SCR_RXFIFO_FSEL_IF4 (0x1 << SCR_RXFIFO_FSEL_OFFSET)
> +#define SCR_RXFIFO_FSEL_IF8 (0x2 << SCR_RXFIFO_FSEL_OFFSET)
> +#define SCR_RXFIFO_FSEL_IF12 (0x3 << SCR_RXFIFO_FSEL_OFFSET)
> +#define SCR_RXFIFO_AUTOSYNC_OFFSET 18
> +#define SCR_RXFIFO_AUTOSYNC_MASK (1 << SCR_RXFIFO_AUTOSYNC_OFFSET)
> +#define SCR_RXFIFO_AUTOSYNC (1 << SCR_RXFIFO_AUTOSYNC_OFFSET)
> +#define SCR_TXFIFO_AUTOSYNC_OFFSET 17
> +#define SCR_TXFIFO_AUTOSYNC_MASK (1 << SCR_TXFIFO_AUTOSYNC_OFFSET)
> +#define SCR_TXFIFO_AUTOSYNC (1 << SCR_TXFIFO_AUTOSYNC_OFFSET)
> +#define SCR_TXFIFO_FSEL_OFFSET 15
> +#define SCR_TXFIFO_FSEL_MASK (0x3 << SCR_TXFIFO_FSEL_OFFSET)
> +#define SCR_TXFIFO_FSEL_IF0 (0x0 << SCR_TXFIFO_FSEL_OFFSET)
> +#define SCR_TXFIFO_FSEL_IF4 (0x1 << SCR_TXFIFO_FSEL_OFFSET)
> +#define SCR_TXFIFO_FSEL_IF8 (0x2 << SCR_TXFIFO_FSEL_OFFSET)
> +#define SCR_TXFIFO_FSEL_IF12 (0x3 << SCR_TXFIFO_FSEL_OFFSET)
> +#define SCR_LOW_POWER (1 << 13)
> +#define SCR_SOFT_RESET (1 << 12)
> +#define SCR_TXFIFO_CTRL_OFFSET 10
> +#define SCR_TXFIFO_CTRL_MASK (0x3 << SCR_TXFIFO_CTRL_OFFSET)
> +#define SCR_TXFIFO_CTRL_ZERO (0x0 << SCR_TXFIFO_CTRL_OFFSET)
> +#define SCR_TXFIFO_CTRL_NORMAL (0x1 << SCR_TXFIFO_CTRL_OFFSET)
> +#define SCR_TXFIFO_CTRL_ONESAMPLE (0x2 << SCR_TXFIFO_CTRL_OFFSET)
> +#define SCR_DMA_RX_EN_OFFSET 9
> +#define SCR_DMA_RX_EN_MASK (1 << SCR_DMA_RX_EN_OFFSET)
> +#define SCR_DMA_RX_EN (1 << SCR_DMA_RX_EN_OFFSET)
> +#define SCR_DMA_TX_EN_OFFSET 8
> +#define SCR_DMA_TX_EN_MASK (1 << SCR_DMA_TX_EN_OFFSET)
> +#define SCR_DMA_TX_EN (1 << SCR_DMA_TX_EN_OFFSET)
> +#define SCR_VAL_OFFSET 5
> +#define SCR_VAL_MASK (1 << SCR_VAL_OFFSET)
> +#define SCR_VAL_CLEAR (1 << SCR_VAL_OFFSET)
> +#define SCR_TXSEL_OFFSET 2
> +#define SCR_TXSEL_MASK (0x7 << SCR_TXSEL_OFFSET)
> +#define SCR_TXSEL_OFF (0 << SCR_TXSEL_OFFSET)
> +#define SCR_TXSEL_RX (1 << SCR_TXSEL_OFFSET)
> +#define SCR_TXSEL_NORMAL (0x5 << SCR_TXSEL_OFFSET)
> +#define SCR_USRC_SEL_OFFSET 0x0
> +#define SCR_USRC_SEL_MASK (0x3 << SCR_USRC_SEL_OFFSET)
> +#define SCR_USRC_SEL_NONE (0x0 << SCR_USRC_SEL_OFFSET)
> +#define SCR_USRC_SEL_RECV (0x1 << SCR_USRC_SEL_OFFSET)
> +#define SCR_USRC_SEL_CHIP (0x3 << SCR_USRC_SEL_OFFSET)
> +
> +/* SPDIF CDText control */
> +#define SRCD_CD_USER_OFFSET 1
> +#define SRCD_CD_USER (1 << SRCD_CD_USER_OFFSET)
> +
> +/* SPDIF Phase Configuration register */
> +#define SRPC_DPLL_LOCKED (1 << 6)
> +#define SRPC_CLKSRC_SEL_OFFSET 7
> +#define SRPC_CLKSRC_SEL_MASK (0xf << SRPC_CLKSRC_SEL_OFFSET)
> +#define SRPC_CLKSRC_SEL_SET(x) ((x << SRPC_CLKSRC_SEL_OFFSET) &
> SRPC_CLKSRC_SEL_MASK)
> +#define SRPC_CLKSRC_SEL_LOCKED_OFFSET1 5
> +#define SRPC_CLKSRC_SEL_LOCKED_OFFSET2 2
> +#define SRPC_GAINSEL_OFFSET 3
> +#define SRPC_GAINSEL_MASK (0x7 << SRPC_GAINSEL_OFFSET)
> +#define SRPC_GAINSEL_SET(x) ((x << SRPC_GAINSEL_OFFSET) &
> SRPC_GAINSEL_MASK)
> +
> +/* SPDIF rx clock source */
> +enum spdif_rxclk_src {
> + SRPC_CLKSRC_0 =3D 0,
> + SRPC_CLKSRC_1,
> + SRPC_CLKSRC_2,
> + SRPC_CLKSRC_3,
> + SRPC_CLKSRC_4,
> + SRPC_CLKSRC_5,
> + SRPC_CLKSRC_6,
> + SRPC_CLKSRC_7,
> + SRPC_CLKSRC_8,
> + SRPC_CLKSRC_9,
> + SRPC_CLKSRC_10,
> + SRPC_CLKSRC_11,
> + SRPC_CLKSRC_12,
> + SRPC_CLKSRC_13,
> + SRPC_CLKSRC_14,
> + SRPC_CLKSRC_15,
> +};
> +#define SRPC_CLKSRC_MAX (SRPC_CLKSRC_15 + 1)
> +#define DEFAULT_RXCLK_SRC SRPC_CLKSRC_1
> +
> +enum spdif_gainsel {
> + GAINSEL_MULTI_24 =3D 0,
> + GAINSEL_MULTI_16,
> + GAINSEL_MULTI_12,
> + GAINSEL_MULTI_8,
> + GAINSEL_MULTI_6,
> + GAINSEL_MULTI_4,
> + GAINSEL_MULTI_3,
> +};
> +#define GAINSEL_MULTI_MAX (GAINSEL_MULTI_3 + 1)
> +#define SPDIF_DEFAULT_GAINSEL GAINSEL_MULTI_8
> +
> +/* SPDIF interrupt mask define */
> +#define INT_DPLL_LOCKED (1 << 20)
> +#define INT_TXFIFO_UNOV (1 << 19)
> +#define INT_TXFIFO_RESYNC (1 << 18)
> +#define INT_CNEW (1 << 17)
> +#define INT_VAL_NOGOOD (1 << 16)
> +#define INT_SYM_ERR (1 << 15)
> +#define INT_BIT_ERR (1 << 14)
> +#define INT_URX_FUL (1 << 10)
> +#define INT_URX_OV (1 << 9)
> +#define INT_QRX_FUL (1 << 8)
> +#define INT_QRX_OV (1 << 7)
> +#define INT_UQ_SYNC (1 << 6)
> +#define INT_UQ_ERR (1 << 5)
> +#define INT_RXFIFO_UNOV (1 << 4)
> +#define INT_RXFIFO_RESYNC (1 << 3)
> +#define INT_LOSS_LOCK (1 << 2)
> +#define INT_TX_EM (1 << 1)
> +#define INT_RXFIFO_FUL (1 << 0)
> +
> +/* SPDIF Clock register */
> +#define STC_SYSCLK_DIV_OFFSET 11
> +#define STC_SYSCLK_DIV_MASK (0x1ff << STC_TXCLK_SRC_OFFSET)
> +#define STC_SYSCLK_DIV(x) ((((x) - 1) << STC_TXCLK_DIV_OFFSET) &
> STC_SYSCLK_DIV_MASK)
> +#define STC_TXCLK_SRC_OFFSET 8
> +#define STC_TXCLK_SRC_MASK (0x7 << STC_TXCLK_SRC_OFFSET)
> +#define STC_TXCLK_SRC_SET(x) ((x << STC_TXCLK_SRC_OFFSET) &
> STC_TXCLK_SRC_MASK)
> +#define STC_TXCLK_ALL_EN_OFFSET 7
> +#define STC_TXCLK_ALL_EN_MASK (1 << STC_TXCLK_ALL_EN_OFFSET)
> +#define STC_TXCLK_ALL_EN (1 << STC_TXCLK_ALL_EN_OFFSET)
> +#define STC_TXCLK_DIV_OFFSET 0
> +#define STC_TXCLK_DIV_MASK (0x7ff << STC_TXCLK_DIV_OFFSET)
> +#define STC_TXCLK_DIV(x) ((((x) - 1) << STC_TXCLK_DIV_OFFSET) &
> STC_TXCLK_DIV_MASK)
> +
> +/* SPDIF tx clksrc */
> +enum spdif_txclk_src {
> + STC_TXCLK_SRC_0 =3D 0,
> + STC_TXCLK_SRC_1,
> + STC_TXCLK_SRC_2,
> + STC_TXCLK_SRC_3,
> + STC_TXCLK_SRC_4,
> + STC_TXCLK_SRC_5,
> + STC_TXCLK_SRC_6,
> + STC_TXCLK_SRC_7,
> +};
> +#define STC_TXCLK_SRC_MAX (STC_TXCLK_SRC_7 + 1)
> +#define DEFAULT_TXCLK_SRC STC_TXCLK_SRC_1
> +
> +/* SPDIF tx rate */
> +enum spdif_txrate {
> + SPDIF_TXRATE_32000 =3D 0,
> + SPDIF_TXRATE_44100,
> + SPDIF_TXRATE_48000,
> +};
> +#define SPDIF_TXRATE_MAX (SPDIF_TXRATE_48000 + 1)
> +
> +
> +#define SPDIF_CSTATUS_BYTE 6
> +#define SPDIF_UBITS_SIZE 96
> +#define SPDIF_QSUB_SIZE (SPDIF_UBITS_SIZE / 8)
> +
> +
> +#define FSL_SPDIF_RATES_PLAYBACK (SNDRV_PCM_RATE_32000 | \
> + SNDRV_PCM_RATE_44100 | \
> + SNDRV_PCM_RATE_48000)
> +
> +#define FSL_SPDIF_RATES_CAPTURE (SNDRV_PCM_RATE_16000 | \
> + SNDRV_PCM_RATE_32000 | \
> + SNDRV_PCM_RATE_44100 | \
> + SNDRV_PCM_RATE_48000 | \
> + SNDRV_PCM_RATE_64000 | \
> + SNDRV_PCM_RATE_96000)
> +
> +#define FSL_SPDIF_FORMATS_PLAYBACK (SNDRV_PCM_FMTBIT_S16_LE | \
> + SNDRV_PCM_FMTBIT_S20_3LE | \
> + SNDRV_PCM_FMTBIT_S24_LE)
> +
> +#define FSL_SPDIF_FORMATS_CAPTURE (SNDRV_PCM_FMTBIT_S24_LE)
> +
> +#endif /* _FSL_SPDIF_DAI_H */
> --
> 1.7.1
>=20
>=20
> _______________________________________________
> Linuxppc-dev mailing list
> Linuxppc-dev@lists.ozlabs.org
> https://lists.ozlabs.org/listinfo/linuxppc-dev
^ permalink raw reply
* Re: [RFC] powerpc: put the common parts of the ppc64*defconfigs in a Kconfig file
From: Scott Wood @ 2013-08-16 21:34 UTC (permalink / raw)
To: Stephen Rothwell; +Cc: ppc-dev
In-Reply-To: <20130809162426.ecdb5b034047db309ebd2b45@canb.auug.org.au>
On Fri, 2013-08-09 at 16:24 +1000, Stephen Rothwell wrote:
> We cannot put the unsetting of config options in the Kconfig file, nor
> the integer or string options.
>
> I checked that after this we get the same .config files generated (except
> for the addition of the new PPC64_DEFCONFIG* config options.
>
> Any thoughts?
Won't this bypass the dependency mechanism? While the dependencies
should already be satisfied currently, nothing would prevent them from
being switched off later. Even if you have all the dependencies listed
in the "select", what if dependencies change later?
It seems like it would be better to have a way to apply multiple
defconfigs at once, and/or have one defconfig include another.
-Scott
^ permalink raw reply
* Re: PCIE device errors after linux kernel upgrade
From: Bjorn Helgaas @ 2013-08-16 22:05 UTC (permalink / raw)
To: Leon Ravich; +Cc: linux-pci@vger.kernel.org, linuxppc-dev
In-Reply-To: <CAPWoNkLTC+1ba3vwY0xiJVmmebvuXZBTwiyH5HAFfE8mRReaRQ@mail.gmail.com>
On Tue, Aug 6, 2013 at 11:41 PM, Leon Ravich <lravich@gmail.com> wrote:
> From comparison of pci printout from the two kernel ,
> beside the EDAC errors I noticed other strange differences:
>
> In 3.8.13 I got BAR 7 and BAR 8:
> [ 39.017749] pci 0000:00:00.0: BAR 8: assigned [mem 0xc0000000-0xdfffffff]
> [ 39.024530] pci 0000:00:00.0: BAR 7: can't assign io (size 0x10000)
>
> In 3.8.13 I am getting:
> [ 38.931873] pci_bus 0000:01: busn_res: can not insert [bus 01-ff]
> under [bus 00-01] (conflicts with (null) [bus 00-01])
>
>
> On 6 August 2013 09:32, Leon Ravich <lravich@gmail.com> wrote:
>> Thanks Bjorn.
Is this still a problem, or have you found a solution in the meantime?
>> 1) If I understand it right this patch only removes the "pci
>> 0000:00:00.0: ignoring class 0x0b2000 (doesn't
>> match header type 01)" message , don't care about it , had it before .
It also affects how the PCI core handles the device. But as you said,
if you had the message before, it's probably not the cause of the
current problem.
>> 2) regarding the comparing of printouts:
Can you post the complete logs somewhere, maybe in a bugzilla or similar?
Where are the "PCIE ERR_CAP_STAT" and similar messages from? My quick
grep didn't find them.
Bjorn
^ permalink raw reply
* Re: [RFC PATCH v2 3/4] powerpc: refactor of_get_cpu_node to support other architectures
From: Benjamin Herrenschmidt @ 2013-08-16 22:13 UTC (permalink / raw)
To: Sudeep KarkadaNagesha
Cc: Jonas Bonn, devicetree, Michal Simek, linux-pm, linux-kernel,
Rob Herring, Rafael J. Wysocki, Grant Likely, linuxppc-dev,
linux-arm-kernel
In-Reply-To: <1376674791-28244-2-git-send-email-Sudeep.KarkadaNagesha@arm.com>
On Fri, 2013-08-16 at 18:39 +0100, Sudeep KarkadaNagesha wrote:
> +static bool __of_find_n_match_cpu_property(struct device_node *cpun,
> + const char *prop_name, int cpu, unsigned int
> *thread)
> +{
> + const __be32 *cell;
> + int ac, prop_len, tid;
> + u64 hwid;
> +
> + ac = of_n_addr_cells(cpun);
> + cell = of_get_property(cpun, prop_name, &prop_len);
> + if (!cell)
> + return false;
> + prop_len /= sizeof(*cell);
> + for (tid = 0; tid < prop_len; tid++) {
> + hwid = of_read_number(cell, ac);
> + if (arch_match_cpu_phys_id(cpu, hwid)) {
> + if (thread)
> + *thread = tid;
> + return true;
> + }
> + cell += ac;
> + }
> + return false;
> +}
The only problem I can see here is if "ac" is not 1, that will not work
for the ibm,ppc-interrupt-server#s case. IE. The latter is always 1 cell
per entry, only "reg" depends on #address-cells.
However that's only a theorical problem since on ppc #address-cells of
/cpus is always 1...
Cheers,
Ben.
^ permalink raw reply
* RE: [RFC PATCH v2 00/11] Add (de)compression support to pstore
From: Luck, Tony @ 2013-08-16 22:15 UTC (permalink / raw)
To: Aruna Balakrishnaiah, linuxppc-dev@ozlabs.org,
linux-kernel@vger.kernel.org, keescook@chromium.org
Cc: jkenisto@linux.vnet.ibm.com, cbouatmailru@gmail.com,
mahesh@linux.vnet.ibm.com, ccross@android.com
In-Reply-To: <20130816131403.3338.82330.stgit@aruna-ThinkPad-T420>
PiBOZWVkcyB0ZXN0aW5nIHdpdGggZXJzdCBiYWNrZW5kLCBlZml2YXJzIGFuZCBwZXJzaXN0ZW50
IHJhbS4NCg0KVGVzdGVkIGFnYWluc3QgRVJTVCAtIHdvcmtzIGZpbmUgZm9yIG1lIG5vdy4NCg0K
TmVlZCB0byBzdGFyZSBhdCB0aGUgY29kZSB0byBzZWUgaWYgdGhlcmUgYXJlIGFueSBtb3JlIGJp
dHMgdGhhdCBjb3VsZCBiZSBjbGVhbmVkIHVwLg0KDQpUaGFua3MgZm9yIGFkZHJlc3NpbmcgbXkg
aXNzdWVzIGZyb20gdjENCg0KLVRvbnkNCg==
^ permalink raw reply
* Re: [RFC PATCH v2 4/4] of: move of_get_cpu_node implementation to DT core library
From: Benjamin Herrenschmidt @ 2013-08-16 22:14 UTC (permalink / raw)
To: Sudeep KarkadaNagesha
Cc: Jonas Bonn, devicetree, Michal Simek, linux-pm, linux-kernel,
Rob Herring, Rafael J. Wysocki, Grant Likely, linuxppc-dev,
linux-arm-kernel
In-Reply-To: <1376674791-28244-3-git-send-email-Sudeep.KarkadaNagesha@arm.com>
On Fri, 2013-08-16 at 18:39 +0100, Sudeep KarkadaNagesha wrote:
> +#ifdef CONFIG_PPC
> + /* Check for historical "ibm,ppc-interrupt-server#s" property
> + * for thread ids on PowerPC. If it doesn't exist fallback to
> + * standard "reg" property.
> + */
> + if (__of_find_n_match_cpu_property(cpun,
> + "ibm,ppc-interrupt-server#s", cpu, thread))
> + return cpun;
> +#endif
It's not "historical". It's still very much in use and well defined in PAPR :-)
Cheers,
Ben.
^ permalink raw reply
* Re: [alsa-devel] [PATCH v4 1/2] ASoC: fsl: Add S/PDIF CPU DAI driver
From: Stephen Warren @ 2013-08-16 22:49 UTC (permalink / raw)
To: Shawn Guo
Cc: devicetree, alsa-devel, lars, linuxppc-dev, Nicolin Chen, timur,
rob.herring, broonie, p.zabel, Fabio Estevam
In-Reply-To: <20130815092428.GI16915@S2101-09.ap.freescale.net>
On 08/15/2013 03:24 AM, Shawn Guo wrote:
> On Thu, Aug 15, 2013 at 10:18:23AM +0800, Nicolin Chen wrote:
>> Hi Stephen,
>>
>> On Wed, Aug 14, 2013 at 09:47:19AM -0600, Stephen Warren wrote:
>>> If the clock source name list is different, then it needs a different
>>> compatible value, so that each compatible value can specify which clock
>>> names are required.
>>>
>>> Also, the compatible value itself should always include the exact HW
>>> that's present (most specific HW version), as well as any other HW it's
>>> compatible with.
>>
>> Thank you for the comments. Yes, I did so in v1-v3, but after rethinking
>> about the situation (Actually both the HW version and the clock mux itself
>> are same, just the clock sources connecting to the mux might be different),
>> so I decided to do this by abstracting the driver from those source info
>> and letting DT binding to pass such information. Because I think putting
>> the clock sources into the driver differed by compatible value would make
>> the driver more like SoC-specified, not the ideal way -- SoC-independent,
>> since the clock sources are based on SoC design, not on itself.
>
> +1
>
> It's pretty much the differences at SoC integration level not the IP
> itself, and it just happens to be handled in a register of the IP.
OK, if the difference are the sources of the clocks and not the set of
clocks, then there's no issue. I can't remember what triggered my
comments above, but obviously it wasn't clear that this was the case.
^ permalink raw reply
* MPC8315 reboot failure, lockdep splat possibly related?
From: Anthony Foiani @ 2013-08-17 1:39 UTC (permalink / raw)
To: linuxppc-dev
Greetings.
I've been experiencing occasional lockups at reboot for a few weeks,
but only once every 10-20 boots. A good reboot looks like this:
[47529.721640] lm77 0-0048: shutdown
[47529.725160] rtc-m41t80 0-0068: shutdown
[47529.729169] i2c i2c-0: shutdown
[47529.732534] fsl-ehci fsl-ehci.0: shutdown
[47529.736842] sd 1:0:0:0: shutdown
[47529.740239] sd 1:0:0:0: [sda] Synchronizing SCSI cache
[47529.747091] uio_pci_generic 0000:00:0a.0: shutdown
[47529.752079] pci 0000:00:00.0: shutdown
[47529.756021] Restarting system.
While a bad one fails after the EHCI shutdown:
[ 747.578001] lm77 0-0048: shutdown
[ 747.581522] rtc-m41t80 0-0068: shutdown
[ 747.585538] i2c i2c-0: shutdown
[ 747.588909] sd 1:0:0:0: shutdown
[ 747.592304] sd 1:0:0:0: [sda] Synchronizing SCSI cache
[ 747.597973] fsl-ehci fsl-ehci.0: shutdown
I enabled lockdep, and I get this splat on every boot, regardless of
whether it locks up at reboot or not. Could it possibly be related?
Any other ideas on how to avoid the reboot lockup?
[ 9.086051] =================================
[ 9.090393] [ INFO: inconsistent lock state ]
[ 9.094744] 3.9.7-ajf-gc39503d #1 Not tainted
[ 9.099087] ---------------------------------
[ 9.103432] inconsistent {HARDIRQ-ON-W} -> {IN-HARDIRQ-W} usage.
[ 9.109431] scsi_eh_1/39 [HC1[1]:SC0[0]:HE0:SE1] takes:
[ 9.114642] (&(&host->lock)->rlock){?.+...}, at: [<c02f4168>] sata_fsl_interrupt+0x50/0x250
[ 9.123137] {HARDIRQ-ON-W} state was registered at:
[ 9.128004] [<c006cdb8>] lock_acquire+0x90/0xf4
[ 9.132737] [<c043ef04>] _raw_spin_lock+0x34/0x4c
[ 9.137645] [<c02f3560>] fsl_sata_set_irq_coalescing+0x68/0x100
[ 9.143750] [<c02f36a0>] sata_fsl_init_controller+0xa8/0xc0
[ 9.149505] [<c02f3f10>] sata_fsl_probe+0x17c/0x2e8
[ 9.154568] [<c02acc90>] driver_probe_device+0x90/0x248
[ 9.159987] [<c02acf0c>] __driver_attach+0xc4/0xc8
[ 9.164964] [<c02aae74>] bus_for_each_dev+0x5c/0xa8
[ 9.170028] [<c02ac218>] bus_add_driver+0x100/0x26c
[ 9.175091] [<c02ad638>] driver_register+0x88/0x198
[ 9.180155] [<c0003a24>] do_one_initcall+0x58/0x1b4
[ 9.185226] [<c05aeeac>] kernel_init_freeable+0x118/0x1c0
[ 9.190823] [<c0004110>] kernel_init+0x18/0x108
[ 9.195542] [<c000f6b8>] ret_from_kernel_thread+0x64/0x6c
[ 9.201142] irq event stamp: 160
[ 9.204366] hardirqs last enabled at (159): [<c043f778>] _raw_spin_unlock_irq+0x30/0x50
[ 9.212469] hardirqs last disabled at (160): [<c000f414>] reenable_mmu+0x30/0x88
[ 9.219867] softirqs last enabled at (144): [<c002ae5c>] __do_softirq+0x168/0x218
[ 9.227435] softirqs last disabled at (137): [<c002b0d4>] irq_exit+0xa8/0xb4
[ 9.234481]
[ 9.234481] other info that might help us debug this:
[ 9.240995] Possible unsafe locking scenario:
[ 9.240995]
[ 9.246898] CPU0
[ 9.249337] ----
[ 9.251776] lock(&(&host->lock)->rlock);
[ 9.255878] <Interrupt>
[ 9.258492] lock(&(&host->lock)->rlock);
[ 9.262765]
[ 9.262765] *** DEADLOCK ***
[ 9.262765]
[ 9.268684] no locks held by scsi_eh_1/39.
[ 9.272767]
[ 9.272767] stack backtrace:
[ 9.277117] Call Trace:
[ 9.279589] [cfff9da0] [c0008504] show_stack+0x48/0x150 (unreliable)
[ 9.285972] [cfff9de0] [c0447d5c] print_usage_bug.part.35+0x268/0x27c
[ 9.292425] [cfff9e10] [c006ace4] mark_lock+0x2ac/0x658
[ 9.297660] [cfff9e40] [c006b7e4] __lock_acquire+0x754/0x1840
[ 9.303414] [cfff9ee0] [c006cdb8] lock_acquire+0x90/0xf4
[ 9.308745] [cfff9f20] [c043ef04] _raw_spin_lock+0x34/0x4c
[ 9.314250] [cfff9f30] [c02f4168] sata_fsl_interrupt+0x50/0x250
[ 9.320187] [cfff9f70] [c0079ff0] handle_irq_event_percpu+0x90/0x254
[ 9.326547] [cfff9fc0] [c007a1fc] handle_irq_event+0x48/0x78
[ 9.332220] [cfff9fe0] [c007c95c] handle_level_irq+0x9c/0x104
[ 9.337981] [cfff9ff0] [c000d978] call_handle_irq+0x18/0x28
[ 9.343568] [cc7139f0] [c000608c] do_IRQ+0xf0/0x1a8
[ 9.348464] [cc713a20] [c000fc8c] ret_from_except+0x0/0x14
[ 9.353983] --- Exception: 501 at _raw_spin_unlock_irq+0x40/0x50
[ 9.353983] LR = _raw_spin_unlock_irq+0x30/0x50
[ 9.364839] [cc713af0] [c043db10] wait_for_common+0xac/0x188
[ 9.370513] [cc713b30] [c02ddee4] ata_exec_internal_sg+0x2b0/0x4f0
[ 9.376699] [cc713be0] [c02de18c] ata_exec_internal+0x68/0xa8
[ 9.382454] [cc713c20] [c02de4b8] ata_dev_read_id+0x158/0x594
[ 9.388205] [cc713ca0] [c02ec244] ata_eh_recover+0xd88/0x13d0
[ 9.393962] [cc713d20] [c02f2520] sata_pmp_error_handler+0xc0/0x8ac
[ 9.400234] [cc713dd0] [c02ecdc8] ata_scsi_port_error_handler+0x464/0x5e8
[ 9.407023] [cc713e10] [c02ecfd0] ata_scsi_error+0x84/0xb8
[ 9.412528] [cc713e40] [c02c4974] scsi_error_handler+0xd8/0x47c
[ 9.418457] [cc713eb0] [c004737c] kthread+0xa8/0xac
[ 9.423355] [cc713f40] [c000f6b8] ret_from_kernel_thread+0x64/0x6c
A full set of kernel messages from a hanging (fails to reboot) session
is here:
http://scrye.com/~tkil/linux/fsl-sata-lockdep-201308/hang-log.txt
And a full set of messages for a boot that reboots successfully:
http://scrye.com/~tkil/linux/fsl-sata-lockdep-201308/no-hang-log.txt
The associated config file:
http://scrye.com/~tkil/linux/fsl-sata-lockdep-201308/config.txt
The only addition I've made to this section of the kernel is my "SATA
speed limit patch", discussed a few weeks back:
http://permalink.gmane.org/gmane.linux.ports.ppc.embedded/58969
That patch does touch sata_fsl_probe, but it just sets a value -- it
doesn't do any locking (for better or for worse), nor does it call any
other functions (and it seems that it's a function further down the
stack that is triggering lockdep).
I took a quick look at the diffs between 3.9.7 (both upstream and my
variant) and the current head of linux-stable, and didn't see anything
that looked relevant. The two main changes I saw were switching from
dev_get_drvdata to platform_get_drvdata and adding the rx_watermark.
I did see that dev_set_drvdata was removed from sata_fsl_probe's exit
path; not sure if that could cause this sort of error.
If anyone has ideas on how to avoid the reboot lockup, I would greatly
appreciate it.
Thank you for your time!
Best regards,
Anthony Foiani
^ permalink raw reply
* RE: MPC8315 reboot failure, lockdep splat possibly related?
From: Bhushan Bharat-R65777 @ 2013-08-17 4:58 UTC (permalink / raw)
To: Anthony Foiani, linuxppc-dev@lists.ozlabs.org
In-Reply-To: <g61v5p02b.fsf@dworkin.scrye.com>
> -----Original Message-----
> From: Linuxppc-dev [mailto:linuxppc-dev-
> bounces+bharat.bhushan=3Dfreescale.com@lists.ozlabs.org] On Behalf Of Ant=
hony
> Foiani
> Sent: Saturday, August 17, 2013 7:10 AM
> To: linuxppc-dev@lists.ozlabs.org
> Subject: MPC8315 reboot failure, lockdep splat possibly related?
>=20
>=20
> Greetings.
>=20
> I've been experiencing occasional lockups at reboot for a few weeks, but =
only
> once every 10-20 boots. A good reboot looks like this:
>=20
> [47529.721640] lm77 0-0048: shutdown
> [47529.725160] rtc-m41t80 0-0068: shutdown
> [47529.729169] i2c i2c-0: shutdown
> [47529.732534] fsl-ehci fsl-ehci.0: shutdown
> [47529.736842] sd 1:0:0:0: shutdown
> [47529.740239] sd 1:0:0:0: [sda] Synchronizing SCSI cache
> [47529.747091] uio_pci_generic 0000:00:0a.0: shutdown
> [47529.752079] pci 0000:00:00.0: shutdown
> [47529.756021] Restarting system.
>=20
> While a bad one fails after the EHCI shutdown:
>=20
> [ 747.578001] lm77 0-0048: shutdown
> [ 747.581522] rtc-m41t80 0-0068: shutdown
> [ 747.585538] i2c i2c-0: shutdown
> [ 747.588909] sd 1:0:0:0: shutdown
> [ 747.592304] sd 1:0:0:0: [sda] Synchronizing SCSI cache
> [ 747.597973] fsl-ehci fsl-ehci.0: shutdown
>=20
> I enabled lockdep, and I get this splat on every boot, regardless of whet=
her it
> locks up at reboot or not. Could it possibly be related?
> Any other ideas on how to avoid the reboot lockup?
>=20
> [ 9.086051] =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D
> [ 9.090393] [ INFO: inconsistent lock state ]
> [ 9.094744] 3.9.7-ajf-gc39503d #1 Not tainted
> [ 9.099087] ---------------------------------
> [ 9.103432] inconsistent {HARDIRQ-ON-W} -> {IN-HARDIRQ-W} usage.
> [ 9.109431] scsi_eh_1/39 [HC1[1]:SC0[0]:HE0:SE1] takes:
> [ 9.114642] (&(&host->lock)->rlock){?.+...}, at: [<c02f4168>]
> sata_fsl_interrupt+0x50/0x250
> [ 9.123137] {HARDIRQ-ON-W} state was registered at:
> [ 9.128004] [<c006cdb8>] lock_acquire+0x90/0xf4
> [ 9.132737] [<c043ef04>] _raw_spin_lock+0x34/0x4c
> [ 9.137645] [<c02f3560>] fsl_sata_set_irq_coalescing+0x68/0x100
> [ 9.143750] [<c02f36a0>] sata_fsl_init_controller+0xa8/0xc0
> [ 9.149505] [<c02f3f10>] sata_fsl_probe+0x17c/0x2e8
> [ 9.154568] [<c02acc90>] driver_probe_device+0x90/0x248
> [ 9.159987] [<c02acf0c>] __driver_attach+0xc4/0xc8
> [ 9.164964] [<c02aae74>] bus_for_each_dev+0x5c/0xa8
> [ 9.170028] [<c02ac218>] bus_add_driver+0x100/0x26c
> [ 9.175091] [<c02ad638>] driver_register+0x88/0x198
> [ 9.180155] [<c0003a24>] do_one_initcall+0x58/0x1b4
> [ 9.185226] [<c05aeeac>] kernel_init_freeable+0x118/0x1c0
> [ 9.190823] [<c0004110>] kernel_init+0x18/0x108
> [ 9.195542] [<c000f6b8>] ret_from_kernel_thread+0x64/0x6c
> [ 9.201142] irq event stamp: 160
> [ 9.204366] hardirqs last enabled at (159): [<c043f778>]
> _raw_spin_unlock_irq+0x30/0x50
> [ 9.212469] hardirqs last disabled at (160): [<c000f414>]
> reenable_mmu+0x30/0x88
> [ 9.219867] softirqs last enabled at (144): [<c002ae5c>]
> __do_softirq+0x168/0x218
> [ 9.227435] softirqs last disabled at (137): [<c002b0d4>]
> irq_exit+0xa8/0xb4
> [ 9.234481]
> [ 9.234481] other info that might help us debug this:
> [ 9.240995] Possible unsafe locking scenario:
> [ 9.240995]
> [ 9.246898] CPU0
> [ 9.249337] ----
> [ 9.251776] lock(&(&host->lock)->rlock);
> [ 9.255878] <Interrupt>
> [ 9.258492] lock(&(&host->lock)->rlock);
> [ 9.262765]
> [ 9.262765] *** DEADLOCK ***
You should get rid of this by changing spin_lock/unlock() in fsl_sata_set_i=
rq_coalescing() to spin_lock_irqsave/restore()
-Bharat
> [ 9.262765]
> [ 9.268684] no locks held by scsi_eh_1/39.
> [ 9.272767]
> [ 9.272767] stack backtrace:
> [ 9.277117] Call Trace:
> [ 9.279589] [cfff9da0] [c0008504] show_stack+0x48/0x150 (unreliable)
> [ 9.285972] [cfff9de0] [c0447d5c] print_usage_bug.part.35+0x268/0x27=
c
> [ 9.292425] [cfff9e10] [c006ace4] mark_lock+0x2ac/0x658
> [ 9.297660] [cfff9e40] [c006b7e4] __lock_acquire+0x754/0x1840
> [ 9.303414] [cfff9ee0] [c006cdb8] lock_acquire+0x90/0xf4
> [ 9.308745] [cfff9f20] [c043ef04] _raw_spin_lock+0x34/0x4c
> [ 9.314250] [cfff9f30] [c02f4168] sata_fsl_interrupt+0x50/0x250
> [ 9.320187] [cfff9f70] [c0079ff0] handle_irq_event_percpu+0x90/0x254
> [ 9.326547] [cfff9fc0] [c007a1fc] handle_irq_event+0x48/0x78
> [ 9.332220] [cfff9fe0] [c007c95c] handle_level_irq+0x9c/0x104
> [ 9.337981] [cfff9ff0] [c000d978] call_handle_irq+0x18/0x28
> [ 9.343568] [cc7139f0] [c000608c] do_IRQ+0xf0/0x1a8
> [ 9.348464] [cc713a20] [c000fc8c] ret_from_except+0x0/0x14
> [ 9.353983] --- Exception: 501 at _raw_spin_unlock_irq+0x40/0x50
> [ 9.353983] LR =3D _raw_spin_unlock_irq+0x30/0x50
> [ 9.364839] [cc713af0] [c043db10] wait_for_common+0xac/0x188
> [ 9.370513] [cc713b30] [c02ddee4] ata_exec_internal_sg+0x2b0/0x4f0
> [ 9.376699] [cc713be0] [c02de18c] ata_exec_internal+0x68/0xa8
> [ 9.382454] [cc713c20] [c02de4b8] ata_dev_read_id+0x158/0x594
> [ 9.388205] [cc713ca0] [c02ec244] ata_eh_recover+0xd88/0x13d0
> [ 9.393962] [cc713d20] [c02f2520] sata_pmp_error_handler+0xc0/0x8ac
> [ 9.400234] [cc713dd0] [c02ecdc8] ata_scsi_port_error_handler+0x464/=
0x5e8
> [ 9.407023] [cc713e10] [c02ecfd0] ata_scsi_error+0x84/0xb8
> [ 9.412528] [cc713e40] [c02c4974] scsi_error_handler+0xd8/0x47c
> [ 9.418457] [cc713eb0] [c004737c] kthread+0xa8/0xac
> [ 9.423355] [cc713f40] [c000f6b8] ret_from_kernel_thread+0x64/0x6c
>=20
> A full set of kernel messages from a hanging (fails to reboot) session is=
here:
>=20
> http://scrye.com/~tkil/linux/fsl-sata-lockdep-201308/hang-log.txt
>=20
> And a full set of messages for a boot that reboots successfully:
>=20
> http://scrye.com/~tkil/linux/fsl-sata-lockdep-201308/no-hang-log.txt
>=20
> The associated config file:
>=20
> http://scrye.com/~tkil/linux/fsl-sata-lockdep-201308/config.txt
>=20
> The only addition I've made to this section of the kernel is my "SATA spe=
ed
> limit patch", discussed a few weeks back:
>=20
> http://permalink.gmane.org/gmane.linux.ports.ppc.embedded/58969
>=20
> That patch does touch sata_fsl_probe, but it just sets a value -- it does=
n't do
> any locking (for better or for worse), nor does it call any other functio=
ns (and
> it seems that it's a function further down the stack that is triggering
> lockdep).
>=20
> I took a quick look at the diffs between 3.9.7 (both upstream and my
> variant) and the current head of linux-stable, and didn't see anything th=
at
> looked relevant. The two main changes I saw were switching from dev_get_=
drvdata
> to platform_get_drvdata and adding the rx_watermark.
> I did see that dev_set_drvdata was removed from sata_fsl_probe's exit pat=
h; not
> sure if that could cause this sort of error.
>=20
> If anyone has ideas on how to avoid the reboot lockup, I would greatly
> appreciate it.
>=20
> Thank you for your time!
>=20
> Best regards,
> Anthony Foiani
> _______________________________________________
> Linuxppc-dev mailing list
> Linuxppc-dev@lists.ozlabs.org
> https://lists.ozlabs.org/listinfo/linuxppc-dev
^ permalink raw reply
* Re: [RFC PATCH v2 3/4] powerpc: refactor of_get_cpu_node to support other architectures
From: Tomasz Figa @ 2013-08-17 10:50 UTC (permalink / raw)
To: linux-arm-kernel
Cc: Jonas Bonn, devicetree, Michal Simek, linux-pm,
Sudeep KarkadaNagesha, linux-kernel, Rob Herring,
Rafael J. Wysocki, Grant Likely, linuxppc-dev
In-Reply-To: <1376674791-28244-2-git-send-email-Sudeep.KarkadaNagesha@arm.com>
Hi Sudeep,
This looks good to me overall, but I have one more question inline.
On Friday 16 of August 2013 18:39:50 Sudeep KarkadaNagesha wrote:
> From: Sudeep KarkadaNagesha <sudeep.karkadanagesha@arm.com>
>
> Currently different drivers requiring to access cpu device node are
> parsing the device tree themselves. Since the ordering in the DT need
> not match the logical cpu ordering, the parsing logic needs to consider
> that. However, this has resulted in lots of code duplication and in some
> cases even incorrect logic.
>
> It's better to consolidate them by adding support for getting cpu
> device node for a given logical cpu index in DT core library. However
> logical to physical index mapping can be architecture specific.
>
> PowerPC has it's own implementation to get the cpu node for a given
> logical index.
>
> This patch refactors the current implementation of of_get_cpu_node.
> This in preparation to move the implementation to DT core library.
> It separates out the logical to physical mapping so that a default
> matching of the physical id to the logical cpu index can be added
> when moved to common code. Architecture specific code can override it.
>
> Cc: Rob Herring <rob.herring@calxeda.com>
> Cc: Grant Likely <grant.likely@linaro.org>
> Cc: Benjamin Herrenschmidt <benh@kernel.crashing.org>
> Signed-off-by: Sudeep KarkadaNagesha <sudeep.karkadanagesha@arm.com>
> ---
> arch/powerpc/kernel/prom.c | 76
> ++++++++++++++++++++++++++++------------------ 1 file changed, 47
> insertions(+), 29 deletions(-)
>
> diff --git a/arch/powerpc/kernel/prom.c b/arch/powerpc/kernel/prom.c
> index eb23ac9..fb12be6 100644
> --- a/arch/powerpc/kernel/prom.c
> +++ b/arch/powerpc/kernel/prom.c
> @@ -865,45 +865,63 @@ static int __init prom_reconfig_setup(void)
> __initcall(prom_reconfig_setup);
> #endif
>
> +bool arch_match_cpu_phys_id(int cpu, u64 phys_id)
> +{
> + return (int)phys_id == get_hard_smp_processor_id(cpu);
> +}
> +
> +static bool __of_find_n_match_cpu_property(struct device_node *cpun,
> + const char *prop_name, int cpu, unsigned int
*thread)
> +{
> + const __be32 *cell;
> + int ac, prop_len, tid;
> + u64 hwid;
> +
> + ac = of_n_addr_cells(cpun);
> + cell = of_get_property(cpun, prop_name, &prop_len);
> + if (!cell)
> + return false;
I wonder how would this handle uniprocessor ARM (pre-v7) cores, for which
the updated bindings[1] define #address-cells = <0> and so no reg
property.
[1] - http://thread.gmane.org/gmane.linux.ports.arm.kernel/260795
Best regards,
Tomasz
^ permalink raw reply
* Re: [PATCH v5 1/2] ASoC: fsl: Add S/PDIF CPU DAI driver
From: Tomasz Figa @ 2013-08-17 12:26 UTC (permalink / raw)
To: Sascha Hauer
Cc: mark.rutland, devicetree, alsa-devel, lars, ian.campbell,
pawel.moll, swarren, festevam, Nicolin Chen, timur, rob.herring,
broonie, p.zabel, galak, shawn.guo, linuxppc-dev
In-Reply-To: <20130816085632.GO26614@pengutronix.de>
On Friday 16 of August 2013 10:56:32 Sascha Hauer wrote:
> On Fri, Aug 16, 2013 at 04:01:25PM +0800, Nicolin Chen wrote:
> > Hi Sascha,
> >
> > Thank you for the detailed comments.
> >
> > On Fri, Aug 16, 2013 at 09:08:18AM +0200, Sascha Hauer wrote:
> > > Which of them the driver should use is configuration and thus
> > > normally
> > > should *not* be described in the devicetree. However, there may be
> > > no
> > > good way for the driver to know which clock to use in which case.
> > > There
> > > may be additional board requirements which are unknown to the
> > > driver. So in this case it might be valid to put the information
> > > which clock to use into the devicetree. But be aware that from the
> > > moment you put this information into the devicetree the driver is
> > > no longer free to chose the best clock, even if in future we find a
> > > good way to automatically guess the best clock. Do you have some
> > > insights in which case I would use which input clock? Is this only
> > > about which clock has the best suitable input frequency or is this
> > > also about synchronization of the audio signal with some other
> > > unit?
> >
> > I understand. What I'm thinking now is to let the driver find the best
> > clock source for tx clock and a correspond divisor like this:
> >
> > "tx<0-8>" Optional Tx clock source for spdif playback.
> >
> > If absent, will use core clock.
> > The index from 0 to 8 is identical
> > to the clock source list described
> > in TxClk_Source bit of register STC.
> > Multiple clock source are allowed
> > for this tx clock source. The driver
> > will select one source from them for
> > each supported sample rate according
> > to the clock rates of these provided
> > clock sources.
>
> You mean tx<0-7>.
>
> Also I would make this option required. Use a dummy clock for mux inputs
> that are grounded for a specific SoC.
Why do you need a dummy clock?
The driver can simply try to grab all the possible clocks and discard
those that failed, so you can just keep those grounded clocks unspecified.
Best regards,
Tomasz
^ permalink raw reply
* Re: [PATCH v5 1/2] ASoC: fsl: Add S/PDIF CPU DAI driver
From: Tomasz Figa @ 2013-08-17 12:28 UTC (permalink / raw)
To: Sascha Hauer
Cc: mark.rutland, devicetree, alsa-devel, lars, ian.campbell,
pawel.moll, swarren, festevam, Nicolin Chen, timur, rob.herring,
broonie, p.zabel, galak, shawn.guo, linuxppc-dev
In-Reply-To: <20130816101151.GQ26614@pengutronix.de>
On Friday 16 of August 2013 12:11:51 Sascha Hauer wrote:
> On Fri, Aug 16, 2013 at 05:53:58PM +0800, Nicolin Chen wrote:
> > On Fri, Aug 16, 2013 at 10:56:32AM +0200, Sascha Hauer wrote:
> > > > "tx<0-8>" Optional Tx clock source for spdif
playback.
> > > >
> > > > If absent, will use core clock.
> > > > The index from 0 to 8 is identical
> > > > to the clock source list described
> > > > in TxClk_Source bit of register
STC.
> > > > Multiple clock source are allowed
> > > > for this tx clock source. The
driver
> > > > will select one source from them
for
> > > > each supported sample rate
according
> > > > to the clock rates of these
provided
> > > > clock sources.
> > >
> > > You mean tx<0-7>
> >
> > Yes. Thank you.
> >
> > > Also I would make this option required. Use a dummy clock for mux
> > > inputs that are grounded for a specific SoC.
> >
> > Some clocks are not from CCM and we haven't defined in imx6q-clk.txt,
> > so in most cases we can't provide a phandle for them, eg: spdif_ext.
> > I think it's a bit hard to force it to be 'required'. An 'optional'
> > looks more flexible to me and a default one is ensured even if it's
> > missing.
>
> <&clks 0> is the dummy clock. This can be used for all input clocks not
> defined by the SoC.
Where does this assumption come from? Is it documented anywhere? What
about cases when you have full description of clocks in device tree, with
one node per clock and #clock-cells = <0>?
Best regards,
Tomasz
^ permalink raw reply
* Re: [PATCH v5 1/2] ASoC: fsl: Add S/PDIF CPU DAI driver
From: Tomasz Figa @ 2013-08-17 12:56 UTC (permalink / raw)
To: Nicolin Chen
Cc: mark.rutland, devicetree, alsa-devel, lars, ian.campbell,
pawel.moll, swarren, festevam, s.hauer, timur, rob.herring,
broonie, p.zabel, galak, shawn.guo, linuxppc-dev
In-Reply-To: <20130816044330.GD1846@MrMyself>
Hi Nicolin,
On Friday 16 of August 2013 12:43:31 Nicolin Chen wrote:
> Hi Tomasz,
>
> Thank you for the comments.
You're welcome.
> I'll revise them in v6.
> And below is my reply for you comments.
Thanks for your reply.
> On Thu, Aug 15, 2013 at 02:18:22PM +0200, Tomasz Figa wrote:
> > > + - clock-names : Includes the following entries:
> > > + name type comments
> > > + "core" Required The core clock of spdif controller
> > > +
> > > + "rx" Optional Rx clock source for spdif record.
> > > + If absent, will use core clock.
> > > +
> > > + "tx" Optional Tx clock source for spdif
playback.
> > > + If absent, will use core clock.
> > > +
> > > + "tx-32000" Optional Tx clock source for 32000Hz sample
rate
> > > + playback. If absent, will use tx
clock.
> > > +
> > > + "tx-44100" Optional Tx clock source for 44100Hz sample
rate
> > > + playback. If absent, will use tx
clock.
> > > +
> > > + "tx-48000" Optional Tx clock source for 48000Hz sample
rate
> > > + playback. If absent, will use tx
clock.
> > > +
> > > + "src<0-7>" Optional Clock source list for tx and rx
clock
> > > + to look up their clock source
indexes.
> > > + This clock list should be
identical to
> > > + the list of TxClk_Source bit value
of
> > > + register SPDIF_STC. If absent or
failed
> > > + to look up, tx and rx clock would
then
> > > + ignore the "rx", "tx" "tx-32000",
> > > + "tx-44100", "tx-48000" clock
phandles
> > > + and select the core clock as
default
> > > + tx and rx clock.
> >
> > I suspect a little abuse of clocks property here. From the description
> > of "core" and "src<0-7>" clocks I assume that the IP can have up to 9
> > clock inputs - core clock and up to 8 extra source clocks. Is it
> > correct?
> >
> > If yes, this makes the "tx", "rx" and "tx-*" clocks describe
> > configuration, not hardware. IMHO it should be up to the driver which
> > source clocks to use for tx and rx channels and for each sampling
> > rate.
>
> First, you are right that all the properties you just commented are
> software configurations. And I got the point that device tree now
> can't allow any software configuration even if the actual hardware
> connection will depend on it.
>
> If so, I would like to remove those abused clocks and also drop the
> unused clocks in src<0-7>, then just remain those needed clocks src.
> I think that can be plausible because there'll be no more clock abuse
> and the driver will be able to get the source index from the name
> 'src<num>'.
OK.
> And you are right about the 9 clock inputs, just there're not only 9
> inputs but also an extra external clock from S/PDIF transmitter via
> coaxial cable or optical fiber -- RxCLK. Please check the following
> list:
>
> 0000 if (DPLL Locked) SPDIF_RxClk else extal
> 0001 if (DPLL Locked) SPDIF_RxClk else spdif_clk
> 0010 if (DPLL Locked) SPDIF_RxClk else asrc_clk
> 0011 if (DPLL Locked) SPDIF_RxClk else spdif_extclk
> 0100 if (DPLL Locked) SPDIF_Rxclk else esai_hckt
> 0101 extal_clk
> 0110 spdif_clk
> 0111 asrc_clk
> 1000 spdif_extclk
> 1001 esai_hckt
> 1010 if (DPLL Locked) SPDIF_RxClk else mlb_clk
> 1011 if (DPLL Locked) SPDIF_RxClk else mlb_phy_clk
> 1100 mkb_clk
> 1101 mlb_phy_clk
Could you explain what the above values are? If they are values written to
a 4-bit mux that selects RX clock source, then all the 16 clocks should be
specified from device tree, even if they are duplicated.
Are the clock names you used above names of clock inputs of the S/PDIF
block or names of SoC-wide clocks?
Can the assignment of clock inputs change? For example on one SoC
0000 if (DPLL Locked) SPDIF_RxClk else extal_clk
0001 if (DPLL Locked) SPDIF_RxClk else spdif_clk
...
0101 extal_clk
0110 spdif_clk
...
and on another
0000 if (DPLL Locked) SPDIF_RxClk else spdif_clk
0001 if (DPLL Locked) SPDIF_RxClk else extal_clk
...
0101 extal_clk
0110 spdif_clk
...
(notice the swapped 0000 and 0001 inputs)
Same goes for the TX mux. If it is a 3-bit, 8-input mux, then it should be
described in device tree separately, as it is different than the 4-bit,
16-input RX mux.
> When (DPLL Locked) condition matches, the rx clock can ignore the 8
> input clocks from clock mux then use the external one from a S/PDIF
> transmitter.
What happens if the "DPLL locked" condition doesn't match? When this can
happen?
> So for the below part:
> > > +Optional properties:
> > > +
> > > + - rx-clksrc-lock: This is a boolean property. If present,
> > > ClkSrc_Sel
> > > bit + of SPDIF_SRPC would be set a clock source that cares DPLL
> > > locked
> > > condition. +
> >
> > This again looks like software configuration, not hardware
> > description.
> > Could you elaborate a bit more on meaning of this property?
>
> I think the rx-clksrc-lock property should be included in DT as well,
> since it's exactly a available clock source for rx. But I guess I just
> need to figure out a better way or a more elaborated description.
I still don't understand the meaning of this property. Could you explain
it please?
Best regards,
Tomasz
^ permalink raw reply
* Re: [PATCH v5 1/2] ASoC: fsl: Add S/PDIF CPU DAI driver
From: Sascha Hauer @ 2013-08-17 14:53 UTC (permalink / raw)
To: Tomasz Figa
Cc: mark.rutland, devicetree, alsa-devel, lars, ian.campbell,
pawel.moll, swarren, festevam, Nicolin Chen, timur, rob.herring,
broonie, p.zabel, galak, shawn.guo, linuxppc-dev
In-Reply-To: <2805432.jMVhHxhr1m@flatron>
On Sat, Aug 17, 2013 at 02:28:04PM +0200, Tomasz Figa wrote:
> > > > Also I would make this option required. Use a dummy clock for mux
> > > > inputs that are grounded for a specific SoC.
> > >
> > > Some clocks are not from CCM and we haven't defined in imx6q-clk.txt,
> > > so in most cases we can't provide a phandle for them, eg: spdif_ext.
> > > I think it's a bit hard to force it to be 'required'. An 'optional'
> > > looks more flexible to me and a default one is ensured even if it's
> > > missing.
> >
> > <&clks 0> is the dummy clock. This can be used for all input clocks not
> > defined by the SoC.
>
> Where does this assumption come from? Is it documented anywhere?
This is how all i.MX clock bindings currently are. See
Documentation/devicetree/bindings/clock/imx*-clock.txt
Sascha
--
Pengutronix e.K. | |
Industrial Linux Solutions | http://www.pengutronix.de/ |
Peiner Str. 6-8, 31137 Hildesheim, Germany | Phone: +49-5121-206917-0 |
Amtsgericht Hildesheim, HRA 2686 | Fax: +49-5121-206917-5555 |
^ permalink raw reply
* Re: [PATCH v5 1/2] ASoC: fsl: Add S/PDIF CPU DAI driver
From: Sascha Hauer @ 2013-08-17 15:00 UTC (permalink / raw)
To: Tomasz Figa
Cc: mark.rutland, devicetree, alsa-devel, lars, ian.campbell,
pawel.moll, swarren, festevam, Nicolin Chen, timur, rob.herring,
broonie, p.zabel, galak, shawn.guo, linuxppc-dev
In-Reply-To: <137675716.iLf1T1CVZo@flatron>
On Sat, Aug 17, 2013 at 02:26:40PM +0200, Tomasz Figa wrote:
> > You mean tx<0-7>.
> >
> > Also I would make this option required. Use a dummy clock for mux inputs
> > that are grounded for a specific SoC.
>
> Why do you need a dummy clock?
>
> The driver can simply try to grab all the possible clocks and discard
> those that failed, so you can just keep those grounded clocks unspecified.
We don't need dummy clocks. My motivation saying this that I was afraid
people try to configure the driver by skipping the clocks they don't
want from the devicetree.
Sascha
--
Pengutronix e.K. | |
Industrial Linux Solutions | http://www.pengutronix.de/ |
Peiner Str. 6-8, 31137 Hildesheim, Germany | Phone: +49-5121-206917-0 |
Amtsgericht Hildesheim, HRA 2686 | Fax: +49-5121-206917-5555 |
^ permalink raw reply
* Re: [PATCH v5 1/2] ASoC: fsl: Add S/PDIF CPU DAI driver
From: Tomasz Figa @ 2013-08-17 15:13 UTC (permalink / raw)
To: Sascha Hauer
Cc: mark.rutland, devicetree, alsa-devel, lars, ian.campbell,
pawel.moll, swarren, festevam, Nicolin Chen, timur, rob.herring,
broonie, p.zabel, galak, shawn.guo, linuxppc-dev
In-Reply-To: <20130817150002.GU26614@pengutronix.de>
On Saturday 17 of August 2013 17:00:02 Sascha Hauer wrote:
> On Sat, Aug 17, 2013 at 02:26:40PM +0200, Tomasz Figa wrote:
> > > You mean tx<0-7>.
> > >
> > > Also I would make this option required. Use a dummy clock for mux
> > > inputs that are grounded for a specific SoC.
> >
> > Why do you need a dummy clock?
> >
> > The driver can simply try to grab all the possible clocks and discard
> > those that failed, so you can just keep those grounded clocks
> > unspecified.
> We don't need dummy clocks. My motivation saying this that I was afraid
> people try to configure the driver by skipping the clocks they don't
> want from the devicetree.
I'm not really sure if the same abuse couldn't be easily achieved by
putting dummy clocks in place of those skipped clocks.
Adding a note in binding documentation that says that all clocks that are
fed to the IP shall be specified should be fine IMHO.
Best regards,
Tomasz
^ permalink raw reply
* Re: [PATCH v5 1/2] ASoC: fsl: Add S/PDIF CPU DAI driver
From: Sascha Hauer @ 2013-08-17 15:14 UTC (permalink / raw)
To: Tomasz Figa
Cc: mark.rutland, devicetree, alsa-devel, lars, ian.campbell,
pawel.moll, swarren, festevam, Nicolin Chen, timur, rob.herring,
broonie, p.zabel, galak, shawn.guo, linuxppc-dev
In-Reply-To: <2362958.X2QCBUPAyI@flatron>
On Sat, Aug 17, 2013 at 02:56:11PM +0200, Tomasz Figa wrote:
> Hi Nicolin,
> > First, you are right that all the properties you just commented are
> > software configurations. And I got the point that device tree now
> > can't allow any software configuration even if the actual hardware
> > connection will depend on it.
> >
> > If so, I would like to remove those abused clocks and also drop the
> > unused clocks in src<0-7>, then just remain those needed clocks src.
> > I think that can be plausible because there'll be no more clock abuse
> > and the driver will be able to get the source index from the name
> > 'src<num>'.
>
> OK.
>
> > And you are right about the 9 clock inputs, just there're not only 9
> > inputs but also an extra external clock from S/PDIF transmitter via
> > coaxial cable or optical fiber -- RxCLK. Please check the following
> > list:
> >
> > 0000 if (DPLL Locked) SPDIF_RxClk else extal
> > 0001 if (DPLL Locked) SPDIF_RxClk else spdif_clk
> > 0010 if (DPLL Locked) SPDIF_RxClk else asrc_clk
> > 0011 if (DPLL Locked) SPDIF_RxClk else spdif_extclk
> > 0100 if (DPLL Locked) SPDIF_Rxclk else esai_hckt
> > 0101 extal_clk
> > 0110 spdif_clk
> > 0111 asrc_clk
> > 1000 spdif_extclk
> > 1001 esai_hckt
> > 1010 if (DPLL Locked) SPDIF_RxClk else mlb_clk
> > 1011 if (DPLL Locked) SPDIF_RxClk else mlb_phy_clk
> > 1100 mkb_clk
> > 1101 mlb_phy_clk
>
> Could you explain what the above values are? If they are values written to
> a 4-bit mux that selects RX clock source, then all the 16 clocks should be
> specified from device tree, even if they are duplicated.
The S/PDIF core can recover the clock for the tx signal from the rx
signal. So if you have an S/PDIF input signal, then the DPLL will be
locked and the SPDIF_RxClk can be used for tx. So the above are really 8
clocks and one "If DPLL locked, use it" bit.
Sascha
--
Pengutronix e.K. | |
Industrial Linux Solutions | http://www.pengutronix.de/ |
Peiner Str. 6-8, 31137 Hildesheim, Germany | Phone: +49-5121-206917-0 |
Amtsgericht Hildesheim, HRA 2686 | Fax: +49-5121-206917-5555 |
^ permalink raw reply
* Re: [PATCH v5 1/2] ASoC: fsl: Add S/PDIF CPU DAI driver
From: Sascha Hauer @ 2013-08-17 15:14 UTC (permalink / raw)
To: Tomasz Figa
Cc: mark.rutland, devicetree, alsa-devel, lars, ian.campbell,
pawel.moll, swarren, festevam, Nicolin Chen, timur, rob.herring,
broonie, p.zabel, galak, shawn.guo, linuxppc-dev
In-Reply-To: <2782793.dUculLxO6S@flatron>
On Sat, Aug 17, 2013 at 05:13:20PM +0200, Tomasz Figa wrote:
> On Saturday 17 of August 2013 17:00:02 Sascha Hauer wrote:
> > On Sat, Aug 17, 2013 at 02:26:40PM +0200, Tomasz Figa wrote:
> > > > You mean tx<0-7>.
> > > >
> > > > Also I would make this option required. Use a dummy clock for mux
> > > > inputs that are grounded for a specific SoC.
> > >
> > > Why do you need a dummy clock?
> > >
> > > The driver can simply try to grab all the possible clocks and discard
> > > those that failed, so you can just keep those grounded clocks
> > > unspecified.
> > We don't need dummy clocks. My motivation saying this that I was afraid
> > people try to configure the driver by skipping the clocks they don't
> > want from the devicetree.
>
> I'm not really sure if the same abuse couldn't be easily achieved by
> putting dummy clocks in place of those skipped clocks.
That's right, yes.
>
> Adding a note in binding documentation that says that all clocks that are
> fed to the IP shall be specified should be fine IMHO.
ok.
Sascha
--
Pengutronix e.K. | |
Industrial Linux Solutions | http://www.pengutronix.de/ |
Peiner Str. 6-8, 31137 Hildesheim, Germany | Phone: +49-5121-206917-0 |
Amtsgericht Hildesheim, HRA 2686 | Fax: +49-5121-206917-5555 |
^ permalink raw reply
* Re: [PATCH v5 1/2] ASoC: fsl: Add S/PDIF CPU DAI driver
From: Tomasz Figa @ 2013-08-17 15:17 UTC (permalink / raw)
To: Sascha Hauer
Cc: mark.rutland, devicetree, alsa-devel, lars, mturquette,
ian.campbell, pawel.moll, swarren, festevam, Nicolin Chen, timur,
rob.herring, broonie, p.zabel, galak, shawn.guo, linuxppc-dev
In-Reply-To: <20130817145316.GT26614@pengutronix.de>
On Saturday 17 of August 2013 16:53:16 Sascha Hauer wrote:
> On Sat, Aug 17, 2013 at 02:28:04PM +0200, Tomasz Figa wrote:
> > > > > Also I would make this option required. Use a dummy clock for
> > > > > mux
> > > > > inputs that are grounded for a specific SoC.
> > > >
> > > > Some clocks are not from CCM and we haven't defined in
> > > > imx6q-clk.txt,
> > > > so in most cases we can't provide a phandle for them, eg:
> > > > spdif_ext.
> > > > I think it's a bit hard to force it to be 'required'. An
> > > > 'optional'
> > > > looks more flexible to me and a default one is ensured even if
> > > > it's
> > > > missing.
> > >
> > > <&clks 0> is the dummy clock. This can be used for all input clocks
> > > not
> > > defined by the SoC.
> >
> > Where does this assumption come from? Is it documented anywhere?
>
> This is how all i.MX clock bindings currently are. See
> Documentation/devicetree/bindings/clock/imx*-clock.txt
OK, thanks.
I guess we need some discussion on dummy clocks vs skipped clocks. I think
we want some consistency on this, don't we?
If we really need a dummy clock, then we might also want a generic way to
specify it.
Best regards,
Tomasz
^ permalink raw reply
* Re: [PATCH v5 1/2] ASoC: fsl: Add S/PDIF CPU DAI driver
From: Tomasz Figa @ 2013-08-17 15:38 UTC (permalink / raw)
To: Sascha Hauer
Cc: mark.rutland, devicetree, alsa-devel, lars, ian.campbell,
pawel.moll, swarren, festevam, Nicolin Chen, timur, rob.herring,
broonie, p.zabel, galak, shawn.guo, linuxppc-dev
In-Reply-To: <20130817151409.GW26614@pengutronix.de>
On Saturday 17 of August 2013 17:14:09 Sascha Hauer wrote:
> On Sat, Aug 17, 2013 at 02:56:11PM +0200, Tomasz Figa wrote:
> > Hi Nicolin,
> >
> > > First, you are right that all the properties you just commented are
> > > software configurations. And I got the point that device tree now
> > > can't allow any software configuration even if the actual hardware
> > > connection will depend on it.
> > >
> > > If so, I would like to remove those abused clocks and also drop the
> > > unused clocks in src<0-7>, then just remain those needed clocks src.
> > > I think that can be plausible because there'll be no more clock
> > > abuse
> > > and the driver will be able to get the source index from the name
> > > 'src<num>'.
> >
> > OK.
> >
> > > And you are right about the 9 clock inputs, just there're not only 9
> > > inputs but also an extra external clock from S/PDIF transmitter via
> > > coaxial cable or optical fiber -- RxCLK. Please check the following
> > > list:
> > >
> > > 0000 if (DPLL Locked) SPDIF_RxClk else extal
> > > 0001 if (DPLL Locked) SPDIF_RxClk else spdif_clk
> > > 0010 if (DPLL Locked) SPDIF_RxClk else asrc_clk
> > > 0011 if (DPLL Locked) SPDIF_RxClk else spdif_extclk
> > > 0100 if (DPLL Locked) SPDIF_Rxclk else esai_hckt
> > > 0101 extal_clk
> > > 0110 spdif_clk
> > > 0111 asrc_clk
> > > 1000 spdif_extclk
> > > 1001 esai_hckt
> > > 1010 if (DPLL Locked) SPDIF_RxClk else mlb_clk
> > > 1011 if (DPLL Locked) SPDIF_RxClk else mlb_phy_clk
> > > 1100 mkb_clk
> > > 1101 mlb_phy_clk
> >
> > Could you explain what the above values are? If they are values
> > written to a 4-bit mux that selects RX clock source, then all the 16
> > clocks should be specified from device tree, even if they are
> > duplicated.
>
> The S/PDIF core can recover the clock for the tx signal from the rx
> signal. So if you have an S/PDIF input signal, then the DPLL will be
> locked and the SPDIF_RxClk can be used for tx. So the above are really 8
> clocks and one "If DPLL locked, use it" bit.
Yes, I'm aware of this and the solution you proposed is fully acceptable,
but it complicates the driver a bit.
If you look at the mux inputs above, you can see that there is no single
bit that specifies "if DPLL locked, use it" mode. Instead the conditional
clock sources are mixed with fixed clock sources, without a linear
translation to 0-7 range, which would have to be hardcoded in the driver.
I guess it's a matter of preference, but if the IP has a RX clock
selection mux that has 16 inputs, the natural representation in device
tree that comes to my mind is 16 clocks - one for each input of the mux.
One might choose to abstract this as 8 clocks, though, since each clock is
duplicated.
In this particular case, the driver would have to know which mux inputs
can use DPLL anyway, so some hardcoding in the driver is still going to
take place, so I guess both solutions are equally right.
Best regards,
Tomasz
^ permalink raw reply
* Re: MPC8315 reboot failure, lockdep splat possibly related?
From: Anthony Foiani @ 2013-08-17 17:17 UTC (permalink / raw)
To: Bhushan Bharat-R65777; +Cc: linuxppc-dev@lists.ozlabs.org
In-Reply-To: <6A3DF150A5B70D4F9B66A25E3F7C888D07114F7C@039-SN2MPN1-013.039d.mgd.msft.net>
Bharat, greetings --
Bhushan Bharat-R65777 <R65777@freescale.com> writes:
> You should get rid of this by changing spin_lock/unlock() in
> fsl_sata_set_irq_coalescing() to spin_lock_irqsave/restore()
I'll do that -- thanks!
Looks like linux-next still has plain spin_lock, not the irqsave variant.
Is this something that needs to be pushed to mainline and/or stable?
If it should go upstream, is this something that Freescale can do, or
should I try to put together a patch? (I'd like to avoid having to do
it myself, because I'm carrying out-of-tree patches that I'd have to
port to linux-next before it'd be accepted there, I fear.)
Either way, I'll definitely report if it fixes the splat on my 3.9.7
system.
Thanks again!
Best regards,
Anthony Foiani
^ permalink raw reply
* Re: [RFC PATCH v2 11/11] pstore/ram: Read and write to the 'compressed' flag of pstore
From: Kees Cook @ 2013-08-17 18:26 UTC (permalink / raw)
To: Aruna Balakrishnaiah
Cc: jkenisto, Tony Luck, Colin Cross, LKML, mahesh, linuxppc-dev,
Anton Vorontsov
In-Reply-To: <20130816131907.3338.76154.stgit@aruna-ThinkPad-T420>
On Fri, Aug 16, 2013 at 6:19 AM, Aruna Balakrishnaiah
<aruna@linux.vnet.ibm.com> wrote:
> In pstore write, add character 'C'(compressed) or 'D'(decompressed)
> in the header while writing to Ram persistent buffer. In pstore read,
> read the header and update the 'compressed' flag accordingly.
>
> Signed-off-by: Aruna Balakrishnaiah <aruna@linux.vnet.ibm.com>
Nice work!
Acked-by: Kees Cook <keescook@chromium.org>
--
Kees Cook
Chrome OS Security
^ permalink raw reply
* Re: [RFC PATCH v2 00/11] Add (de)compression support to pstore
From: Kees Cook @ 2013-08-17 18:32 UTC (permalink / raw)
To: Luck, Tony
Cc: jkenisto@linux.vnet.ibm.com, ccross@android.com,
linux-kernel@vger.kernel.org, mahesh@linux.vnet.ibm.com,
linuxppc-dev@ozlabs.org, Aruna Balakrishnaiah,
cbouatmailru@gmail.com
In-Reply-To: <3908561D78D1C84285E8C5FCA982C28F31CBF152@ORSMSX106.amr.corp.intel.com>
On Fri, Aug 16, 2013 at 3:15 PM, Luck, Tony <tony.luck@intel.com> wrote:
>> Needs testing with erst backend, efivars and persistent ram.
>
> Tested against ERST - works fine for me now.
>
> Need to stare at the code to see if there are any more bits that could be cleaned up.
>
> Thanks for addressing my issues from v1
Yeah, this is great. While I haven't tested it myself yet, the code
seems to be in good shape. I acked the ram piece separately, but
consider the entire series:
Reviewed-by: Kees Cook <keescook@chromium.org>
Thanks!
-Kees
--
Kees Cook
Chrome OS Security
^ permalink raw reply
* [PATCH 1/4] hotplug, x86: Fix online state in cpu0 debug interface
From: Toshi Kani @ 2013-08-17 19:46 UTC (permalink / raw)
To: mingo, hpa, tglx, gregkh, benh
Cc: fenghua.yu, Toshi Kani, x86, linux-kernel, rjw, isimatu.yasuaki,
srivatsa.bhat, bp, linuxppc-dev
In-Reply-To: <1376768819-28975-1-git-send-email-toshi.kani@hp.com>
_debug_hotplug_cpu() is a debug interface that puts cpu0 offline during
boot-up when CONFIG_DEBUG_HOTPLUG_CPU0 is set. After cpu0 is put offline
in this interface, however, /sys/devices/system/cpu/cpu0/online still
shows 1 (online).
This patch fixes _debug_hotplug_cpu() to update dev->offline when CPU
online/offline operation succeeded.
Signed-off-by: Toshi Kani <toshi.kani@hp.com>
---
arch/x86/kernel/topology.c | 7 +++++--
1 file changed, 5 insertions(+), 2 deletions(-)
diff --git a/arch/x86/kernel/topology.c b/arch/x86/kernel/topology.c
index 6e60b5f..5823bbd 100644
--- a/arch/x86/kernel/topology.c
+++ b/arch/x86/kernel/topology.c
@@ -72,16 +72,19 @@ int __ref _debug_hotplug_cpu(int cpu, int action)
ret = cpu_down(cpu);
if (!ret) {
pr_info("CPU %u is now offline\n", cpu);
+ dev->offline = true;
kobject_uevent(&dev->kobj, KOBJ_OFFLINE);
} else
pr_debug("Can't offline CPU%d.\n", cpu);
break;
case 1:
ret = cpu_up(cpu);
- if (!ret)
+ if (!ret) {
+ dev->offline = false;
kobject_uevent(&dev->kobj, KOBJ_ONLINE);
- else
+ } else {
pr_debug("Can't online CPU%d.\n", cpu);
+ }
break;
default:
ret = -EINVAL;
^ permalink raw reply related
* [PATCH 4/4] hotplug, powerpc, x86: Remove cpu_hotplug_driver_lock()
From: Toshi Kani @ 2013-08-17 19:46 UTC (permalink / raw)
To: mingo, hpa, tglx, gregkh, benh
Cc: fenghua.yu, Toshi Kani, x86, linux-kernel, rjw, isimatu.yasuaki,
srivatsa.bhat, bp, linuxppc-dev
In-Reply-To: <1376768819-28975-1-git-send-email-toshi.kani@hp.com>
cpu_hotplug_driver_lock() serializes CPU online/offline operations
when ARCH_CPU_PROBE_RELEASE is set. This lock interface is no longer
necessary with the following reason:
- lock_device_hotplug() now protects CPU online/offline operations,
including the probe & release interfaces enabled by
ARCH_CPU_PROBE_RELEASE. The use of cpu_hotplug_driver_lock() is
redundant.
- cpu_hotplug_driver_lock() is only valid when ARCH_CPU_PROBE_RELEASE
is defined, which is misleading and is only enabled on powerpc.
This patch removes the cpu_hotplug_driver_lock() interface. As
a result, ARCH_CPU_PROBE_RELEASE only enables / disables the cpu
probe & release interface as intended. There is no functional change
in this patch.
Signed-off-by: Toshi Kani <toshi.kani@hp.com>
---
Performed build test only on powerpc.
---
arch/powerpc/kernel/smp.c | 12 ----------
arch/powerpc/platforms/pseries/dlpar.c | 40 ++++++++++++--------------------
arch/x86/kernel/topology.c | 2 --
drivers/base/cpu.c | 10 +-------
include/linux/cpu.h | 13 ----------
5 files changed, 16 insertions(+), 61 deletions(-)
diff --git a/arch/powerpc/kernel/smp.c b/arch/powerpc/kernel/smp.c
index 38b0ba6..1667269 100644
--- a/arch/powerpc/kernel/smp.c
+++ b/arch/powerpc/kernel/smp.c
@@ -763,18 +763,6 @@ void __cpu_die(unsigned int cpu)
smp_ops->cpu_die(cpu);
}
-static DEFINE_MUTEX(powerpc_cpu_hotplug_driver_mutex);
-
-void cpu_hotplug_driver_lock()
-{
- mutex_lock(&powerpc_cpu_hotplug_driver_mutex);
-}
-
-void cpu_hotplug_driver_unlock()
-{
- mutex_unlock(&powerpc_cpu_hotplug_driver_mutex);
-}
-
void cpu_die(void)
{
if (ppc_md.cpu_die)
diff --git a/arch/powerpc/platforms/pseries/dlpar.c b/arch/powerpc/platforms/pseries/dlpar.c
index a1a7b9a..e39325d 100644
--- a/arch/powerpc/platforms/pseries/dlpar.c
+++ b/arch/powerpc/platforms/pseries/dlpar.c
@@ -387,18 +387,13 @@ static ssize_t dlpar_cpu_probe(const char *buf, size_t count)
char *cpu_name;
int rc;
- cpu_hotplug_driver_lock();
rc = strict_strtoul(buf, 0, &drc_index);
- if (rc) {
- rc = -EINVAL;
- goto out;
- }
+ if (rc)
+ return -EINVAL;
dn = dlpar_configure_connector(drc_index);
- if (!dn) {
- rc = -EINVAL;
- goto out;
- }
+ if (!dn)
+ return -EINVAL;
/* configure-connector reports cpus as living in the base
* directory of the device tree. CPUs actually live in the
@@ -407,8 +402,7 @@ static ssize_t dlpar_cpu_probe(const char *buf, size_t count)
cpu_name = kasprintf(GFP_KERNEL, "/cpus%s", dn->full_name);
if (!cpu_name) {
dlpar_free_cc_nodes(dn);
- rc = -ENOMEM;
- goto out;
+ return -ENOMEM;
}
kfree(dn->full_name);
@@ -417,22 +411,21 @@ static ssize_t dlpar_cpu_probe(const char *buf, size_t count)
rc = dlpar_acquire_drc(drc_index);
if (rc) {
dlpar_free_cc_nodes(dn);
- rc = -EINVAL;
- goto out;
+ return -EINVAL;
}
rc = dlpar_attach_node(dn);
if (rc) {
dlpar_release_drc(drc_index);
dlpar_free_cc_nodes(dn);
- goto out;
+ return rc;
}
rc = dlpar_online_cpu(dn);
-out:
- cpu_hotplug_driver_unlock();
+ if (rc)
+ return rc;
- return rc ? rc : count;
+ return count;
}
static int dlpar_offline_cpu(struct device_node *dn)
@@ -505,30 +498,27 @@ static ssize_t dlpar_cpu_release(const char *buf, size_t count)
return -EINVAL;
}
- cpu_hotplug_driver_lock();
rc = dlpar_offline_cpu(dn);
if (rc) {
of_node_put(dn);
- rc = -EINVAL;
- goto out;
+ return -EINVAL;
}
rc = dlpar_release_drc(*drc_index);
if (rc) {
of_node_put(dn);
- goto out;
+ return rc;
}
rc = dlpar_detach_node(dn);
if (rc) {
dlpar_acquire_drc(*drc_index);
- goto out;
+ return rc;
}
of_node_put(dn);
-out:
- cpu_hotplug_driver_unlock();
- return rc ? rc : count;
+
+ return count;
}
static int __init pseries_dlpar_init(void)
diff --git a/arch/x86/kernel/topology.c b/arch/x86/kernel/topology.c
index a3f35eb..649b010 100644
--- a/arch/x86/kernel/topology.c
+++ b/arch/x86/kernel/topology.c
@@ -66,7 +66,6 @@ int __ref _debug_hotplug_cpu(int cpu, int action)
return -EINVAL;
lock_device_hotplug();
- cpu_hotplug_driver_lock();
switch (action) {
case 0:
@@ -91,7 +90,6 @@ int __ref _debug_hotplug_cpu(int cpu, int action)
ret = -EINVAL;
}
- cpu_hotplug_driver_unlock();
unlock_device_hotplug();
return ret;
diff --git a/drivers/base/cpu.c b/drivers/base/cpu.c
index 4cc6928..b4ebd7b 100644
--- a/drivers/base/cpu.c
+++ b/drivers/base/cpu.c
@@ -45,8 +45,6 @@ static int __ref cpu_subsys_online(struct device *dev)
int from_nid, to_nid;
int ret;
- cpu_hotplug_driver_lock();
-
from_nid = cpu_to_node(cpuid);
ret = cpu_up(cpuid);
/*
@@ -57,18 +55,12 @@ static int __ref cpu_subsys_online(struct device *dev)
if (from_nid != to_nid)
change_cpu_under_node(cpu, from_nid, to_nid);
- cpu_hotplug_driver_unlock();
return ret;
}
static int cpu_subsys_offline(struct device *dev)
{
- int ret;
-
- cpu_hotplug_driver_lock();
- ret = cpu_down(dev->id);
- cpu_hotplug_driver_unlock();
- return ret;
+ return cpu_down(dev->id);
}
void unregister_cpu(struct cpu *cpu)
diff --git a/include/linux/cpu.h b/include/linux/cpu.h
index ab0eade..e847ef8 100644
--- a/include/linux/cpu.h
+++ b/include/linux/cpu.h
@@ -182,19 +182,6 @@ extern void cpu_hotplug_enable(void);
void clear_tasks_mm_cpumask(int cpu);
int cpu_down(unsigned int cpu);
-#ifdef CONFIG_ARCH_CPU_PROBE_RELEASE
-extern void cpu_hotplug_driver_lock(void);
-extern void cpu_hotplug_driver_unlock(void);
-#else
-static inline void cpu_hotplug_driver_lock(void)
-{
-}
-
-static inline void cpu_hotplug_driver_unlock(void)
-{
-}
-#endif
-
#else /* CONFIG_HOTPLUG_CPU */
#define get_online_cpus() do { } while (0)
^ permalink raw reply related
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox