[PATCH v2 3/4] ASoC: sunxi: Add S/PDIF machine driver.

2015-09-30 Thread codekipper
From: Marcus Cooper 

Signed-off-by: Marcus Cooper 
---
 sound/soc/sunxi/sunxi-machine-spdif.c | 108 ++
 1 file changed, 108 insertions(+)
 create mode 100644 sound/soc/sunxi/sunxi-machine-spdif.c

diff --git a/sound/soc/sunxi/sunxi-machine-spdif.c 
b/sound/soc/sunxi/sunxi-machine-spdif.c
new file mode 100644
index 000..2adb727
--- /dev/null
+++ b/sound/soc/sunxi/sunxi-machine-spdif.c
@@ -0,0 +1,108 @@
+/*
+ * Copyright (C) 2015 Andrea Venturi 
+ * From code by (C) 2013 Freescale Semiconductor, Inc.
+ * (sound/soc/fsl/imx-spdif.c)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include 
+#include 
+#include 
+
+struct sunxi_machine_spdif_data {
+   struct snd_soc_dai_link dai;
+   struct snd_soc_card card;
+};
+
+static int sunxi_machine_spdif_audio_probe(struct platform_device *pdev)
+{
+   struct device_node *spdif_np, *np = pdev->dev.of_node;
+   struct sunxi_machine_spdif_data *data;
+   int ret = 0;
+
+   dev_dbg(>dev, "%s: Looking for spdif-controller\n", __func__);
+   spdif_np = of_parse_phandle(np, "spdif-controller", 0);
+   if (!spdif_np) {
+   dev_err(>dev, "failed to find spdif-controller\n");
+   ret = -EINVAL;
+   goto end;
+   }
+
+   data = devm_kzalloc(>dev, sizeof(*data), GFP_KERNEL);
+   if (!data) {
+   ret = -ENOMEM;
+   goto end;
+   }
+
+   data->dai.name = "S/PDIF PCM";
+   data->dai.stream_name = "S/PDIF PCM";
+   data->dai.codec_dai_name = "snd-soc-dummy-dai";
+   data->dai.codec_name = "snd-soc-dummy";
+   data->dai.cpu_of_node = spdif_np;
+   data->dai.platform_of_node = spdif_np;
+   data->dai.playback_only = true;
+   data->dai.capture_only = true;
+
+   if (of_property_read_bool(np, "spdif-out"))
+   data->dai.capture_only = false;
+
+   if (of_property_read_bool(np, "spdif-in"))
+   data->dai.playback_only = false;
+
+   if (data->dai.playback_only && data->dai.capture_only) {
+   dev_err(>dev, "no enabled S/PDIF DAI link\n");
+   goto end;
+   }
+
+   data->card.dev = >dev;
+   data->card.dai_link = >dai;
+   data->card.num_links = 1;
+   data->card.owner = THIS_MODULE;
+
+   ret = snd_soc_of_parse_card_name(>card, "model");
+   if (ret)
+   goto end;
+
+   ret = devm_snd_soc_register_card(>dev, >card);
+   if (ret) {
+   dev_err(>dev, "snd_soc_register_card failed: %d\n", ret);
+   goto end;
+   }
+
+   platform_set_drvdata(pdev, data);
+
+end:
+   of_node_put(spdif_np);
+
+   return ret;
+}
+
+static const struct of_device_id sunxi_machine_spdif_dt_ids[] = {
+   { .compatible = "allwinner,sunxi-audio-spdif", },
+   { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, sunxi_machine_spdif_dt_ids);
+
+static struct platform_driver sunxi_machine_spdif_driver = {
+   .driver = {
+   .name = "sunxi-machine-spdif",
+   .of_match_table = sunxi_machine_spdif_dt_ids,
+   },
+   .probe = sunxi_machine_spdif_audio_probe,
+};
+
+module_platform_driver(sunxi_machine_spdif_driver);
+
+MODULE_AUTHOR("Marcus Cooper ");
+MODULE_AUTHOR("Andrea Venturi, ");
+MODULE_DESCRIPTION("Allwinner sunxi S/PDIF machine driver");
+MODULE_LICENSE("GPL v2");
-- 
1.9.1

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


[PATCH v2 4/4] ASOC: sunxi: Add support for the spdif block

2015-09-30 Thread codekipper
From: Marcus Cooper 

The sun4i, sun6i and sun7i SoC families have an SPDIF
block which is capable of playback and capture.

This patch enables the playback of this block for
the sun4i and sun7i families.

Signed-off-by: Marcus Cooper 
---
 sound/soc/sunxi/Kconfig   |  12 +
 sound/soc/sunxi/Makefile  |   4 +
 sound/soc/sunxi/sun4i-spdif.c | 612 ++
 3 files changed, 628 insertions(+)
 create mode 100644 sound/soc/sunxi/sun4i-spdif.c

diff --git a/sound/soc/sunxi/Kconfig b/sound/soc/sunxi/Kconfig
index 84c72ec..2ebf43d 100644
--- a/sound/soc/sunxi/Kconfig
+++ b/sound/soc/sunxi/Kconfig
@@ -8,4 +8,16 @@ config SND_SUN4I_CODEC
  Select Y or M to add support for the Codec embedded in the Allwinner
  A10 and affiliated SoCs.
 
+config SND_SOC_SUNXI_DAI_SPDIF
+tristate
+   depends on OF
+select SND_SOC_GENERIC_DMAENGINE_PCM
+select REGMAP_MMIO
+
+config SND_SOC_SUNXI_MACHINE_SPDIF
+tristate "APB on-chip sun4i/sun5i/sun7i SPDIF"
+   depends on OF
+select SND_SOC_SUNXI_DAI_SPDIF
+help
+  Say Y if you want to add support for SoC S/PDIF audio as simple 
audio card.
 endmenu
diff --git a/sound/soc/sunxi/Makefile b/sound/soc/sunxi/Makefile
index ea8a08c..c8c0a00 100644
--- a/sound/soc/sunxi/Makefile
+++ b/sound/soc/sunxi/Makefile
@@ -1,2 +1,6 @@
 obj-$(CONFIG_SND_SUN4I_CODEC) += sun4i-codec.o
 
+snd-soc-sunxi-dai-spdif-objs := sun4i-spdif.o
+obj-$(CONFIG_SND_SOC_SUNXI_DAI_SPDIF) += snd-soc-sunxi-dai-spdif.o
+snd-soc-sunxi-machine-spdif-objs := sunxi-machine-spdif.o
+obj-$(CONFIG_SND_SOC_SUNXI_MACHINE_SPDIF) += snd-soc-sunxi-machine-spdif.o
diff --git a/sound/soc/sunxi/sun4i-spdif.c b/sound/soc/sunxi/sun4i-spdif.c
new file mode 100644
index 000..5fff6f6
--- /dev/null
+++ b/sound/soc/sunxi/sun4i-spdif.c
@@ -0,0 +1,612 @@
+/*
+ * ALSA SoC SPDIF Audio Layer
+ *
+ * Copyright 2015 Andrea Venturi 
+ * Copyright 2015 Marcus Cooper 
+ *
+ * Based on the Allwinner SDK driver, released under the GPL.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+/*
+ * this is SPDIF sun4i simple audio card DAI driver that uses the codec
+ * "dummy driver" as per sound/soc/fsl/imx-spdif.c
+ */
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+
+#defineSUN4I_SPDIF_CTL (0x00)
+   #define SUN4I_SPDIF_CTL_MCLKDIV(v)  ((v) << 4) /* v even */
+   #define SUN4I_SPDIF_CTL_MCLKOUTEN   BIT(2)
+   #define SUN4I_SPDIF_CTL_GEN BIT(1)
+   #define SUN4I_SPDIF_CTL_RESET   BIT(0)
+
+#define SUN4I_SPDIF_TXCFG  (0x04)
+   #define SUN4I_SPDIF_TXCFG_SINGLEMOD BIT(31)
+   #define SUN4I_SPDIF_TXCFG_ASS   BIT(17)
+   #define SUN4I_SPDIF_TXCFG_NONAUDIO  BIT(16)
+   #define SUN4I_SPDIF_TXCFG_TXRATIO(v)((v) << 4)
+   #define SUN4I_SPDIF_TXCFG_TXRATIO_MASK  GENMASK(8, 4)
+   #define SUN4I_SPDIF_TXCFG_FMTRVDGENMASK(3, 2)
+   #define SUN4I_SPDIF_TXCFG_FMT16BIT  (0 << 2)
+   #define SUN4I_SPDIF_TXCFG_FMT20BIT  (1 << 2)
+   #define SUN4I_SPDIF_TXCFG_FMT24BIT  (2 << 2)
+   #define SUN4I_SPDIF_TXCFG_CHSTMODE  BIT(1)
+   #define SUN4I_SPDIF_TXCFG_TXEN  BIT(0)
+
+#define SUN4I_SPDIF_RXCFG  (0x08)
+   #define SUN4I_SPDIF_RXCFG_LOCKFLAG  BIT(4)
+   #define SUN4I_SPDIF_RXCFG_CHSTSRC   BIT(3)
+   #define SUN4I_SPDIF_RXCFG_CHSTCPBIT(1)
+   #define SUN4I_SPDIF_RXCFG_RXEN  BIT(0)
+
+#define SUN4I_SPDIF_TXFIFO (0x0C)
+
+#define SUN4I_SPDIF_RXFIFO (0x10)
+
+#define SUN4I_SPDIF_FCTL   (0x14)
+   #define SUN4I_SPDIF_FCTL_FIFOSRCBIT(31)
+   #define SUN4I_SPDIF_FCTL_FTXBIT(17)
+   #define SUN4I_SPDIF_FCTL_FRXBIT(16)
+   #define SUN4I_SPDIF_FCTL_TXTL(v)((v) << 8)
+   #define SUN4I_SPDIF_FCTL_TXTL_MASK  GENMASK(12, 8)
+   #define SUN4I_SPDIF_FCTL_RXTL(v)((v) << 3)
+   #define SUN4I_SPDIF_FCTL_RXTL_MASK  GENMASK(7, 3)
+   #define SUN4I_SPDIF_FCTL_TXIM   BIT(2)
+   #define 

[PATCH v2 0/4] Add SPDIF support for Allwinner SoCs

2015-09-30 Thread codekipper
From: Marcus Cooper <codekip...@gmail.com>

This patch set adds support for the Allwinner SPDIF transceiver as present
on the A10, A20 and A31 SoC boards.

For now just the SPDIF transmitter has been tested on a Mele A2000.

In order for this patch set to be functional we require audio clock patches
which will be delivered separately. For those that are interested I've pushed
the patches here with all the required changes to get SPDIF audio out of the
device.

https://github.com/codekipper/linux-sunxi/commits/spdif_delivery

This is version 2 of the patch series. After Mark's initial comments I realised
that I shouldn't of blindly copied the register set-up from the original SDK
that was released. It doesn't help also that the datasheet that finally emerged
lacked a serious amount of detail. If anybody does recognise the IP used for the
block then please speak out.

In short, much of the code that was in the first release is no longer here. 

I'm still unsure about the machine driver setup. Simple card seems a bit 
overkill
and what I've added is pretty much a copy of what is done in imx-spdif. I'm not
planning on arguing the case for my method so if you can advise then I'm all
ears.

Thanks in advance,
CK

---
Changes since v1:
- Moved sunxi-machine-spdif.c to seperate patch
- replaced sunxi in naming scheme with sun4i in the sun4i-spdif driver.
- split tx controller into seperate enable/disable functions
- moved setclk and setfmt functionality into hw params
- added support for mono signals.
- cleaned up probe clock set up.
- removed all writes to transmit status registers.
- removed of_id
- removed power management code.
- Added support for more rates.
---
Marcus Cooper (4):
  dt-bindings: add sunxi SPDIF transceiver bindings
  dt-binding: Add sunxi S/PDIF machine driver
  ASoC: sunxi: Add S/PDIF machine driver.
  ASOC: sunxi: Add support for the spdif block

 .../devicetree/bindings/sound/sunxi,spdif.txt  |  49 ++
 .../bindings/sound/sunxi-audio-spdif.txt   |  36 ++
 sound/soc/sunxi/Kconfig|  12 +
 sound/soc/sunxi/Makefile   |   4 +
 sound/soc/sunxi/sun4i-spdif.c  | 612 +
 sound/soc/sunxi/sunxi-machine-spdif.c  | 108 
 6 files changed, 821 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/sound/sunxi,spdif.txt
 create mode 100644 
Documentation/devicetree/bindings/sound/sunxi-audio-spdif.txt
 create mode 100644 sound/soc/sunxi/sun4i-spdif.c
 create mode 100644 sound/soc/sunxi/sunxi-machine-spdif.c

-- 
1.9.1

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


[PATCH v2 2/4] dt-binding: Add sunxi S/PDIF machine driver

2015-09-30 Thread codekipper
From: Marcus Cooper 

Add device tree bindings for the SPDIF machine driver for Allwinner SoC
devices.

Signed-off-by: Marcus Cooper 
---
 .../bindings/sound/sunxi-audio-spdif.txt   | 36 ++
 1 file changed, 36 insertions(+)
 create mode 100644 
Documentation/devicetree/bindings/sound/sunxi-audio-spdif.txt

diff --git a/Documentation/devicetree/bindings/sound/sunxi-audio-spdif.txt 
b/Documentation/devicetree/bindings/sound/sunxi-audio-spdif.txt
new file mode 100644
index 000..b9e8152
--- /dev/null
+++ b/Documentation/devicetree/bindings/sound/sunxi-audio-spdif.txt
@@ -0,0 +1,36 @@
+Allwinner audio complex with S/PDIF transceiver
+
+Required properties:
+
+  - compatible : "Allwinner,sunxi-audio-spdif"
+
+  - model  : The user-visible name of this sound complex
+
+  - spdif-controller   : The phandle of the Allwinner S/PDIF controller
+
+
+Optional properties:
+
+  - spdif-out  : This is a boolean property. If present, the
+ transmitting function of S/PDIF will be enabled,
+ indicating there's a physical S/PDIF out connector
+ or jack on the board or it's connecting to some
+ other IP block, such as an HDMI encoder or
+ display-controller.
+
+  - spdif-in   : This is a boolean property. If present, the receiving
+ function of S/PDIF will be enabled, indicating there
+ is a physical S/PDIF in connector/jack on the board.
+
+* Note: At least one of these two properties should be set in the DT binding.
+
+
+Example:
+
+sound-spdif {
+   compatible = "allwinner,sunxi-audio-spdif";
+   model = "sunxi-spdif";
+   spdif-controller = <>;
+   spdif-out;
+   spdif-in;
+};
-- 
1.9.1

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


[PATCH v2 1/4] dt-bindings: add sunxi SPDIF transceiver bindings

2015-09-30 Thread codekipper
From: Marcus Cooper 

Add devicetree bindings for the SPDIF transceiver found on
found on Allwinners A10, A20 and A31 SoCs.

Signed-off-by: Marcus Cooper 
---
 .../devicetree/bindings/sound/sunxi,spdif.txt  | 49 ++
 1 file changed, 49 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/sound/sunxi,spdif.txt

diff --git a/Documentation/devicetree/bindings/sound/sunxi,spdif.txt 
b/Documentation/devicetree/bindings/sound/sunxi,spdif.txt
new file mode 100644
index 000..1868722
--- /dev/null
+++ b/Documentation/devicetree/bindings/sound/sunxi,spdif.txt
@@ -0,0 +1,49 @@
+Allwinner Sony/Philips Digital Interface Format (S/PDIF) Controller
+
+The Allwinner S/PDIF audio block is a transceiver that allows the
+processor to receive and transmit digital audio via an coaxial cable or
+a fibre cable.
+
+Required properties:
+
+  - compatible : should be one of the following:
+- "allwinner,sun4i-a10-spdif": for the Allwinner A10 SoC
+- "allwinner,sun7i-a20-spdif": for the Allwinner A20 SoC
+- "allwinner,sun6i-a31-spdif": for the Allwinner A31 SoC
+
+  - reg: Offset and length of the register set for the 
device.
+
+  - interrupts : Contains the 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:
+   "apb" clock for the spdif bus.
+   "audio"   clock from the audio pll.
+   "spdif"   clock for spdif controller.
+
+Optional:
+
+  - spdif-in   : Enable block for capturing an SPDIF signal.
+
+  - spdif-out  : Enable block for transmitting an SPDIF signal.
+
+Example:
+
+spdif: spdif@01c21000 {
+   compatible = "allwinner,sun4i-a10-spdif";
+   reg = <0x01c21000 0x40>;
+   interrupts = <13>;
+   clocks = <_gates 1>, < 0>, <_clk>;
+   clock-names = "apb", "audio", "spdif";
+   dmas = < 0 2>, < 0 2>;
+   dma-names = "rx", "tx";
+   spdif-in = "disabled";
+   spdif-out = "okay";
+   status = "okay";
+};
-- 
1.9.1

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


[linux-sunxi][alsa-devel][PATCH 1/3] dt-bindings: add sunxi SPDIF transceiver bindings

2015-09-23 Thread codekipper
From: Marcus Cooper 

Add devicetree bindings for the SPDIF transceiver found on
found on Allwinners A10, A20 and A31 SoCs.

Signed-off-by: Marcus Cooper 
---
 .../devicetree/bindings/sound/sunxi,spdif.txt  | 49 ++
 1 file changed, 49 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/sound/sunxi,spdif.txt

diff --git a/Documentation/devicetree/bindings/sound/sunxi,spdif.txt 
b/Documentation/devicetree/bindings/sound/sunxi,spdif.txt
new file mode 100644
index 000..1868722
--- /dev/null
+++ b/Documentation/devicetree/bindings/sound/sunxi,spdif.txt
@@ -0,0 +1,49 @@
+Allwinner Sony/Philips Digital Interface Format (S/PDIF) Controller
+
+The Allwinner S/PDIF audio block is a transceiver that allows the
+processor to receive and transmit digital audio via an coaxial cable or
+a fibre cable.
+
+Required properties:
+
+  - compatible : should be one of the following:
+- "allwinner,sun4i-a10-spdif": for the Allwinner A10 SoC
+- "allwinner,sun7i-a20-spdif": for the Allwinner A20 SoC
+- "allwinner,sun6i-a31-spdif": for the Allwinner A31 SoC
+
+  - reg: Offset and length of the register set for the 
device.
+
+  - interrupts : Contains the 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:
+   "apb" clock for the spdif bus.
+   "audio"   clock from the audio pll.
+   "spdif"   clock for spdif controller.
+
+Optional:
+
+  - spdif-in   : Enable block for capturing an SPDIF signal.
+
+  - spdif-out  : Enable block for transmitting an SPDIF signal.
+
+Example:
+
+spdif: spdif@01c21000 {
+   compatible = "allwinner,sun4i-a10-spdif";
+   reg = <0x01c21000 0x40>;
+   interrupts = <13>;
+   clocks = <_gates 1>, < 0>, <_clk>;
+   clock-names = "apb", "audio", "spdif";
+   dmas = < 0 2>, < 0 2>;
+   dma-names = "rx", "tx";
+   spdif-in = "disabled";
+   spdif-out = "okay";
+   status = "okay";
+};
-- 
2.5.3

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


[linux-sunxi][alsa-devel][PATCH 2/3] dt-binding: Add sunxi SPDIF machine driver

2015-09-23 Thread codekipper
From: Marcus Cooper 

Add device tree bindings for the SPDIF machine driver for Allwinner SoC
devices.

Signed-off-by: Marcus Cooper 
---
 .../bindings/sound/sunxi-audio-spdif.txt   | 36 ++
 1 file changed, 36 insertions(+)
 create mode 100644 
Documentation/devicetree/bindings/sound/sunxi-audio-spdif.txt

diff --git a/Documentation/devicetree/bindings/sound/sunxi-audio-spdif.txt 
b/Documentation/devicetree/bindings/sound/sunxi-audio-spdif.txt
new file mode 100644
index 000..b9e8152
--- /dev/null
+++ b/Documentation/devicetree/bindings/sound/sunxi-audio-spdif.txt
@@ -0,0 +1,36 @@
+Allwinner audio complex with S/PDIF transceiver
+
+Required properties:
+
+  - compatible : "Allwinner,sunxi-audio-spdif"
+
+  - model  : The user-visible name of this sound complex
+
+  - spdif-controller   : The phandle of the Allwinner S/PDIF controller
+
+
+Optional properties:
+
+  - spdif-out  : This is a boolean property. If present, the
+ transmitting function of S/PDIF will be enabled,
+ indicating there's a physical S/PDIF out connector
+ or jack on the board or it's connecting to some
+ other IP block, such as an HDMI encoder or
+ display-controller.
+
+  - spdif-in   : This is a boolean property. If present, the receiving
+ function of S/PDIF will be enabled, indicating there
+ is a physical S/PDIF in connector/jack on the board.
+
+* Note: At least one of these two properties should be set in the DT binding.
+
+
+Example:
+
+sound-spdif {
+   compatible = "allwinner,sunxi-audio-spdif";
+   model = "sunxi-spdif";
+   spdif-controller = <>;
+   spdif-out;
+   spdif-in;
+};
-- 
2.5.3

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


[linux-sunxi][alsa-devel][PATCH 0/3]Add SPDIF support for Allwinner SoCs

2015-09-23 Thread codekipper
From: Marcus Cooper <codekip...@gmail.com>

This patch set adds support for the Allwinner SPDIF transceiver as present
on the A10, A20 and A31 SoC boards.

For now just the SPDIF transmitter has been tested on a Mele A2000.

In order for this patch set to be functional we require audio clock patches
which will be delivered separately. For those that are interested I've pushed
the patches here with all the required changes to get SPDIF audio out of the
device.

https://github.com/codekipper/linux-sunxi/commits/spdif_delivery

Thanks in advance,
CK

Marcus Cooper (3):
  dt-bindings: add sunxi SPDIF transceiver bindings
  dt-binding: Add sunxi SPDIF machine driver
  ASOC: sunxi: Add support for the spdif block

 .../devicetree/bindings/sound/sunxi,spdif.txt  |  49 ++
 .../bindings/sound/sunxi-audio-spdif.txt   |  36 +
 sound/soc/sunxi/Kconfig|  10 +
 sound/soc/sunxi/Makefile   |   4 +
 sound/soc/sunxi/sunxi-machine-spdif.c  | 110 +++
 sound/soc/sunxi/sunxi-spdif.c  | 801 +
 6 files changed, 1010 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/sound/sunxi,spdif.txt
 create mode 100644 
Documentation/devicetree/bindings/sound/sunxi-audio-spdif.txt
 create mode 100644 sound/soc/sunxi/sunxi-machine-spdif.c
 create mode 100644 sound/soc/sunxi/sunxi-spdif.c

-- 
2.5.3

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


[linux-sunxi][alsa-devel][PATCH 3/3] ASOC: sunxi: Add support for the spdif block

2015-09-24 Thread codekipper
From: Marcus Cooper 

The sun4i, sun6i and sun7i SoC families have an SPDIF
block which is capable of playback and capture.

This patch enables the playback of this block for
the sun4i and sun7i families.

Signed-off-by: Marcus Cooper 
---
 sound/soc/sunxi/Kconfig   |  10 +
 sound/soc/sunxi/Makefile  |   4 +
 sound/soc/sunxi/sunxi-machine-spdif.c | 110 +
 sound/soc/sunxi/sunxi-spdif.c | 801 ++
 4 files changed, 925 insertions(+)
 create mode 100644 sound/soc/sunxi/sunxi-machine-spdif.c
 create mode 100644 sound/soc/sunxi/sunxi-spdif.c

diff --git a/sound/soc/sunxi/Kconfig b/sound/soc/sunxi/Kconfig
index 84c72ec..053db02 100644
--- a/sound/soc/sunxi/Kconfig
+++ b/sound/soc/sunxi/Kconfig
@@ -8,4 +8,14 @@ config SND_SUN4I_CODEC
  Select Y or M to add support for the Codec embedded in the Allwinner
  A10 and affiliated SoCs.
 
+config SND_SOC_SUNXI_DAI_SPDIF
+tristate
+select SND_SOC_GENERIC_DMAENGINE_PCM
+select REGMAP_MMIO
+
+config SND_SOC_SUNXI_MACHINE_SPDIF
+tristate "APB on-chip sun4i/sun5i/sun7i SPDIF"
+select SND_SOC_SUNXI_DAI_SPDIF
+help
+  Say Y if you want to add support for SoC S/PDIF audio as simple 
audio card.
 endmenu
diff --git a/sound/soc/sunxi/Makefile b/sound/soc/sunxi/Makefile
index ea8a08c..7849a75 100644
--- a/sound/soc/sunxi/Makefile
+++ b/sound/soc/sunxi/Makefile
@@ -1,2 +1,6 @@
 obj-$(CONFIG_SND_SUN4I_CODEC) += sun4i-codec.o
 
+snd-soc-sunxi-dai-spdif-objs := sunxi-spdif.o
+obj-$(CONFIG_SND_SOC_SUNXI_DAI_SPDIF) += snd-soc-sunxi-dai-spdif.o
+snd-soc-sunxi-machine-spdif-objs := sunxi-machine-spdif.o
+obj-$(CONFIG_SND_SOC_SUNXI_MACHINE_SPDIF) += snd-soc-sunxi-machine-spdif.o
diff --git a/sound/soc/sunxi/sunxi-machine-spdif.c 
b/sound/soc/sunxi/sunxi-machine-spdif.c
new file mode 100644
index 000..f8f6bd8
--- /dev/null
+++ b/sound/soc/sunxi/sunxi-machine-spdif.c
@@ -0,0 +1,110 @@
+/*
+ * Copyright (C) 2015 Andrea Venturi 
+ * From code by (C) 2013 Freescale Semiconductor, Inc.
+ * (sound/soc/fsl/imx-spdif.c)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include 
+#include 
+#include 
+
+struct sunxi_machine_spdif_data {
+   struct snd_soc_dai_link dai;
+   struct snd_soc_card card;
+};
+
+static int sunxi_machine_spdif_audio_probe(struct platform_device *pdev)
+{
+   struct device_node *spdif_np, *np = pdev->dev.of_node;
+   struct sunxi_machine_spdif_data *data;
+   int ret = 0;
+
+   dev_dbg(>dev, "%s: Looking for spdif-controller\n", __func__);
+   spdif_np = of_parse_phandle(np, "spdif-controller", 0);
+   if (!spdif_np) {
+   dev_err(>dev, "failed to find spdif-controller\n");
+   ret = -EINVAL;
+   goto end;
+   }
+
+   data = devm_kzalloc(>dev, sizeof(*data), GFP_KERNEL);
+   if (!data) {
+   ret = -ENOMEM;
+   goto end;
+   }
+
+   data->dai.name = "S/PDIF PCM";
+   data->dai.stream_name = "S/PDIF PCM";
+   data->dai.codec_dai_name = "snd-soc-dummy-dai";
+   data->dai.codec_name = "snd-soc-dummy";
+   data->dai.cpu_of_node = spdif_np;
+   data->dai.platform_of_node = spdif_np;
+   data->dai.playback_only = true;
+   data->dai.capture_only = true;
+
+   if (of_property_read_bool(np, "spdif-out"))
+   data->dai.capture_only = false;
+
+   if (of_property_read_bool(np, "spdif-in"))
+   data->dai.playback_only = false;
+
+   if (data->dai.playback_only && data->dai.capture_only) {
+   dev_err(>dev, "no enabled S/PDIF DAI link\n");
+   goto end;
+   }
+
+   data->card.dev = >dev;
+   data->card.dai_link = >dai;
+   data->card.num_links = 1;
+   data->card.owner = THIS_MODULE;
+
+   ret = snd_soc_of_parse_card_name(>card, "model");
+   if (ret)
+   goto end;
+
+   ret = devm_snd_soc_register_card(>dev, >card);
+   if (ret) {
+   dev_err(>dev, "snd_soc_register_card failed: %d\n", ret);
+   goto end;
+   }
+
+   platform_set_drvdata(pdev, data);
+
+end:
+   of_node_put(spdif_np);
+
+   return ret;
+}
+
+#ifdef CONFIG_OF
+static const struct of_device_id sunxi_machine_spdif_dt_ids[] = {
+   { .compatible = "allwinner,sunxi-audio-spdif", },
+   { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, sunxi_machine_spdif_dt_ids);

[PATCH v5 2/2] ASoC: sunxi: Add support for the SPDIF block

2016-02-08 Thread codekipper
From: Marcus Cooper 

The sun4i, sun5i and sun7i SoC families have an SPDIF
block which is capable of playback and capture.

This patch enables the playback of this block for
the sun4i families.

Signed-off-by: Marcus Cooper 
---
 sound/soc/sunxi/Kconfig   |   8 +
 sound/soc/sunxi/Makefile  |   1 +
 sound/soc/sunxi/sun4i-spdif.c | 549 ++
 3 files changed, 558 insertions(+)
 create mode 100644 sound/soc/sunxi/sun4i-spdif.c

diff --git a/sound/soc/sunxi/Kconfig b/sound/soc/sunxi/Kconfig
index 84c72ec..ae42294 100644
--- a/sound/soc/sunxi/Kconfig
+++ b/sound/soc/sunxi/Kconfig
@@ -8,4 +8,12 @@ config SND_SUN4I_CODEC
  Select Y or M to add support for the Codec embedded in the Allwinner
  A10 and affiliated SoCs.
 
+config SND_SUN4I_SPDIF
+   tristate "Allwinner A10 SPDIF Support"
+   depends on OF
+   select SND_SOC_GENERIC_DMAENGINE_PCM
+   select REGMAP_MMIO
+   help
+ Say Y or M to add support for the S/PDIF audio block in the Allwinner
+ A10 and affiliated SoCs.
 endmenu
diff --git a/sound/soc/sunxi/Makefile b/sound/soc/sunxi/Makefile
index ea8a08c..8f5e889 100644
--- a/sound/soc/sunxi/Makefile
+++ b/sound/soc/sunxi/Makefile
@@ -1,2 +1,3 @@
 obj-$(CONFIG_SND_SUN4I_CODEC) += sun4i-codec.o
 
+obj-$(CONFIG_SND_SUN4I_SPDIF) += sun4i-spdif.o
diff --git a/sound/soc/sunxi/sun4i-spdif.c b/sound/soc/sunxi/sun4i-spdif.c
new file mode 100644
index 000..85a58a7
--- /dev/null
+++ b/sound/soc/sunxi/sun4i-spdif.c
@@ -0,0 +1,549 @@
+/*
+ * ALSA SoC SPDIF Audio Layer
+ *
+ * Copyright 2015 Andrea Venturi 
+ * Copyright 2015 Marcus Cooper 
+ *
+ * Based on the Allwinner SDK driver, released under the GPL.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+
+#defineSUN4I_SPDIF_CTL (0x00)
+   #define SUN4I_SPDIF_CTL_MCLKDIV(v)  ((v) << 4) /* v even */
+   #define SUN4I_SPDIF_CTL_MCLKOUTEN   BIT(2)
+   #define SUN4I_SPDIF_CTL_GEN BIT(1)
+   #define SUN4I_SPDIF_CTL_RESET   BIT(0)
+
+#define SUN4I_SPDIF_TXCFG  (0x04)
+   #define SUN4I_SPDIF_TXCFG_SINGLEMOD BIT(31)
+   #define SUN4I_SPDIF_TXCFG_ASS   BIT(17)
+   #define SUN4I_SPDIF_TXCFG_NONAUDIO  BIT(16)
+   #define SUN4I_SPDIF_TXCFG_TXRATIO(v)((v) << 4)
+   #define SUN4I_SPDIF_TXCFG_TXRATIO_MASK  GENMASK(8, 4)
+   #define SUN4I_SPDIF_TXCFG_FMTRVDGENMASK(3, 2)
+   #define SUN4I_SPDIF_TXCFG_FMT16BIT  (0 << 2)
+   #define SUN4I_SPDIF_TXCFG_FMT20BIT  (1 << 2)
+   #define SUN4I_SPDIF_TXCFG_FMT24BIT  (2 << 2)
+   #define SUN4I_SPDIF_TXCFG_CHSTMODE  BIT(1)
+   #define SUN4I_SPDIF_TXCFG_TXEN  BIT(0)
+
+#define SUN4I_SPDIF_RXCFG  (0x08)
+   #define SUN4I_SPDIF_RXCFG_LOCKFLAG  BIT(4)
+   #define SUN4I_SPDIF_RXCFG_CHSTSRC   BIT(3)
+   #define SUN4I_SPDIF_RXCFG_CHSTCPBIT(1)
+   #define SUN4I_SPDIF_RXCFG_RXEN  BIT(0)
+
+#define SUN4I_SPDIF_TXFIFO (0x0C)
+
+#define SUN4I_SPDIF_RXFIFO (0x10)
+
+#define SUN4I_SPDIF_FCTL   (0x14)
+   #define SUN4I_SPDIF_FCTL_FIFOSRCBIT(31)
+   #define SUN4I_SPDIF_FCTL_FTXBIT(17)
+   #define SUN4I_SPDIF_FCTL_FRXBIT(16)
+   #define SUN4I_SPDIF_FCTL_TXTL(v)((v) << 8)
+   #define SUN4I_SPDIF_FCTL_TXTL_MASK  GENMASK(12, 8)
+   #define SUN4I_SPDIF_FCTL_RXTL(v)((v) << 3)
+   #define SUN4I_SPDIF_FCTL_RXTL_MASK  GENMASK(7, 3)
+   #define SUN4I_SPDIF_FCTL_TXIM   BIT(2)
+   #define SUN4I_SPDIF_FCTL_RXOM(v)((v) << 0)
+   #define SUN4I_SPDIF_FCTL_RXOM_MASK  GENMASK(1, 0)
+
+#define SUN4I_SPDIF_FSTA   (0x18)
+   #define SUN4I_SPDIF_FSTA_TXEBIT(14)
+   #define SUN4I_SPDIF_FSTA_TXECNTSHT  (8)
+   #define SUN4I_SPDIF_FSTA_RXABIT(6)
+   #define SUN4I_SPDIF_FSTA_RXACNTSHT  (0)
+
+#define SUN4I_SPDIF_INT(0x1C)
+

[PATCH v4 2/2] ASoC: sunxi: Add support for the SPDIF block

2016-02-04 Thread codekipper
From: Marcus Cooper 

The sun4i, sun5i and sun7i SoC families have an SPDIF
block which is capable of playback and capture.

This patch enables the playback of this block for
the sun4i families.

Signed-off-by: Marcus Cooper 
---
 sound/soc/sunxi/Kconfig   |   8 +
 sound/soc/sunxi/Makefile  |   1 +
 sound/soc/sunxi/sun4i-spdif.c | 561 ++
 3 files changed, 570 insertions(+)
 create mode 100644 sound/soc/sunxi/sun4i-spdif.c

diff --git a/sound/soc/sunxi/Kconfig b/sound/soc/sunxi/Kconfig
index 84c72ec..6af7224 100644
--- a/sound/soc/sunxi/Kconfig
+++ b/sound/soc/sunxi/Kconfig
@@ -8,4 +8,12 @@ config SND_SUN4I_CODEC
  Select Y or M to add support for the Codec embedded in the Allwinner
  A10 and affiliated SoCs.
 
+config SND_SUN4I_SPDIF
+tristate "Allwinner A10 SPDIF Support"
+   depends on OF
+select SND_SOC_GENERIC_DMAENGINE_PCM
+select REGMAP_MMIO
+help
+  Say Y or M to add support for the S/PDIF audio block in the Allwinner
+ A10 and affiliated SoCs.
 endmenu
diff --git a/sound/soc/sunxi/Makefile b/sound/soc/sunxi/Makefile
index ea8a08c..8f5e889 100644
--- a/sound/soc/sunxi/Makefile
+++ b/sound/soc/sunxi/Makefile
@@ -1,2 +1,3 @@
 obj-$(CONFIG_SND_SUN4I_CODEC) += sun4i-codec.o
 
+obj-$(CONFIG_SND_SUN4I_SPDIF) += sun4i-spdif.o
diff --git a/sound/soc/sunxi/sun4i-spdif.c b/sound/soc/sunxi/sun4i-spdif.c
new file mode 100644
index 000..bb32344
--- /dev/null
+++ b/sound/soc/sunxi/sun4i-spdif.c
@@ -0,0 +1,561 @@
+/*
+ * ALSA SoC SPDIF Audio Layer
+ *
+ * Copyright 2015 Andrea Venturi 
+ * Copyright 2015 Marcus Cooper 
+ *
+ * Based on the Allwinner SDK driver, released under the GPL.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+
+#defineSUN4I_SPDIF_CTL (0x00)
+   #define SUN4I_SPDIF_CTL_MCLKDIV(v)  ((v) << 4) /* v even */
+   #define SUN4I_SPDIF_CTL_MCLKOUTEN   BIT(2)
+   #define SUN4I_SPDIF_CTL_GEN BIT(1)
+   #define SUN4I_SPDIF_CTL_RESET   BIT(0)
+
+#define SUN4I_SPDIF_TXCFG  (0x04)
+   #define SUN4I_SPDIF_TXCFG_SINGLEMOD BIT(31)
+   #define SUN4I_SPDIF_TXCFG_ASS   BIT(17)
+   #define SUN4I_SPDIF_TXCFG_NONAUDIO  BIT(16)
+   #define SUN4I_SPDIF_TXCFG_TXRATIO(v)((v) << 4)
+   #define SUN4I_SPDIF_TXCFG_TXRATIO_MASK  GENMASK(8, 4)
+   #define SUN4I_SPDIF_TXCFG_FMTRVDGENMASK(3, 2)
+   #define SUN4I_SPDIF_TXCFG_FMT16BIT  (0 << 2)
+   #define SUN4I_SPDIF_TXCFG_FMT20BIT  (1 << 2)
+   #define SUN4I_SPDIF_TXCFG_FMT24BIT  (2 << 2)
+   #define SUN4I_SPDIF_TXCFG_CHSTMODE  BIT(1)
+   #define SUN4I_SPDIF_TXCFG_TXEN  BIT(0)
+
+#define SUN4I_SPDIF_RXCFG  (0x08)
+   #define SUN4I_SPDIF_RXCFG_LOCKFLAG  BIT(4)
+   #define SUN4I_SPDIF_RXCFG_CHSTSRC   BIT(3)
+   #define SUN4I_SPDIF_RXCFG_CHSTCPBIT(1)
+   #define SUN4I_SPDIF_RXCFG_RXEN  BIT(0)
+
+#define SUN4I_SPDIF_TXFIFO (0x0C)
+
+#define SUN4I_SPDIF_RXFIFO (0x10)
+
+#define SUN4I_SPDIF_FCTL   (0x14)
+   #define SUN4I_SPDIF_FCTL_FIFOSRCBIT(31)
+   #define SUN4I_SPDIF_FCTL_FTXBIT(17)
+   #define SUN4I_SPDIF_FCTL_FRXBIT(16)
+   #define SUN4I_SPDIF_FCTL_TXTL(v)((v) << 8)
+   #define SUN4I_SPDIF_FCTL_TXTL_MASK  GENMASK(12, 8)
+   #define SUN4I_SPDIF_FCTL_RXTL(v)((v) << 3)
+   #define SUN4I_SPDIF_FCTL_RXTL_MASK  GENMASK(7, 3)
+   #define SUN4I_SPDIF_FCTL_TXIM   BIT(2)
+   #define SUN4I_SPDIF_FCTL_RXOM(v)((v) << 0)
+   #define SUN4I_SPDIF_FCTL_RXOM_MASK  GENMASK(1, 0)
+
+#define SUN4I_SPDIF_FSTA   (0x18)
+   #define SUN4I_SPDIF_FSTA_TXEBIT(14)
+   #define SUN4I_SPDIF_FSTA_TXECNTSHT  (8)
+   #define SUN4I_SPDIF_FSTA_RXABIT(6)
+   #define SUN4I_SPDIF_FSTA_RXACNTSHT  (0)
+
+#define SUN4I_SPDIF_INT(0x1C)

[PATCH v4 1/2] dt-bindings: sunxi :add sun4i SPDIF transceiver

2016-02-04 Thread codekipper
From: Marcus Cooper 

Add devicetree bindings for the SPDIF transceiver found on
found on Allwinners A10 and A20 SoCs.

Signed-off-by: Marcus Cooper 
---
 .../bindings/sound/sunxi,sun4i-spdif.txt   | 39 ++
 1 file changed, 39 insertions(+)
 create mode 100644 
Documentation/devicetree/bindings/sound/sunxi,sun4i-spdif.txt

diff --git a/Documentation/devicetree/bindings/sound/sunxi,sun4i-spdif.txt 
b/Documentation/devicetree/bindings/sound/sunxi,sun4i-spdif.txt
new file mode 100644
index 000..13503aa
--- /dev/null
+++ b/Documentation/devicetree/bindings/sound/sunxi,sun4i-spdif.txt
@@ -0,0 +1,39 @@
+Allwinner Sony/Philips Digital Interface Format (S/PDIF) Controller
+
+The Allwinner S/PDIF audio block is a transceiver that allows the
+processor to receive and transmit digital audio via an coaxial cable or
+a fibre cable.
+For now only playback is supported.
+
+Required properties:
+
+  - compatible : should be one of the following:
+- "allwinner,sun4i-a10-spdif": for the Allwinner A10 SoC
+
+  - reg: Offset and length of the register set for the 
device.
+
+  - interrupts : Contains the 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:
+   "apb" clock for the spdif bus.
+   "spdif"   clock for spdif controller.
+
+Example:
+
+spdif: spdif@01c21000 {
+   compatible = "allwinner,sun4i-a10-spdif";
+   reg = <0x01c21000 0x40>;
+   interrupts = <13>;
+   clocks = <_gates 1>, <_clk>;
+   clock-names = "apb", "spdif";
+   dmas = < 0 2>, < 0 2>;
+   dma-names = "rx", "tx";
+   status = "okay";
+};
-- 
2.7.0



[PATCH v4 0/2] ASoC: Add SPDIF support for Allwinner SoCs

2016-02-04 Thread codekipper
From: Marcus Cooper <codekip...@gmail.com>

This patch set adds support for the Allwinner SPDIF transceiver.

For now just the SPDIF transmitter has been tested on a Mele A2000(A10)
and a Itead Ibox(A20).

In order for this patch set to be functional we require an audio clock patch
which will be delivered separately. For those that are interested I've pushed
the patches here with all the required changes to get SPDIF audio out of the
device.

https://github.com/codekipper/linux-sunxi/commits/spdif_delivery

Thanks in advance,
CK

---
Changes since v3:
- removed code required for spdif capture
- added disable/enable of apb clk to suspend/resume.
- removed unnecessary dt checks in probe
- fixed error conditions in probe/resume
- modified pm_runtime functionality(confirmed driver worked with PM disabled).
- removed .owner from platform driver
- renamed bindings file
 
Changes since v2:
- removed sunxi-machine-spdif and replaced with simple audio card
- removed untested compatibilities from device tree documentation
- added pm_runtime and remove shutdown
- removed pll2 as it's the parent of the spdif clock
- rename clk to spdif_clk
- removed enabling of mclk output
- removed interrupts status being cleared as it's not being used
- use default fifo settings for now
- fixed alignments for wrapped lines

Changes since v1:
- Moved sunxi-machine-spdif.c to separate patch
- replaced sunxi in naming scheme with sun4i in the sun4i-spdif driver.
- split tx controller into separate enable/disable functions
- moved setclk and setfmt functionality into hw params
- added support for mono signals.
- cleaned up probe clock set up.
- removed all writes to transmit status registers.
- removed of_id
- removed power management code.
- Added support for more rates.

Marcus Cooper (2):
  dt-bindings: sunxi :add sun4i SPDIF transceiver
  ASoC: sunxi: Add support for the SPDIF block

 .../bindings/sound/sunxi,sun4i-spdif.txt   |  39 ++
 sound/soc/sunxi/Kconfig|   8 +
 sound/soc/sunxi/Makefile   |   1 +
 sound/soc/sunxi/sun4i-spdif.c  | 561 +
 4 files changed, 609 insertions(+)
 create mode 100644 
Documentation/devicetree/bindings/sound/sunxi,sun4i-spdif.txt
 create mode 100644 sound/soc/sunxi/sun4i-spdif.c

-- 
2.7.0



[PATCH v5 1/2] dt-bindings: sunxi :add sun4i SPDIF transceiver

2016-02-08 Thread codekipper
From: Marcus Cooper 

Add devicetree bindings for the SPDIF transceiver found on
found on Allwinners A10 and A20 SoCs.

Signed-off-by: Marcus Cooper 
---
 .../bindings/sound/sunxi,sun4i-spdif.txt   | 39 ++
 1 file changed, 39 insertions(+)
 create mode 100644 
Documentation/devicetree/bindings/sound/sunxi,sun4i-spdif.txt

diff --git a/Documentation/devicetree/bindings/sound/sunxi,sun4i-spdif.txt 
b/Documentation/devicetree/bindings/sound/sunxi,sun4i-spdif.txt
new file mode 100644
index 000..13503aa
--- /dev/null
+++ b/Documentation/devicetree/bindings/sound/sunxi,sun4i-spdif.txt
@@ -0,0 +1,39 @@
+Allwinner Sony/Philips Digital Interface Format (S/PDIF) Controller
+
+The Allwinner S/PDIF audio block is a transceiver that allows the
+processor to receive and transmit digital audio via an coaxial cable or
+a fibre cable.
+For now only playback is supported.
+
+Required properties:
+
+  - compatible : should be one of the following:
+- "allwinner,sun4i-a10-spdif": for the Allwinner A10 SoC
+
+  - reg: Offset and length of the register set for the 
device.
+
+  - interrupts : Contains the 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:
+   "apb" clock for the spdif bus.
+   "spdif"   clock for spdif controller.
+
+Example:
+
+spdif: spdif@01c21000 {
+   compatible = "allwinner,sun4i-a10-spdif";
+   reg = <0x01c21000 0x40>;
+   interrupts = <13>;
+   clocks = <_gates 1>, <_clk>;
+   clock-names = "apb", "spdif";
+   dmas = < 0 2>, < 0 2>;
+   dma-names = "rx", "tx";
+   status = "okay";
+};
-- 
2.7.1



[PATCH v5 0/2] ASoC: Add SPDIF support for Allwinner SoCs

2016-02-08 Thread codekipper
From: Marcus Cooper <codekip...@gmail.com>

This patch set adds support for the Allwinner SPDIF transceiver.

For now just the SPDIF transmitter has been tested on a Mele A2000(A10)
and a Itead Ibox(A20).

In order for this patch set to be functional we require an audio clock patch
which will be delivered separately. For those that are interested I've pushed
the patches here with all the required changes to get SPDIF audio out of the
device.

https://github.com/codekipper/linux-sunxi/commits/spdif_delivery

Thanks in advance,
CK

---
Changes since v4:
- corrected indentation issues
- removed old macros
- removed unnecessary enabling of apb clock

Changes since v3:
- removed code required for spdif capture
- added disable/enable of apb clk to suspend/resume.
- removed unnecessary dt checks in probe
- fixed error conditions in probe/resume
- modified pm_runtime functionality and confirmed that driver worked when PM 
was disabled.
- removed .owner from platform driver
- renamed bindings file

Changes since v2:
- removed sunxi-machine-spdif and replaced with simple audio card
- removed untested compatibilities from device tree documentation
- added pm_runtime and remove shutdown
- removed pll2 as it's the parent of the spdif clock
- rename clk to spdif_clk
- removed enabling of mclk output
- removed interrupts status being cleared as it's not being used
- use default fifo settings for now
- fixed alignments for wrapped lines

Changes since v1:
- Moved sunxi-machine-spdif.c to separate patch
- replaced sunxi in naming scheme with sun4i in the sun4i-spdif driver.
- split tx controller into separate enable/disable functions
- moved setclk and setfmt functionality into hw params
- added support for mono signals.
- cleaned up probe clock set up.
- removed all writes to transmit status registers.
- removed of_id
- removed power management code.
- Added support for more rates.

Marcus Cooper (2):
  dt-bindings: sunxi :add sun4i SPDIF transceiver
  ASoC: sunxi: Add support for the SPDIF block

 .../bindings/sound/sunxi,sun4i-spdif.txt   |  39 ++
 sound/soc/sunxi/Kconfig|   8 +
 sound/soc/sunxi/Makefile   |   1 +
 sound/soc/sunxi/sun4i-spdif.c  | 549 +
 4 files changed, 597 insertions(+)
 create mode 100644 
Documentation/devicetree/bindings/sound/sunxi,sun4i-spdif.txt
 create mode 100644 sound/soc/sunxi/sun4i-spdif.c

-- 
2.7.1



[PATCH v6 1/2] dt-bindings: sunxi :add sun4i SPDIF transceiver

2016-02-08 Thread codekipper
From: Marcus Cooper 

Add devicetree bindings for the SPDIF transceiver found on
found on Allwinners A10 and A20 SoCs.

Signed-off-by: Marcus Cooper 
---
 .../bindings/sound/sunxi,sun4i-spdif.txt   | 39 ++
 1 file changed, 39 insertions(+)
 create mode 100644 
Documentation/devicetree/bindings/sound/sunxi,sun4i-spdif.txt

diff --git a/Documentation/devicetree/bindings/sound/sunxi,sun4i-spdif.txt 
b/Documentation/devicetree/bindings/sound/sunxi,sun4i-spdif.txt
new file mode 100644
index 000..13503aa
--- /dev/null
+++ b/Documentation/devicetree/bindings/sound/sunxi,sun4i-spdif.txt
@@ -0,0 +1,39 @@
+Allwinner Sony/Philips Digital Interface Format (S/PDIF) Controller
+
+The Allwinner S/PDIF audio block is a transceiver that allows the
+processor to receive and transmit digital audio via an coaxial cable or
+a fibre cable.
+For now only playback is supported.
+
+Required properties:
+
+  - compatible : should be one of the following:
+- "allwinner,sun4i-a10-spdif": for the Allwinner A10 SoC
+
+  - reg: Offset and length of the register set for the 
device.
+
+  - interrupts : Contains the 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:
+   "apb" clock for the spdif bus.
+   "spdif"   clock for spdif controller.
+
+Example:
+
+spdif: spdif@01c21000 {
+   compatible = "allwinner,sun4i-a10-spdif";
+   reg = <0x01c21000 0x40>;
+   interrupts = <13>;
+   clocks = <_gates 1>, <_clk>;
+   clock-names = "apb", "spdif";
+   dmas = < 0 2>, < 0 2>;
+   dma-names = "rx", "tx";
+   status = "okay";
+};
-- 
2.7.1



[PATCH v6 0/2] ASoC: Add SPDIF support for Allwinner SoCs

2016-02-08 Thread codekipper
From: Marcus Cooper <codekip...@gmail.com>

This patch set adds support for the Allwinner SPDIF transceiver.

For now just the SPDIF transmitter has been tested on a Mele A2000(A10)
and a Itead Ibox(A20).

In order for this patch set to be functional we require an audio clock patch
which will be delivered separately. For those that are interested I've pushed
the patches here with all the required changes to get SPDIF audio out of the
device.

https://github.com/codekipper/linux-sunxi/commits/spdif_delivery

Thanks in advance,
CK

---
Changes since v5:
- fixed warning that had sneaked in.'

Changes since v4:
- corrected indentation issues
- removed old macros
- removed unnecessary enabling of apb clock

Changes since v3:
- removed code required for spdif capture
- added disable/enable of apb clk to suspend/resume.
- removed unnecessary dt checks in probe
- fixed error conditions in probe/resume
- modified pm_runtime functionality and confirmed that driver worked when PM 
was disabled.
- removed .owner from platform driver
- renamed bindings file

Changes since v2:
- removed sunxi-machine-spdif and replaced with simple audio card
- removed untested compatibilities from device tree documentation
- added pm_runtime and remove shutdown
- removed pll2 as it's the parent of the spdif clock
- rename clk to spdif_clk
- removed enabling of mclk output
- removed interrupts status being cleared as it's not being used
- use default fifo settings for now
- fixed alignments for wrapped lines

Changes since v1:
- Moved sunxi-machine-spdif.c to separate patch
- replaced sunxi in naming scheme with sun4i in the sun4i-spdif driver.
- split tx controller into separate enable/disable functions
- moved setclk and setfmt functionality into hw params
- added support for mono signals.
- cleaned up probe clock set up.
- removed all writes to transmit status registers.
- removed of_id
- removed power management code.
- Added support for more rates.


Marcus Cooper (2):
  dt-bindings: sunxi :add sun4i SPDIF transceiver
  ASoC: sunxi: Add support for the SPDIF block

 .../bindings/sound/sunxi,sun4i-spdif.txt   |  39 ++
 sound/soc/sunxi/Kconfig|   8 +
 sound/soc/sunxi/Makefile   |   1 +
 sound/soc/sunxi/sun4i-spdif.c  | 550 +
 4 files changed, 598 insertions(+)
 create mode 100644 
Documentation/devicetree/bindings/sound/sunxi,sun4i-spdif.txt
 create mode 100644 sound/soc/sunxi/sun4i-spdif.c

-- 
2.7.1



[PATCH v6 2/2] ASoC: sunxi: Add support for the SPDIF block

2016-02-08 Thread codekipper
From: Marcus Cooper 

The sun4i, sun5i and sun7i SoC families have an SPDIF
block which is capable of playback and capture.

This patch enables the playback of this block for
the sun4i families.

Signed-off-by: Marcus Cooper 
---
 sound/soc/sunxi/Kconfig   |   8 +
 sound/soc/sunxi/Makefile  |   1 +
 sound/soc/sunxi/sun4i-spdif.c | 550 ++
 3 files changed, 559 insertions(+)
 create mode 100644 sound/soc/sunxi/sun4i-spdif.c

diff --git a/sound/soc/sunxi/Kconfig b/sound/soc/sunxi/Kconfig
index 84c72ec..ae42294 100644
--- a/sound/soc/sunxi/Kconfig
+++ b/sound/soc/sunxi/Kconfig
@@ -8,4 +8,12 @@ config SND_SUN4I_CODEC
  Select Y or M to add support for the Codec embedded in the Allwinner
  A10 and affiliated SoCs.
 
+config SND_SUN4I_SPDIF
+   tristate "Allwinner A10 SPDIF Support"
+   depends on OF
+   select SND_SOC_GENERIC_DMAENGINE_PCM
+   select REGMAP_MMIO
+   help
+ Say Y or M to add support for the S/PDIF audio block in the Allwinner
+ A10 and affiliated SoCs.
 endmenu
diff --git a/sound/soc/sunxi/Makefile b/sound/soc/sunxi/Makefile
index ea8a08c..8f5e889 100644
--- a/sound/soc/sunxi/Makefile
+++ b/sound/soc/sunxi/Makefile
@@ -1,2 +1,3 @@
 obj-$(CONFIG_SND_SUN4I_CODEC) += sun4i-codec.o
 
+obj-$(CONFIG_SND_SUN4I_SPDIF) += sun4i-spdif.o
diff --git a/sound/soc/sunxi/sun4i-spdif.c b/sound/soc/sunxi/sun4i-spdif.c
new file mode 100644
index 000..0b04fb0
--- /dev/null
+++ b/sound/soc/sunxi/sun4i-spdif.c
@@ -0,0 +1,550 @@
+/*
+ * ALSA SoC SPDIF Audio Layer
+ *
+ * Copyright 2015 Andrea Venturi 
+ * Copyright 2015 Marcus Cooper 
+ *
+ * Based on the Allwinner SDK driver, released under the GPL.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+
+#defineSUN4I_SPDIF_CTL (0x00)
+   #define SUN4I_SPDIF_CTL_MCLKDIV(v)  ((v) << 4) /* v even */
+   #define SUN4I_SPDIF_CTL_MCLKOUTEN   BIT(2)
+   #define SUN4I_SPDIF_CTL_GEN BIT(1)
+   #define SUN4I_SPDIF_CTL_RESET   BIT(0)
+
+#define SUN4I_SPDIF_TXCFG  (0x04)
+   #define SUN4I_SPDIF_TXCFG_SINGLEMOD BIT(31)
+   #define SUN4I_SPDIF_TXCFG_ASS   BIT(17)
+   #define SUN4I_SPDIF_TXCFG_NONAUDIO  BIT(16)
+   #define SUN4I_SPDIF_TXCFG_TXRATIO(v)((v) << 4)
+   #define SUN4I_SPDIF_TXCFG_TXRATIO_MASK  GENMASK(8, 4)
+   #define SUN4I_SPDIF_TXCFG_FMTRVDGENMASK(3, 2)
+   #define SUN4I_SPDIF_TXCFG_FMT16BIT  (0 << 2)
+   #define SUN4I_SPDIF_TXCFG_FMT20BIT  (1 << 2)
+   #define SUN4I_SPDIF_TXCFG_FMT24BIT  (2 << 2)
+   #define SUN4I_SPDIF_TXCFG_CHSTMODE  BIT(1)
+   #define SUN4I_SPDIF_TXCFG_TXEN  BIT(0)
+
+#define SUN4I_SPDIF_RXCFG  (0x08)
+   #define SUN4I_SPDIF_RXCFG_LOCKFLAG  BIT(4)
+   #define SUN4I_SPDIF_RXCFG_CHSTSRC   BIT(3)
+   #define SUN4I_SPDIF_RXCFG_CHSTCPBIT(1)
+   #define SUN4I_SPDIF_RXCFG_RXEN  BIT(0)
+
+#define SUN4I_SPDIF_TXFIFO (0x0C)
+
+#define SUN4I_SPDIF_RXFIFO (0x10)
+
+#define SUN4I_SPDIF_FCTL   (0x14)
+   #define SUN4I_SPDIF_FCTL_FIFOSRCBIT(31)
+   #define SUN4I_SPDIF_FCTL_FTXBIT(17)
+   #define SUN4I_SPDIF_FCTL_FRXBIT(16)
+   #define SUN4I_SPDIF_FCTL_TXTL(v)((v) << 8)
+   #define SUN4I_SPDIF_FCTL_TXTL_MASK  GENMASK(12, 8)
+   #define SUN4I_SPDIF_FCTL_RXTL(v)((v) << 3)
+   #define SUN4I_SPDIF_FCTL_RXTL_MASK  GENMASK(7, 3)
+   #define SUN4I_SPDIF_FCTL_TXIM   BIT(2)
+   #define SUN4I_SPDIF_FCTL_RXOM(v)((v) << 0)
+   #define SUN4I_SPDIF_FCTL_RXOM_MASK  GENMASK(1, 0)
+
+#define SUN4I_SPDIF_FSTA   (0x18)
+   #define SUN4I_SPDIF_FSTA_TXEBIT(14)
+   #define SUN4I_SPDIF_FSTA_TXECNTSHT  (8)
+   #define SUN4I_SPDIF_FSTA_RXABIT(6)
+   #define SUN4I_SPDIF_FSTA_RXACNTSHT  (0)
+
+#define SUN4I_SPDIF_INT(0x1C)
+

[PATCH v3 2/2] ASOC: sunxi: Add support for the SPDIF block

2016-02-02 Thread codekipper
From: Marcus Cooper 

The sun4i, sun5i and sun7i SoC families have an SPDIF
block which is capable of playback and capture.

This patch enables the playback of this block for
the sun4i families.

Signed-off-by: Marcus Cooper 
---
 sound/soc/sunxi/Kconfig   |   8 +
 sound/soc/sunxi/Makefile  |   1 +
 sound/soc/sunxi/sun4i-spdif.c | 586 ++
 3 files changed, 595 insertions(+)
 create mode 100644 sound/soc/sunxi/sun4i-spdif.c

diff --git a/sound/soc/sunxi/Kconfig b/sound/soc/sunxi/Kconfig
index 84c72ec..6af7224 100644
--- a/sound/soc/sunxi/Kconfig
+++ b/sound/soc/sunxi/Kconfig
@@ -8,4 +8,12 @@ config SND_SUN4I_CODEC
  Select Y or M to add support for the Codec embedded in the Allwinner
  A10 and affiliated SoCs.
 
+config SND_SUN4I_SPDIF
+tristate "Allwinner A10 SPDIF Support"
+   depends on OF
+select SND_SOC_GENERIC_DMAENGINE_PCM
+select REGMAP_MMIO
+help
+  Say Y or M to add support for the S/PDIF audio block in the Allwinner
+ A10 and affiliated SoCs.
 endmenu
diff --git a/sound/soc/sunxi/Makefile b/sound/soc/sunxi/Makefile
index ea8a08c..8f5e889 100644
--- a/sound/soc/sunxi/Makefile
+++ b/sound/soc/sunxi/Makefile
@@ -1,2 +1,3 @@
 obj-$(CONFIG_SND_SUN4I_CODEC) += sun4i-codec.o
 
+obj-$(CONFIG_SND_SUN4I_SPDIF) += sun4i-spdif.o
diff --git a/sound/soc/sunxi/sun4i-spdif.c b/sound/soc/sunxi/sun4i-spdif.c
new file mode 100644
index 000..16265b3
--- /dev/null
+++ b/sound/soc/sunxi/sun4i-spdif.c
@@ -0,0 +1,586 @@
+/*
+ * ALSA SoC SPDIF Audio Layer
+ *
+ * Copyright 2015 Andrea Venturi 
+ * Copyright 2015 Marcus Cooper 
+ *
+ * Based on the Allwinner SDK driver, released under the GPL.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+
+#defineSUN4I_SPDIF_CTL (0x00)
+   #define SUN4I_SPDIF_CTL_MCLKDIV(v)  ((v) << 4) /* v even */
+   #define SUN4I_SPDIF_CTL_MCLKOUTEN   BIT(2)
+   #define SUN4I_SPDIF_CTL_GEN BIT(1)
+   #define SUN4I_SPDIF_CTL_RESET   BIT(0)
+
+#define SUN4I_SPDIF_TXCFG  (0x04)
+   #define SUN4I_SPDIF_TXCFG_SINGLEMOD BIT(31)
+   #define SUN4I_SPDIF_TXCFG_ASS   BIT(17)
+   #define SUN4I_SPDIF_TXCFG_NONAUDIO  BIT(16)
+   #define SUN4I_SPDIF_TXCFG_TXRATIO(v)((v) << 4)
+   #define SUN4I_SPDIF_TXCFG_TXRATIO_MASK  GENMASK(8, 4)
+   #define SUN4I_SPDIF_TXCFG_FMTRVDGENMASK(3, 2)
+   #define SUN4I_SPDIF_TXCFG_FMT16BIT  (0 << 2)
+   #define SUN4I_SPDIF_TXCFG_FMT20BIT  (1 << 2)
+   #define SUN4I_SPDIF_TXCFG_FMT24BIT  (2 << 2)
+   #define SUN4I_SPDIF_TXCFG_CHSTMODE  BIT(1)
+   #define SUN4I_SPDIF_TXCFG_TXEN  BIT(0)
+
+#define SUN4I_SPDIF_RXCFG  (0x08)
+   #define SUN4I_SPDIF_RXCFG_LOCKFLAG  BIT(4)
+   #define SUN4I_SPDIF_RXCFG_CHSTSRC   BIT(3)
+   #define SUN4I_SPDIF_RXCFG_CHSTCPBIT(1)
+   #define SUN4I_SPDIF_RXCFG_RXEN  BIT(0)
+
+#define SUN4I_SPDIF_TXFIFO (0x0C)
+
+#define SUN4I_SPDIF_RXFIFO (0x10)
+
+#define SUN4I_SPDIF_FCTL   (0x14)
+   #define SUN4I_SPDIF_FCTL_FIFOSRCBIT(31)
+   #define SUN4I_SPDIF_FCTL_FTXBIT(17)
+   #define SUN4I_SPDIF_FCTL_FRXBIT(16)
+   #define SUN4I_SPDIF_FCTL_TXTL(v)((v) << 8)
+   #define SUN4I_SPDIF_FCTL_TXTL_MASK  GENMASK(12, 8)
+   #define SUN4I_SPDIF_FCTL_RXTL(v)((v) << 3)
+   #define SUN4I_SPDIF_FCTL_RXTL_MASK  GENMASK(7, 3)
+   #define SUN4I_SPDIF_FCTL_TXIM   BIT(2)
+   #define SUN4I_SPDIF_FCTL_RXOM(v)((v) << 0)
+   #define SUN4I_SPDIF_FCTL_RXOM_MASK  GENMASK(1, 0)
+
+#define SUN4I_SPDIF_FSTA   (0x18)
+   #define SUN4I_SPDIF_FSTA_TXEBIT(14)
+   #define SUN4I_SPDIF_FSTA_TXECNTSHT  (8)
+   #define SUN4I_SPDIF_FSTA_RXABIT(6)
+   #define SUN4I_SPDIF_FSTA_RXACNTSHT  (0)
+
+#define SUN4I_SPDIF_INT(0x1C)

[PATCH v3 0/2] Add SPDIF support for Allwinner SoCs

2016-02-02 Thread codekipper
From: Marcus Cooper <codekip...@gmail.com>

This patch set adds support for the Allwinner SPDIF transceiver.

For now just the SPDIF transmitter has been tested on a Mele A2000(A10)
and a Itead Ibox(A20).

In order for this patch set to be functional we require an audio clock patch
which will be delivered separately. For those that are interested I've pushed
the patches here with all the required changes to get SPDIF audio out of the
device.

https://github.com/codekipper/linux-sunxi/commits/spdif_delivery

This is version 3 of the patch series. It's been quite a while since v2 and I'm
hoping now that all the previous comments have been acted on.

Thanks in advance,
CK

---
Changes since v2:
- removed sunxi-machine-spdif and replaced with simple audio card
- removed untested compatibilities from device tree documentation
- added pm_runtime and remove shutdown
- removed pll2 as it's the parent of the spdif clock
- rename clk to spdif_clk
- removed enabling of mclk output
- removed interrupts status being cleared as it's not being used
- use default fifo settings for now
- fixed alignments for wrapped lines

Changes since v1:
- Moved sunxi-machine-spdif.c to separate patch
- replaced sunxi in naming scheme with sun4i in the sun4i-spdif driver.
- split tx controller into separate enable/disable functions
- moved setclk and setfmt functionality into hw params
- added support for mono signals.
- cleaned up probe clock set up.
- removed all writes to transmit status registers.
- removed of_id
- removed power management code.
- Added support for more rates.

Marcus Cooper (2):
  dt-bindings: add sun4i SPDIF transceiver bindings
  ASOC: sunxi: Add support for the SPDIF block

 .../devicetree/bindings/sound/sun4i,spdif.txt  |  46 ++
 sound/soc/sunxi/Kconfig|   8 +
 sound/soc/sunxi/Makefile   |   1 +
 sound/soc/sunxi/sun4i-spdif.c  | 586 +
 4 files changed, 641 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/sound/sun4i,spdif.txt
 create mode 100644 sound/soc/sunxi/sun4i-spdif.c

-- 
2.7.0



[PATCH v3 1/2] dt-bindings: add sun4i SPDIF transceiver bindings

2016-02-02 Thread codekipper
From: Marcus Cooper 

Add devicetree bindings for the SPDIF transceiver found on
found on Allwinners A10 and A20 SoCs.

Signed-off-by: Marcus Cooper 
---
 .../devicetree/bindings/sound/sun4i,spdif.txt  | 46 ++
 1 file changed, 46 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/sound/sun4i,spdif.txt

diff --git a/Documentation/devicetree/bindings/sound/sun4i,spdif.txt 
b/Documentation/devicetree/bindings/sound/sun4i,spdif.txt
new file mode 100644
index 000..55ed2f6
--- /dev/null
+++ b/Documentation/devicetree/bindings/sound/sun4i,spdif.txt
@@ -0,0 +1,46 @@
+Allwinner Sony/Philips Digital Interface Format (S/PDIF) Controller
+
+The Allwinner S/PDIF audio block is a transceiver that allows the
+processor to receive and transmit digital audio via an coaxial cable or
+a fibre cable.
+
+Required properties:
+
+  - compatible : should be one of the following:
+- "allwinner,sun4i-a10-spdif": for the Allwinner A10 SoC
+
+  - reg: Offset and length of the register set for the 
device.
+
+  - interrupts : Contains the 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:
+   "apb" clock for the spdif bus.
+   "spdif"   clock for spdif controller.
+
+Optional:
+
+  - spdif-in   : Enable block for capturing an SPDIF signal.
+
+  - spdif-out  : Enable block for transmitting an SPDIF signal.
+
+Example:
+
+spdif: spdif@01c21000 {
+   compatible = "allwinner,sun4i-a10-spdif";
+   reg = <0x01c21000 0x40>;
+   interrupts = <13>;
+   clocks = <_gates 1>, <_clk>;
+   clock-names = "apb", "spdif";
+   dmas = < 0 2>, < 0 2>;
+   dma-names = "rx", "tx";
+   spdif-in = "disabled";
+   spdif-out = "okay";
+   status = "okay";
+};
-- 
2.7.0



[PATCH v7 2/2] ASoC: sunxi: Add support for the SPDIF block

2016-02-21 Thread codekipper
From: Marcus Cooper 

The sun4i, sun5i and sun7i SoC families have an SPDIF
block which is capable of playback and capture.

This patch enables the playback of this block for
the sun4i families.

Signed-off-by: Marcus Cooper 
---
 sound/soc/sunxi/Kconfig   |   8 +
 sound/soc/sunxi/Makefile  |   1 +
 sound/soc/sunxi/sun4i-spdif.c | 542 ++
 3 files changed, 551 insertions(+)
 create mode 100644 sound/soc/sunxi/sun4i-spdif.c

diff --git a/sound/soc/sunxi/Kconfig b/sound/soc/sunxi/Kconfig
index 84c72ec..ae42294 100644
--- a/sound/soc/sunxi/Kconfig
+++ b/sound/soc/sunxi/Kconfig
@@ -8,4 +8,12 @@ config SND_SUN4I_CODEC
  Select Y or M to add support for the Codec embedded in the Allwinner
  A10 and affiliated SoCs.
 
+config SND_SUN4I_SPDIF
+   tristate "Allwinner A10 SPDIF Support"
+   depends on OF
+   select SND_SOC_GENERIC_DMAENGINE_PCM
+   select REGMAP_MMIO
+   help
+ Say Y or M to add support for the S/PDIF audio block in the Allwinner
+ A10 and affiliated SoCs.
 endmenu
diff --git a/sound/soc/sunxi/Makefile b/sound/soc/sunxi/Makefile
index ea8a08c..8f5e889 100644
--- a/sound/soc/sunxi/Makefile
+++ b/sound/soc/sunxi/Makefile
@@ -1,2 +1,3 @@
 obj-$(CONFIG_SND_SUN4I_CODEC) += sun4i-codec.o
 
+obj-$(CONFIG_SND_SUN4I_SPDIF) += sun4i-spdif.o
diff --git a/sound/soc/sunxi/sun4i-spdif.c b/sound/soc/sunxi/sun4i-spdif.c
new file mode 100644
index 000..baa2696
--- /dev/null
+++ b/sound/soc/sunxi/sun4i-spdif.c
@@ -0,0 +1,542 @@
+/*
+ * ALSA SoC SPDIF Audio Layer
+ *
+ * Copyright 2015 Andrea Venturi 
+ * Copyright 2015 Marcus Cooper 
+ *
+ * Based on the Allwinner SDK driver, released under the GPL.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+
+#defineSUN4I_SPDIF_CTL (0x00)
+   #define SUN4I_SPDIF_CTL_MCLKDIV(v)  ((v) << 4) /* v even */
+   #define SUN4I_SPDIF_CTL_MCLKOUTEN   BIT(2)
+   #define SUN4I_SPDIF_CTL_GEN BIT(1)
+   #define SUN4I_SPDIF_CTL_RESET   BIT(0)
+
+#define SUN4I_SPDIF_TXCFG  (0x04)
+   #define SUN4I_SPDIF_TXCFG_SINGLEMOD BIT(31)
+   #define SUN4I_SPDIF_TXCFG_ASS   BIT(17)
+   #define SUN4I_SPDIF_TXCFG_NONAUDIO  BIT(16)
+   #define SUN4I_SPDIF_TXCFG_TXRATIO(v)((v) << 4)
+   #define SUN4I_SPDIF_TXCFG_TXRATIO_MASK  GENMASK(8, 4)
+   #define SUN4I_SPDIF_TXCFG_FMTRVDGENMASK(3, 2)
+   #define SUN4I_SPDIF_TXCFG_FMT16BIT  (0 << 2)
+   #define SUN4I_SPDIF_TXCFG_FMT20BIT  (1 << 2)
+   #define SUN4I_SPDIF_TXCFG_FMT24BIT  (2 << 2)
+   #define SUN4I_SPDIF_TXCFG_CHSTMODE  BIT(1)
+   #define SUN4I_SPDIF_TXCFG_TXEN  BIT(0)
+
+#define SUN4I_SPDIF_RXCFG  (0x08)
+   #define SUN4I_SPDIF_RXCFG_LOCKFLAG  BIT(4)
+   #define SUN4I_SPDIF_RXCFG_CHSTSRC   BIT(3)
+   #define SUN4I_SPDIF_RXCFG_CHSTCPBIT(1)
+   #define SUN4I_SPDIF_RXCFG_RXEN  BIT(0)
+
+#define SUN4I_SPDIF_TXFIFO (0x0C)
+
+#define SUN4I_SPDIF_RXFIFO (0x10)
+
+#define SUN4I_SPDIF_FCTL   (0x14)
+   #define SUN4I_SPDIF_FCTL_FIFOSRCBIT(31)
+   #define SUN4I_SPDIF_FCTL_FTXBIT(17)
+   #define SUN4I_SPDIF_FCTL_FRXBIT(16)
+   #define SUN4I_SPDIF_FCTL_TXTL(v)((v) << 8)
+   #define SUN4I_SPDIF_FCTL_TXTL_MASK  GENMASK(12, 8)
+   #define SUN4I_SPDIF_FCTL_RXTL(v)((v) << 3)
+   #define SUN4I_SPDIF_FCTL_RXTL_MASK  GENMASK(7, 3)
+   #define SUN4I_SPDIF_FCTL_TXIM   BIT(2)
+   #define SUN4I_SPDIF_FCTL_RXOM(v)((v) << 0)
+   #define SUN4I_SPDIF_FCTL_RXOM_MASK  GENMASK(1, 0)
+
+#define SUN4I_SPDIF_FSTA   (0x18)
+   #define SUN4I_SPDIF_FSTA_TXEBIT(14)
+   #define SUN4I_SPDIF_FSTA_TXECNTSHT  (8)
+   #define SUN4I_SPDIF_FSTA_RXABIT(6)
+   #define SUN4I_SPDIF_FSTA_RXACNTSHT  (0)
+
+#define SUN4I_SPDIF_INT(0x1C)
+

[PATCH v7 1/2] ASoC: sunxi :add sun4i SPDIF dt bindings

2016-02-21 Thread codekipper
From: Marcus Cooper 

Add devicetree bindings for the SPDIF transceiver found on
found on Allwinners A10 and A20 SoCs.

Signed-off-by: Marcus Cooper 
---
 .../bindings/sound/sunxi,sun4i-spdif.txt   | 39 ++
 1 file changed, 39 insertions(+)
 create mode 100644 
Documentation/devicetree/bindings/sound/sunxi,sun4i-spdif.txt

diff --git a/Documentation/devicetree/bindings/sound/sunxi,sun4i-spdif.txt 
b/Documentation/devicetree/bindings/sound/sunxi,sun4i-spdif.txt
new file mode 100644
index 000..13503aa
--- /dev/null
+++ b/Documentation/devicetree/bindings/sound/sunxi,sun4i-spdif.txt
@@ -0,0 +1,39 @@
+Allwinner Sony/Philips Digital Interface Format (S/PDIF) Controller
+
+The Allwinner S/PDIF audio block is a transceiver that allows the
+processor to receive and transmit digital audio via an coaxial cable or
+a fibre cable.
+For now only playback is supported.
+
+Required properties:
+
+  - compatible : should be one of the following:
+- "allwinner,sun4i-a10-spdif": for the Allwinner A10 SoC
+
+  - reg: Offset and length of the register set for the 
device.
+
+  - interrupts : Contains the 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:
+   "apb" clock for the spdif bus.
+   "spdif"   clock for spdif controller.
+
+Example:
+
+spdif: spdif@01c21000 {
+   compatible = "allwinner,sun4i-a10-spdif";
+   reg = <0x01c21000 0x40>;
+   interrupts = <13>;
+   clocks = <_gates 1>, <_clk>;
+   clock-names = "apb", "spdif";
+   dmas = < 0 2>, < 0 2>;
+   dma-names = "rx", "tx";
+   status = "okay";
+};
-- 
2.7.1



[PATCH v7 0/2] ASoC: Add SPDIF support for Allwinner SoCs

2016-02-21 Thread codekipper
From: Marcus Cooper <codekip...@gmail.com>

For now just the SPDIF transmitter has been tested on a Mele A2000(A10)
and a Itead Ibox(A20).

In order for this patch set to be functional we require an audio clock patch
which will be delivered separately. For those that are interested I've pushed
the patches here with all the required changes to get SPDIF audio out of the
device.

https://github.com/codekipper/linux-sunxi/commits/spdif_delivery

Thanks in advance,
CK

---
Changes since v6:
- removed legacy dapm components that are no longer needed.
- changed dt-bindings patch subject styling to match that of the sound subsystem

Changes since v5:
- fixed warning that had sneaked in.

Changes since v4:
- corrected indentation issues
- removed old macros
- removed unnecessary enabling of apb clock

Changes since v3:
- removed code required for spdif capture
- added disable/enable of apb clk to suspend/resume.
- removed unnecessary dt checks in probe
- fixed error conditions in probe/resume
- modified pm_runtime functionality and confirmed that driver worked when PM 
was disabled.
- removed .owner from platform driver
- renamed bindings file

Changes since v2:
- removed sunxi-machine-spdif and replaced with simple audio card
- removed untested compatibilities from device tree documentation
- added pm_runtime and remove shutdown
- removed pll2 as it's the parent of the spdif clock
- rename clk to spdif_clk
- removed enabling of mclk output
- removed interrupts status being cleared as it's not being used
- use default fifo settings for now
- fixed alignments for wrapped lines

Changes since v1:
- Moved sunxi-machine-spdif.c to separate patch
- replaced sunxi in naming scheme with sun4i in the sun4i-spdif driver.
- split tx controller into separate enable/disable functions
- moved setclk and setfmt functionality into hw params
- added support for mono signals.
- cleaned up probe clock set up.
- removed all writes to transmit status registers.
- removed of_id
- removed power management code.
- Added support for more rates.

Marcus Cooper (2):
  ASoC: sunxi :add sun4i SPDIF dt bindings
  ASoC: sunxi: Add support for the SPDIF block

 .../bindings/sound/sunxi,sun4i-spdif.txt   |  39 ++
 sound/soc/sunxi/Kconfig|   8 +
 sound/soc/sunxi/Makefile   |   1 +
 sound/soc/sunxi/sun4i-spdif.c  | 542 +
 4 files changed, 590 insertions(+)
 create mode 100644 
Documentation/devicetree/bindings/sound/sunxi,sun4i-spdif.txt
 create mode 100644 sound/soc/sunxi/sun4i-spdif.c

-- 
2.7.1



[PATCH v2 1/2] ASoC: sunxi: Add bindings for sun6i to SPDIF

2016-07-30 Thread codekipper
From: Marcus Cooper 

The A31 SoC uses the same SPDIF block as found in earlier SoCs, but its
reset is controlled via a separate reset controller.

Signed-off-by: Marcus Cooper 
---
 Documentation/devicetree/bindings/sound/sunxi,sun4i-spdif.txt | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/Documentation/devicetree/bindings/sound/sunxi,sun4i-spdif.txt 
b/Documentation/devicetree/bindings/sound/sunxi,sun4i-spdif.txt
index 13503aa..0230c4d 100644
--- a/Documentation/devicetree/bindings/sound/sunxi,sun4i-spdif.txt
+++ b/Documentation/devicetree/bindings/sound/sunxi,sun4i-spdif.txt
@@ -9,6 +9,7 @@ Required properties:
 
   - compatible : should be one of the following:
 - "allwinner,sun4i-a10-spdif": for the Allwinner A10 SoC
+- "allwinner,sun6i-a31-spdif": for the Allwinner A31 SoC
 
   - reg: Offset and length of the register set for the 
device.
 
@@ -25,6 +26,8 @@ Required properties:
"apb" clock for the spdif bus.
"spdif"   clock for spdif controller.
 
+  - resets : reset specifier for the ahb reset (A31 and newer only)
+
 Example:
 
 spdif: spdif@01c21000 {
-- 
2.9.2



[PATCH v2 2/2] ASoC: sunxi: compatibility for sun6i to SPDIF

2016-07-30 Thread codekipper
From: Marcus Cooper 

The A31 SoC uses the same SPDIF block as found in earlier SoCs, but its
reset is controlled via a separate reset controller.

The DMA also complains when the maxburst is set to 4 so it's been adjusted
to 8 which suites both the older and newer SoCs.

Signed-off-by: Marcus Cooper 
---
 sound/soc/sunxi/sun4i-spdif.c | 17 -
 1 file changed, 16 insertions(+), 1 deletion(-)

diff --git a/sound/soc/sunxi/sun4i-spdif.c b/sound/soc/sunxi/sun4i-spdif.c
index 0b04fb0..88fbb3a 100644
--- a/sound/soc/sunxi/sun4i-spdif.c
+++ b/sound/soc/sunxi/sun4i-spdif.c
@@ -29,6 +29,7 @@
 #include 
 #include 
 #include 
+#include 
 #include 
 #include 
 #include 
@@ -162,6 +163,7 @@ struct sun4i_spdif_dev {
struct platform_device *pdev;
struct clk *spdif_clk;
struct clk *apb_clk;
+   struct reset_control *rst;
struct snd_soc_dai_driver cpu_dai_drv;
struct regmap *regmap;
struct snd_dmaengine_dai_dma_data dma_params_tx;
@@ -411,6 +413,7 @@ static const struct snd_soc_dapm_route dit_routes[] = {
 
 static const struct of_device_id sun4i_spdif_of_match[] = {
{ .compatible = "allwinner,sun4i-a10-spdif", },
+   { .compatible = "allwinner,sun6i-a31-spdif", },
{ /* sentinel */ }
 };
 MODULE_DEVICE_TABLE(of, sun4i_spdif_of_match);
@@ -482,11 +485,23 @@ static int sun4i_spdif_probe(struct platform_device *pdev)
}
 
host->dma_params_tx.addr = res->start + SUN4I_SPDIF_TXFIFO;
-   host->dma_params_tx.maxburst = 4;
+   host->dma_params_tx.maxburst = 8;
host->dma_params_tx.addr_width = DMA_SLAVE_BUSWIDTH_2_BYTES;
 
platform_set_drvdata(pdev, host);
 
+   if (of_device_is_compatible(pdev->dev.of_node,
+   "allwinner,sun6i-a31-spdif")) {
+   host->rst = devm_reset_control_get_optional(>dev, NULL);
+   if (IS_ERR(host->rst) && PTR_ERR(host->rst) == -EPROBE_DEFER) {
+   ret = -EPROBE_DEFER;
+   dev_err(>dev, "Failed to get reset: %d\n", ret);
+   goto err_disable_apb_clk;
+   }
+   if (!IS_ERR(host->rst))
+   reset_control_deassert(host->rst);
+   }
+
ret = devm_snd_soc_register_component(>dev,
_spdif_component, _spdif_dai, 1);
if (ret)
-- 
2.9.2



[PATCH v2 0/2] ASoC: Extended SPDIF support to Allwinner A31 SoCs

2016-07-30 Thread codekipper
From: Marcus Cooper <codekip...@gmail.com>

This patch set extends the current support of the Allwinner SPDIF
transceiver to include the A31 SoC.

For now just the SPDIF transmitter has been tested on the Mele I7.

In order for this patch set to be functional then we require changes
to the clocks and the device tree. For those that are interested I've
pushed all the required patches here

https://github.com/codekipper/linux-sunxi/commits/a31-spdif

Thanks in advance,
CK

---
Changes since v1:
 - Corrected mistake in bindings documentation

Marcus Cooper (2):
  ASoC: sunxi: Add bindings for sun6i to SPDIF
  ASoC: sunxi: compatibility for sun6i to SPDIF

 .../devicetree/bindings/sound/sunxi,sun4i-spdif.txt |  3 +++
 sound/soc/sunxi/sun4i-spdif.c   | 17 -
 2 files changed, 19 insertions(+), 1 deletion(-)

-- 
2.9.2



[PATCH 2/2] ASoC: sunxi: compatibility for sun6i to SPDIF

2016-07-30 Thread codekipper
From: Marcus Cooper 

The A31 SoC uses the same SPDIF block as found in earlier SoCs, but its
reset is controlled via a separate reset controller.

The DMA also complains when the maxburst is set to 4 so it's been adjusted
to 8 which suites both the older and newer SoCs.

Signed-off-by: Marcus Cooper 
---
 sound/soc/sunxi/sun4i-spdif.c | 17 -
 1 file changed, 16 insertions(+), 1 deletion(-)

diff --git a/sound/soc/sunxi/sun4i-spdif.c b/sound/soc/sunxi/sun4i-spdif.c
index 0b04fb0..88fbb3a 100644
--- a/sound/soc/sunxi/sun4i-spdif.c
+++ b/sound/soc/sunxi/sun4i-spdif.c
@@ -29,6 +29,7 @@
 #include 
 #include 
 #include 
+#include 
 #include 
 #include 
 #include 
@@ -162,6 +163,7 @@ struct sun4i_spdif_dev {
struct platform_device *pdev;
struct clk *spdif_clk;
struct clk *apb_clk;
+   struct reset_control *rst;
struct snd_soc_dai_driver cpu_dai_drv;
struct regmap *regmap;
struct snd_dmaengine_dai_dma_data dma_params_tx;
@@ -411,6 +413,7 @@ static const struct snd_soc_dapm_route dit_routes[] = {
 
 static const struct of_device_id sun4i_spdif_of_match[] = {
{ .compatible = "allwinner,sun4i-a10-spdif", },
+   { .compatible = "allwinner,sun6i-a31-spdif", },
{ /* sentinel */ }
 };
 MODULE_DEVICE_TABLE(of, sun4i_spdif_of_match);
@@ -482,11 +485,23 @@ static int sun4i_spdif_probe(struct platform_device *pdev)
}
 
host->dma_params_tx.addr = res->start + SUN4I_SPDIF_TXFIFO;
-   host->dma_params_tx.maxburst = 4;
+   host->dma_params_tx.maxburst = 8;
host->dma_params_tx.addr_width = DMA_SLAVE_BUSWIDTH_2_BYTES;
 
platform_set_drvdata(pdev, host);
 
+   if (of_device_is_compatible(pdev->dev.of_node,
+   "allwinner,sun6i-a31-spdif")) {
+   host->rst = devm_reset_control_get_optional(>dev, NULL);
+   if (IS_ERR(host->rst) && PTR_ERR(host->rst) == -EPROBE_DEFER) {
+   ret = -EPROBE_DEFER;
+   dev_err(>dev, "Failed to get reset: %d\n", ret);
+   goto err_disable_apb_clk;
+   }
+   if (!IS_ERR(host->rst))
+   reset_control_deassert(host->rst);
+   }
+
ret = devm_snd_soc_register_component(>dev,
_spdif_component, _spdif_dai, 1);
if (ret)
-- 
2.9.2



[PATCH 0/2] ASoC: Extended SPDIF support to Allwinner A31 SoCs

2016-07-30 Thread codekipper
From: Marcus Cooper <codekip...@gmail.com>

This patch set extends the current support of the Allwinner SPDIF
transceiver to include the A31 SoC.

For now just the SPDIF transmitter has been tested on the Mele I7.

In order for this patch set to be functional then we require changes
to the clocks and the device tree. For those that are interested I've
pushed all the required patches here

https://github.com/codekipper/linux-sunxi/commits/a31-spdif

Thanks in advance,
CK

Marcus Cooper (2):
  ASoC: sunxi: Add bindings for sun6i to SPDIF
  ASoC: sunxi: compatibility for sun6i to SPDIF

 .../devicetree/bindings/sound/sunxi,sun4i-spdif.txt |  3 +++
 sound/soc/sunxi/sun4i-spdif.c   | 17 -
 2 files changed, 19 insertions(+), 1 deletion(-)

-- 
2.9.2



[PATCH 1/2] ASoC: sunxi: Add bindings for sun6i to SPDIF

2016-07-30 Thread codekipper
From: Marcus Cooper 

The A31 SoC uses the same SPDIF block as found in earlier SoCs, but its
reset is controlled via a separate reset controller.

Signed-off-by: Marcus Cooper 
---
 Documentation/devicetree/bindings/sound/sunxi,sun4i-spdif.txt | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/Documentation/devicetree/bindings/sound/sunxi,sun4i-spdif.txt 
b/Documentation/devicetree/bindings/sound/sunxi,sun4i-spdif.txt
index 13503aa..4fe80f7 100644
--- a/Documentation/devicetree/bindings/sound/sunxi,sun4i-spdif.txt
+++ b/Documentation/devicetree/bindings/sound/sunxi,sun4i-spdif.txt
@@ -9,6 +9,7 @@ Required properties:
 
   - compatible : should be one of the following:
 - "allwinner,sun4i-a10-spdif": for the Allwinner A10 SoC
+- "allwinner,sun6i-a31-spdif": for the Allwinner A31 SoC
 
   - reg: Offset and length of the register set for the 
device.
 
@@ -25,6 +26,8 @@ Required properties:
"apb" clock for the spdif bus.
"spdif"   clock for spdif controller.
 
+  - reset  : reset specifier for the ahb reset (A31 and newer only)
+
 Example:
 
 spdif: spdif@01c21000 {
-- 
2.9.2



[PATCH v2 1/2] ASoC: sunxi: Add bindings for sun8i to SPDIF

2017-01-19 Thread codekipper
From: Marcus Cooper 

The H3 SoC uses the same SPDIF block as found in earlier SoCs, but the
transmit fifo is at a different address.

Signed-off-by: Marcus Cooper 
---
 Documentation/devicetree/bindings/sound/sunxi,sun4i-spdif.txt | 1 +
 1 file changed, 1 insertion(+)

diff --git a/Documentation/devicetree/bindings/sound/sunxi,sun4i-spdif.txt 
b/Documentation/devicetree/bindings/sound/sunxi,sun4i-spdif.txt
index 0230c4d20506..fe0a65e6d629 100644
--- a/Documentation/devicetree/bindings/sound/sunxi,sun4i-spdif.txt
+++ b/Documentation/devicetree/bindings/sound/sunxi,sun4i-spdif.txt
@@ -10,6 +10,7 @@ Required properties:
   - compatible : should be one of the following:
 - "allwinner,sun4i-a10-spdif": for the Allwinner A10 SoC
 - "allwinner,sun6i-a31-spdif": for the Allwinner A31 SoC
+- "allwinner,sun8i-h3-spdif": for the Allwinner H3 SoC
 
   - reg: Offset and length of the register set for the 
device.
 
-- 
2.11.0



[PATCH v2 0/2] ASoC: sun4i-spdif: Add support for the H3 SoC

2017-01-19 Thread codekipper
From: Marcus Cooper 

The H3 SoC uses the same SPDIF block as found in earlier SoCs, but the
transmit fifo is at a different address.

This has been tested on the Beelink X2.
BR,
CK
---
Changes since v1:
 - Now a patch set with bindings and driver changes.
---
Marcus Cooper (2):
  ASoC: sunxi: Add bindings for sun8i to SPDIF
  ASoC: sun4i-spdif: Add support for the H3 SoC

 Documentation/devicetree/bindings/sound/sunxi,sun4i-spdif.txt |  1 +
 sound/soc/sunxi/sun4i-spdif.c | 11 +++
 2 files changed, 12 insertions(+)

-- 
2.11.0



[PATCH v2 2/2] ASoC: sun4i-spdif: Add support for the H3 SoC

2017-01-19 Thread codekipper
From: Marcus Cooper 

The H3 SoC uses the same SPDIF block as found in earlier SoCs, but its
TXFIFO is mapped to another address.

Signed-off-by: Marcus Cooper 
---
 sound/soc/sunxi/sun4i-spdif.c | 11 +++
 1 file changed, 11 insertions(+)

diff --git a/sound/soc/sunxi/sun4i-spdif.c b/sound/soc/sunxi/sun4i-spdif.c
index fec62ee1fc72..c03cd07a9b19 100644
--- a/sound/soc/sunxi/sun4i-spdif.c
+++ b/sound/soc/sunxi/sun4i-spdif.c
@@ -103,6 +103,8 @@
#define SUN4I_SPDIF_ISTA_RXOSTA BIT(1)
#define SUN4I_SPDIF_ISTA_RXASTA BIT(0)
 
+#define SUN8I_SPDIF_TXFIFO (0x20)
+
 #define SUN4I_SPDIF_TXCNT  (0x24)
 
 #define SUN4I_SPDIF_RXCNT  (0x28)
@@ -417,6 +419,11 @@ static const struct sun4i_spdif_quirks 
sun6i_a31_spdif_quirks = {
.has_reset  = true,
 };
 
+static const struct sun4i_spdif_quirks sun8i_h3_spdif_quirks = {
+   .reg_dac_txdata = SUN8I_SPDIF_TXFIFO,
+   .has_reset  = true,
+};
+
 static const struct of_device_id sun4i_spdif_of_match[] = {
{
.compatible = "allwinner,sun4i-a10-spdif",
@@ -426,6 +433,10 @@ static const struct of_device_id sun4i_spdif_of_match[] = {
.compatible = "allwinner,sun6i-a31-spdif",
.data = _a31_spdif_quirks,
},
+   {
+   .compatible = "allwinner,sun8i-h3-spdif",
+   .data = _h3_spdif_quirks,
+   },
{ /* sentinel */ }
 };
 MODULE_DEVICE_TABLE(of, sun4i_spdif_of_match);
-- 
2.11.0



[PATCH] ASoC: sun4i-spdif: Add support for the H3 SoC

2017-01-12 Thread codekipper
From: Marcus Cooper 

The H3 SoC uses the same SPDIF block as found in earlier SoCs, but its
TXFIFO is mapped to another address.

Signed-off-by: Marcus Cooper 
---
 sound/soc/sunxi/sun4i-spdif.c | 11 +++
 1 file changed, 11 insertions(+)

diff --git a/sound/soc/sunxi/sun4i-spdif.c b/sound/soc/sunxi/sun4i-spdif.c
index fec62ee1fc72..c03cd07a9b19 100644
--- a/sound/soc/sunxi/sun4i-spdif.c
+++ b/sound/soc/sunxi/sun4i-spdif.c
@@ -103,6 +103,8 @@
#define SUN4I_SPDIF_ISTA_RXOSTA BIT(1)
#define SUN4I_SPDIF_ISTA_RXASTA BIT(0)
 
+#define SUN8I_SPDIF_TXFIFO (0x20)
+
 #define SUN4I_SPDIF_TXCNT  (0x24)
 
 #define SUN4I_SPDIF_RXCNT  (0x28)
@@ -417,6 +419,11 @@ static const struct sun4i_spdif_quirks 
sun6i_a31_spdif_quirks = {
.has_reset  = true,
 };
 
+static const struct sun4i_spdif_quirks sun8i_h3_spdif_quirks = {
+   .reg_dac_txdata = SUN8I_SPDIF_TXFIFO,
+   .has_reset  = true,
+};
+
 static const struct of_device_id sun4i_spdif_of_match[] = {
{
.compatible = "allwinner,sun4i-a10-spdif",
@@ -426,6 +433,10 @@ static const struct of_device_id sun4i_spdif_of_match[] = {
.compatible = "allwinner,sun6i-a31-spdif",
.data = _a31_spdif_quirks,
},
+   {
+   .compatible = "allwinner,sun8i-h3-spdif",
+   .data = _h3_spdif_quirks,
+   },
{ /* sentinel */ }
 };
 MODULE_DEVICE_TABLE(of, sun4i_spdif_of_match);
-- 
2.11.0



[PATCH] ASoC: sunxi: Add bindings for sun8i to SPDIF

2017-01-12 Thread codekipper
From: Marcus Cooper 

The H3 SoC uses the same SPDIF block as found in earlier SoCs, but the
transmit fifo is at a different address.

Signed-off-by: Marcus Cooper 
---
 Documentation/devicetree/bindings/sound/sunxi,sun4i-spdif.txt | 1 +
 1 file changed, 1 insertion(+)

diff --git a/Documentation/devicetree/bindings/sound/sunxi,sun4i-spdif.txt 
b/Documentation/devicetree/bindings/sound/sunxi,sun4i-spdif.txt
index 0230c4d20506..fe0a65e6d629 100644
--- a/Documentation/devicetree/bindings/sound/sunxi,sun4i-spdif.txt
+++ b/Documentation/devicetree/bindings/sound/sunxi,sun4i-spdif.txt
@@ -10,6 +10,7 @@ Required properties:
   - compatible : should be one of the following:
 - "allwinner,sun4i-a10-spdif": for the Allwinner A10 SoC
 - "allwinner,sun6i-a31-spdif": for the Allwinner A31 SoC
+- "allwinner,sun8i-h3-spdif": for the Allwinner H3 SoC
 
   - reg: Offset and length of the register set for the 
device.
 
-- 
2.11.0



[PATCH 1/2] ASoC: sun4i-spdif: remove legacy dapm components

2016-12-20 Thread codekipper
From: Marcus Cooper 

The dapm components are now handled by the ALSA SoC SPDIF DIT driver
so can be removed.

Signed-off-by: Marcus Cooper 
---
 sound/soc/sunxi/sun4i-spdif.c | 8 
 1 file changed, 8 deletions(-)

diff --git a/sound/soc/sunxi/sun4i-spdif.c b/sound/soc/sunxi/sun4i-spdif.c
index 88fbb3a1e660..048de15d6937 100644
--- a/sound/soc/sunxi/sun4i-spdif.c
+++ b/sound/soc/sunxi/sun4i-spdif.c
@@ -403,14 +403,6 @@ static struct snd_soc_dai_driver sun4i_spdif_dai = {
.name = "spdif",
 };
 
-static const struct snd_soc_dapm_widget dit_widgets[] = {
-   SND_SOC_DAPM_OUTPUT("spdif-out"),
-};
-
-static const struct snd_soc_dapm_route dit_routes[] = {
-   { "spdif-out", NULL, "Playback" },
-};
-
 static const struct of_device_id sun4i_spdif_of_match[] = {
{ .compatible = "allwinner,sun4i-a10-spdif", },
{ .compatible = "allwinner,sun6i-a31-spdif", },
-- 
2.11.0



[PATCH 2/2] ASoC: sun4i-spdif: Add quirks to the spdif driver

2016-12-20 Thread codekipper
From: Marcus Cooper 

It has been seen that some newer SoCs have a different TX FIFO
address and we already have the difference with the A31 requiring
a reset. Add a quirks structure so that these can be managed
easily.

Signed-off-by: Marcus Cooper 
---
 sound/soc/sunxi/sun4i-spdif.c | 36 +++-
 1 file changed, 31 insertions(+), 5 deletions(-)

diff --git a/sound/soc/sunxi/sun4i-spdif.c b/sound/soc/sunxi/sun4i-spdif.c
index 048de15d6937..fec62ee1fc72 100644
--- a/sound/soc/sunxi/sun4i-spdif.c
+++ b/sound/soc/sunxi/sun4i-spdif.c
@@ -403,9 +403,29 @@ static struct snd_soc_dai_driver sun4i_spdif_dai = {
.name = "spdif",
 };
 
+struct sun4i_spdif_quirks {
+   unsigned int reg_dac_txdata;/* TX FIFO offset for DMA config */
+   bool has_reset;
+};
+
+static const struct sun4i_spdif_quirks sun4i_a10_spdif_quirks = {
+   .reg_dac_txdata = SUN4I_SPDIF_TXFIFO,
+};
+
+static const struct sun4i_spdif_quirks sun6i_a31_spdif_quirks = {
+   .reg_dac_txdata = SUN4I_SPDIF_TXFIFO,
+   .has_reset  = true,
+};
+
 static const struct of_device_id sun4i_spdif_of_match[] = {
-   { .compatible = "allwinner,sun4i-a10-spdif", },
-   { .compatible = "allwinner,sun6i-a31-spdif", },
+   {
+   .compatible = "allwinner,sun4i-a10-spdif",
+   .data = _a10_spdif_quirks,
+   },
+   {
+   .compatible = "allwinner,sun6i-a31-spdif",
+   .data = _a31_spdif_quirks,
+   },
{ /* sentinel */ }
 };
 MODULE_DEVICE_TABLE(of, sun4i_spdif_of_match);
@@ -438,6 +458,7 @@ static int sun4i_spdif_probe(struct platform_device *pdev)
 {
struct sun4i_spdif_dev *host;
struct resource *res;
+   const struct sun4i_spdif_quirks *quirks;
int ret;
void __iomem *base;
 
@@ -459,6 +480,12 @@ static int sun4i_spdif_probe(struct platform_device *pdev)
if (IS_ERR(base))
return PTR_ERR(base);
 
+   quirks = of_device_get_match_data(>dev);
+   if (quirks == NULL) {
+   dev_err(>dev, "Failed to determine the quirks to use\n");
+   return -ENODEV;
+   }
+
host->regmap = devm_regmap_init_mmio(>dev, base,
_spdif_regmap_config);
 
@@ -476,14 +503,13 @@ static int sun4i_spdif_probe(struct platform_device *pdev)
goto err_disable_apb_clk;
}
 
-   host->dma_params_tx.addr = res->start + SUN4I_SPDIF_TXFIFO;
+   host->dma_params_tx.addr = res->start + quirks->reg_dac_txdata;
host->dma_params_tx.maxburst = 8;
host->dma_params_tx.addr_width = DMA_SLAVE_BUSWIDTH_2_BYTES;
 
platform_set_drvdata(pdev, host);
 
-   if (of_device_is_compatible(pdev->dev.of_node,
-   "allwinner,sun6i-a31-spdif")) {
+   if (quirks->has_reset) {
host->rst = devm_reset_control_get_optional(>dev, NULL);
if (IS_ERR(host->rst) && PTR_ERR(host->rst) == -EPROBE_DEFER) {
ret = -EPROBE_DEFER;
-- 
2.11.0



[PATCH 0/2] ASoC: sun4i-spdif: Changes in preparation of supporting new SoCs

2016-12-20 Thread codekipper
From: Marcus Cooper 

Hi All,
please find attached two patches. First being a cleanup of something that
shouldn't be in the code and the second adds the mechanism for supporting
newer Allwiner SoCs. There was a third patch in the series and that was
bringing in support of SPDIF on the Allwinner H3 but I've not been able to
test it so that I hear audio. As soon as I get some hardware with a SPDIF
connection I will confirm and push.
BR,
CK 

Marcus Cooper (2):
  ASoC: sun4i-spdif: remove legacy dapm components
  ASoC: sun4i-spdif: Add quirks to the spdif driver

 sound/soc/sunxi/sun4i-spdif.c | 36 +++-
 1 file changed, 27 insertions(+), 9 deletions(-)

-- 
2.11.0



[PATCH] ASoC: sun4i-i2s: Add quirks for newer SoCs

2016-12-20 Thread codekipper
From: Marcus Cooper 

Newer SoCs have additional functionality so a quirks structure
has been added to handle them. So far we've seen the use of a
reset controller, a different address for the TXFIFO and varying
register changes.

This patch prepares the driver for these changes and adds the
reset specifier.

Signed-off-by: Marcus Cooper 
---
 .../devicetree/bindings/sound/sun4i-i2s.txt|  2 +
 sound/soc/sunxi/sun4i-i2s.c| 47 --
 2 files changed, 45 insertions(+), 4 deletions(-)

diff --git a/Documentation/devicetree/bindings/sound/sun4i-i2s.txt 
b/Documentation/devicetree/bindings/sound/sun4i-i2s.txt
index 7a2c0945fd22..494a881ccd21 100644
--- a/Documentation/devicetree/bindings/sound/sun4i-i2s.txt
+++ b/Documentation/devicetree/bindings/sound/sun4i-i2s.txt
@@ -18,6 +18,8 @@ Required properties:
- "apb" : clock for the I2S bus interface
- "mod" : module clock for the I2S controller
 - #sound-dai-cells : Must be equal to 0
+- resets: reset specifier for the ahb reset (A31 and newer only)
+
 
 Example:
 
diff --git a/sound/soc/sunxi/sun4i-i2s.c b/sound/soc/sunxi/sun4i-i2s.c
index f24d19526603..80fe4f1d6e3b 100644
--- a/sound/soc/sunxi/sun4i-i2s.c
+++ b/sound/soc/sunxi/sun4i-i2s.c
@@ -14,9 +14,11 @@
 #include 
 #include 
 #include 
+#include 
 #include 
 #include 
 #include 
+#include 
 
 #include 
 #include 
@@ -92,6 +94,7 @@ struct sun4i_i2s {
struct clk  *bus_clk;
struct clk  *mod_clk;
struct regmap   *regmap;
+   struct reset_control *rst;
 
unsigned intmclk_freq;
 
@@ -104,6 +107,13 @@ struct sun4i_i2s_clk_div {
u8  val;
 };
 
+struct sun4i_i2s_quirks {
+   unsigned intreg_dac_txdata; /* TX FIFO offset for DMA config */
+   boolhas_reset;
+   const struct regmap_config  *sun4i_i2s_regmap;
+   const struct snd_soc_dai_ops*ops;
+};
+
 static const struct sun4i_i2s_clk_div sun4i_i2s_bclk_div[] = {
{ .div = 2, .val = 0 },
{ .div = 4, .val = 1 },
@@ -541,7 +551,6 @@ static struct snd_soc_dai_driver sun4i_i2s_dai = {
.rates = SNDRV_PCM_RATE_8000_192000,
.formats = SNDRV_PCM_FMTBIT_S16_LE,
},
-   .ops = _i2s_dai_ops,
.symmetric_rates = 1,
 };
 
@@ -655,6 +664,7 @@ static int sun4i_i2s_probe(struct platform_device *pdev)
 {
struct sun4i_i2s *i2s;
struct resource *res;
+   const struct sun4i_i2s_quirks *quirks;
void __iomem *regs;
int irq, ret;
 
@@ -680,8 +690,14 @@ static int sun4i_i2s_probe(struct platform_device *pdev)
return PTR_ERR(i2s->bus_clk);
}
 
+   quirks = of_device_get_match_data(>dev);
+   if (quirks == NULL) {
+   dev_err(>dev, "Failed to determine the quirks to use\n");
+   return -ENODEV;
+   }
+
i2s->regmap = devm_regmap_init_mmio(>dev, regs,
-   _i2s_regmap_config);
+   quirks->sun4i_i2s_regmap);
if (IS_ERR(i2s->regmap)) {
dev_err(>dev, "Regmap initialisation failed\n");
return PTR_ERR(i2s->regmap);
@@ -692,13 +708,25 @@ static int sun4i_i2s_probe(struct platform_device *pdev)
dev_err(>dev, "Can't get our mod clock\n");
return PTR_ERR(i2s->mod_clk);
}
+

-   i2s->playback_dma_data.addr = res->start + SUN4I_I2S_FIFO_TX_REG;
+   i2s->playback_dma_data.addr = res->start + quirks->reg_dac_txdata;
i2s->playback_dma_data.maxburst = 4;
 
i2s->capture_dma_data.addr = res->start + SUN4I_I2S_FIFO_RX_REG;
i2s->capture_dma_data.maxburst = 4;
 
+   if (quirks->has_reset) {
+   i2s->rst = devm_reset_control_get_optional(>dev, NULL);
+   if (IS_ERR(i2s->rst) && PTR_ERR(i2s->rst) == -EPROBE_DEFER) {
+   ret = -EPROBE_DEFER;
+   dev_err(>dev, "Failed to get reset: %d\n", ret);
+   goto err_pm_disable;
+   }
+   if (!IS_ERR(i2s->rst))
+   reset_control_deassert(i2s->rst);
+   }
+
pm_runtime_enable(>dev);
if (!pm_runtime_enabled(>dev)) {
ret = sun4i_i2s_runtime_resume(>dev);
@@ -706,6 +734,8 @@ static int sun4i_i2s_probe(struct platform_device *pdev)
goto err_pm_disable;
}
 
+   /* Register ops with dai */
+   sun4i_i2s_dai.ops = quirks->ops;
ret = devm_snd_soc_register_component(>dev,
  _i2s_component,
  _i2s_dai, 1);
@@ -742,8 +772,17 @@ static int sun4i_i2s_remove(struct platform_device *pdev)
return 0;
 }
 
+static const struct sun4i_i2s_quirks sun4i_a10_i2s_quirks = {
+   .reg_dac_txdata = SUN4I_I2S_FIFO_TX_REG,
+   

[PATCH v3 02/12] ASoC: sun4i-i2s: Add clkdiv offsets to quirks

2017-07-29 Thread codekipper
From: Marcus Cooper 

The BCLKDIV and MCLKDIV found on newer SoCs start from an offset of 1.
Add the functionality to adjust the division values according to the
needs to the device being used.

Signed-off-by: Marcus Cooper 
---
 sound/soc/sunxi/sun4i-i2s.c | 8 ++--
 1 file changed, 6 insertions(+), 2 deletions(-)

diff --git a/sound/soc/sunxi/sun4i-i2s.c b/sound/soc/sunxi/sun4i-i2s.c
index d7ee7a443e4e..1d538de4e4d0 100644
--- a/sound/soc/sunxi/sun4i-i2s.c
+++ b/sound/soc/sunxi/sun4i-i2s.c
@@ -94,9 +94,13 @@
  * struct sun4i_i2s_quirks - Differences between SoC variants.
  *
  * @has_reset: SoC needs reset deasserted.
+ * @mclk_offset: Value by which mclkdiv needs to be adjusted.
+ * @bclk_offset: Value by which bclkdiv needs to be adjusted.
  */
 struct sun4i_i2s_quirks {
boolhas_reset;
+   unsigned intmclk_offset;
+   unsigned intbclk_offset;
 };
 
 struct sun4i_i2s {
@@ -149,7 +153,7 @@ static int sun4i_i2s_get_bclk_div(struct sun4i_i2s *i2s,
const struct sun4i_i2s_clk_div *bdiv = _i2s_bclk_div[i];
 
if (bdiv->div == div)
-   return bdiv->val;
+   return bdiv->val + i2s->variant->bclk_offset;
}
 
return -EINVAL;
@@ -167,7 +171,7 @@ static int sun4i_i2s_get_mclk_div(struct sun4i_i2s *i2s,
const struct sun4i_i2s_clk_div *mdiv = _i2s_mclk_div[i];
 
if (mdiv->div == div)
-   return mdiv->val;
+   return mdiv->val + i2s->variant->mclk_offset;
}
 
return -EINVAL;
-- 
2.13.3



[PATCH v3 07/12] ASoC: sun4i-i2s: bclk and lrclk polarity tidyup

2017-07-29 Thread codekipper
From: Marcus Cooper 

On newer SoCs the bit fields for the blck and lrclk polarity are in
a different locations. Use regmap fields to set the polarity bits
as intended.

Signed-off-by: Marcus Cooper 
---
 sound/soc/sunxi/sun4i-i2s.c | 45 -
 1 file changed, 32 insertions(+), 13 deletions(-)

diff --git a/sound/soc/sunxi/sun4i-i2s.c b/sound/soc/sunxi/sun4i-i2s.c
index 171df99a267e..90daa974bd27 100644
--- a/sound/soc/sunxi/sun4i-i2s.c
+++ b/sound/soc/sunxi/sun4i-i2s.c
@@ -50,6 +50,8 @@
 #define SUN4I_I2S_FMT0_FMT_RIGHT_J (2 << 0)
 #define SUN4I_I2S_FMT0_FMT_LEFT_J  (1 << 0)
 #define SUN4I_I2S_FMT0_FMT_I2S (0 << 0)
+#define SUN4I_I2S_FMT0_POLARITY_INVERTED   (1)
+#define SUN4I_I2S_FMT0_POLARITY_NORMAL (0)
 
 #define SUN4I_I2S_FMT1_REG 0x08
 #define SUN4I_I2S_FIFO_TX_REG  0x0c
@@ -101,6 +103,8 @@
  * @fmt_offset: Value by which wss and sr needs to be adjusted.
  * @field_fmt_set_wss: regmap field to set word select size.
  * @field_fmt_set_sr: regmap field to set sample resolution.
+ * @field_fmt_set_bclk_polarity: regmap field to set clk polarity.
+ * @field_fmt_set_lrclk_polarity: regmap field to set frame polarity.
  * @field_txchanmap: location of the tx channel mapping register.
  * @field_rxchanmap: location of the rx channel mapping register.
  * @field_txchansel: location of the tx channel select bit fields.
@@ -117,6 +121,8 @@ struct sun4i_i2s_quirks {
/* Register fields for i2s */
struct reg_fieldfield_fmt_set_wss;
struct reg_fieldfield_fmt_set_sr;
+   struct reg_fieldfield_fmt_set_bclk_polarity;
+   struct reg_fieldfield_fmt_set_lrclk_polarity;
struct reg_fieldfield_txchanmap;
struct reg_fieldfield_rxchanmap;
struct reg_fieldfield_txchansel;
@@ -137,6 +143,8 @@ struct sun4i_i2s {
/* Register fields for i2s */
struct regmap_field *field_fmt_set_wss;
struct regmap_field *field_fmt_set_sr;
+   struct regmap_field *field_fmt_set_bclk_polarity;
+   struct regmap_field *field_fmt_set_lrclk_polarity;
struct regmap_field *field_txchanmap;
struct regmap_field *field_rxchanmap;
struct regmap_field *field_txchansel;
@@ -332,6 +340,8 @@ static int sun4i_i2s_set_fmt(struct snd_soc_dai *dai, 
unsigned int fmt)
 {
struct sun4i_i2s *i2s = snd_soc_dai_get_drvdata(dai);
u32 val;
+   u32 bclk_polarity = SUN4I_I2S_FMT0_POLARITY_NORMAL;
+   u32 lrclk_polarity = SUN4I_I2S_FMT0_POLARITY_NORMAL;
 
/* DAI Mode */
switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
@@ -356,32 +366,25 @@ static int sun4i_i2s_set_fmt(struct snd_soc_dai *dai, 
unsigned int fmt)
switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
case SND_SOC_DAIFMT_IB_IF:
/* Invert both clocks */
-   val = SUN4I_I2S_FMT0_BCLK_POLARITY_INVERTED |
-   SUN4I_I2S_FMT0_LRCLK_POLARITY_INVERTED;
+   bclk_polarity = SUN4I_I2S_FMT0_POLARITY_INVERTED;
+   lrclk_polarity = SUN4I_I2S_FMT0_POLARITY_INVERTED;
break;
case SND_SOC_DAIFMT_IB_NF:
/* Invert bit clock */
-   val = SUN4I_I2S_FMT0_BCLK_POLARITY_INVERTED |
-   SUN4I_I2S_FMT0_LRCLK_POLARITY_NORMAL;
+   bclk_polarity = SUN4I_I2S_FMT0_POLARITY_INVERTED;
break;
case SND_SOC_DAIFMT_NB_IF:
/* Invert frame clock */
-   val = SUN4I_I2S_FMT0_LRCLK_POLARITY_INVERTED |
-   SUN4I_I2S_FMT0_BCLK_POLARITY_NORMAL;
+   lrclk_polarity = SUN4I_I2S_FMT0_POLARITY_INVERTED;
break;
case SND_SOC_DAIFMT_NB_NF:
-   /* Nothing to do for both normal cases */
-   val = SUN4I_I2S_FMT0_BCLK_POLARITY_NORMAL |
-   SUN4I_I2S_FMT0_LRCLK_POLARITY_NORMAL;
break;
default:
return -EINVAL;
}
 
-   regmap_update_bits(i2s->regmap, SUN4I_I2S_FMT0_REG,
-  SUN4I_I2S_FMT0_BCLK_POLARITY_MASK |
-  SUN4I_I2S_FMT0_LRCLK_POLARITY_MASK,
-  val);
+   regmap_field_write(i2s->field_fmt_set_bclk_polarity, bclk_polarity);
+   regmap_field_write(i2s->field_fmt_set_lrclk_polarity, lrclk_polarity);
 
/* DAI clock master masks */
switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
@@ -709,6 +712,8 @@ static const struct sun4i_i2s_quirks sun4i_a10_i2s_quirks = 
{
.sun4i_i2s_regmap   = _i2s_regmap_config,
.field_fmt_set_wss  = REG_FIELD(SUN4I_I2S_FMT0_REG, 2, 3),
.field_fmt_set_sr   = REG_FIELD(SUN4I_I2S_FMT0_REG, 4, 5),
+  

[PATCH v3 12/12] ASoC: sun4i-i2s: Add support for H3

2017-07-29 Thread codekipper
From: Marcus Cooper 

The sun8i-h3 introduces a lot of changes to the i2s block such
as different register locations, extended clock division and
more operational modes. As we have to consider the earlier
implementation then these changes need to be isolated.

Signed-off-by: Marcus Cooper 
---
 .../devicetree/bindings/sound/sun4i-i2s.txt|   2 +
 sound/soc/sunxi/sun4i-i2s.c| 173 +
 2 files changed, 175 insertions(+)

diff --git a/Documentation/devicetree/bindings/sound/sun4i-i2s.txt 
b/Documentation/devicetree/bindings/sound/sun4i-i2s.txt
index ee21da865771..fc5da6080759 100644
--- a/Documentation/devicetree/bindings/sound/sun4i-i2s.txt
+++ b/Documentation/devicetree/bindings/sound/sun4i-i2s.txt
@@ -8,6 +8,7 @@ Required properties:
 - compatible: should be one of the following:
- "allwinner,sun4i-a10-i2s"
- "allwinner,sun6i-a31-i2s"
+   - "allwinner,sun8i-h3-i2s"
 - reg: physical base address of the controller and length of memory mapped
   region.
 - interrupts: should contain the I2S interrupt.
@@ -22,6 +23,7 @@ Required properties:
 
 Required properties for the following compatibles:
- "allwinner,sun6i-a31-i2s"
+   - "allwinner,sun8i-h3-i2s"
 - resets: phandle to the reset line for this codec
 
 Example:
diff --git a/sound/soc/sunxi/sun4i-i2s.c b/sound/soc/sunxi/sun4i-i2s.c
index d8bcd3d9c2b6..87dfb5017c25 100644
--- a/sound/soc/sunxi/sun4i-i2s.c
+++ b/sound/soc/sunxi/sun4i-i2s.c
@@ -92,11 +92,43 @@
 #define SUN4I_I2S_RX_CHAN_SEL_REG  0x38
 #define SUN4I_I2S_RX_CHAN_MAP_REG  0x3c
 
+/* Defines required for sun8i-h3 support */
+#define SUN8I_I2S_CTRL_BCLK_OUTBIT(18)
+#define SUN8I_I2S_CTRL_LRCK_OUTBIT(17)
+
+#define SUN8I_I2S_FMT0_LRCK_PERIOD_MASKGENMASK(17, 8)
+#define SUN8I_I2S_FMT0_LRCK_PERIOD(period) (period << 8)
+
+#define SUN8I_I2S_INT_STA_REG  0x0c
+#define SUN8I_I2S_FIFO_TX_REG  0x20
+
+#define SUN8I_I2S_CLK_DIV_MCLK_EN  8
+
+#define SUN8I_I2S_CHAN_CFG_REG 0x30
+#define SUN8I_I2S_CHAN_CFG_RX_SLOT_NUM_MASKGENMASK(6, 4)
+#define SUN8I_I2S_CHAN_CFG_RX_SLOT_NUM(chan)   (chan - 1)
+#define SUN8I_I2S_CHAN_CFG_TX_SLOT_NUM_MASKGENMASK(2, 0)
+#define SUN8I_I2S_CHAN_CFG_TX_SLOT_NUM(chan)   (chan - 1)
+
+#define SUN8I_I2S_TX_CHAN_MAP_REG  0x44
+#define SUN8I_I2S_TX_CHAN_SEL_REG  0x34
+#define SUN8I_I2S_TX_CHAN_OFFSET_MASK  GENMASK(13,11)
+#define SUN8I_I2S_TX_CHAN_OFFSET(offset)   (offset << 12)
+#define SUN8I_I2S_TX_CHAN_EN_MASK  GENMASK(11, 4)
+#define SUN8I_I2S_TX_CHAN_EN(num_chan) (((1 << num_chan) - 1) << 4)
+
+#define SUN8I_I2S_RX_CHAN_SEL_REG  0x54
+#define SUN8I_I2S_RX_CHAN_MAP_REG  0x58
+
 /**
  * struct sun4i_i2s_quirks - Differences between SoC variants.
  *
  * @has_reset: SoC needs reset deasserted.
  * @has_slave_select_bit: SoC has a bit to enable slave mode.
+ * @has_fmt_set_lrck_period: SoC requires lrclk period to be set.
+ * @has_chcfg: tx and rx slot number need to be set.
+ * @has_chsel_tx_chen: requires lrclk period to be set.
+ * @has_chsel_offset: requires lrclk period to be set.
  * @reg_offset_txdata: offset of the tx fifo.
  * @sun4i_i2s_regmap: regmap config to use.
  * @mclk_offset: Value by which mclkdiv needs to be adjusted.
@@ -116,6 +148,10 @@
 struct sun4i_i2s_quirks {
boolhas_reset;
boolhas_slave_select_bit;
+   boolhas_fmt_set_lrck_period;
+   boolhas_chcfg;
+   boolhas_chsel_tx_chen;
+   boolhas_chsel_offset;
unsigned intreg_offset_txdata;  /* TX FIFO */
const struct regmap_config  *sun4i_i2s_regmap;
unsigned intmclk_offset;
@@ -291,6 +327,12 @@ static int sun4i_i2s_set_clk_rate(struct sun4i_i2s *i2s,
 
regmap_field_write(i2s->field_clkdiv_mclk_en, 1);
 
+   /* Set sync period */
+   if (i2s->variant->has_fmt_set_lrck_period)
+   regmap_update_bits(i2s->regmap, SUN4I_I2S_FMT0_REG,
+  SUN8I_I2S_FMT0_LRCK_PERIOD_MASK,
+  SUN8I_I2S_FMT0_LRCK_PERIOD(0x1f));
+
return 0;
 }
 
@@ -305,6 +347,15 @@ static int sun4i_i2s_hw_params(struct snd_pcm_substream 
*substream,
if (params_channels(params) != 2)
return -EINVAL;
 
+   if (i2s->variant->has_chcfg) {
+   regmap_update_bits(i2s->regmap, SUN8I_I2S_CHAN_CFG_REG,
+  SUN8I_I2S_CHAN_CFG_TX_SLOT_NUM_MASK,
+  
SUN8I_I2S_CHAN_CFG_TX_SLOT_NUM(params_channels(params)));
+   regmap_update_bits(i2s->regmap, SUN8I_I2S_CHAN_CFG_REG,
+  

[PATCH v3 11/12] ASoC: sun4i-i2s: Update global enable with bitmask

2017-07-29 Thread codekipper
From: Marcus Cooper 

The default value of the config register is different on newer
SoCs and therefore enabling/disabling with a register write
will clear bits used to set the direction of the clock and frame
pins.

Signed-off-by: Marcus Cooper 
---
 sound/soc/sunxi/sun4i-i2s.c | 7 ---
 1 file changed, 4 insertions(+), 3 deletions(-)

diff --git a/sound/soc/sunxi/sun4i-i2s.c b/sound/soc/sunxi/sun4i-i2s.c
index 1c4d763e3a8e..d8bcd3d9c2b6 100644
--- a/sound/soc/sunxi/sun4i-i2s.c
+++ b/sound/soc/sunxi/sun4i-i2s.c
@@ -527,8 +527,8 @@ static int sun4i_i2s_startup(struct snd_pcm_substream 
*substream,
struct sun4i_i2s *i2s = snd_soc_dai_get_drvdata(dai);
 
/* Enable the whole hardware block */
-   regmap_write(i2s->regmap, SUN4I_I2S_CTRL_REG,
-SUN4I_I2S_CTRL_GL_EN);
+   regmap_update_bits(i2s->regmap, SUN4I_I2S_CTRL_REG,
+  SUN4I_I2S_CTRL_GL_EN, SUN4I_I2S_CTRL_GL_EN);
 
/* Enable the first output line */
regmap_update_bits(i2s->regmap, SUN4I_I2S_CTRL_REG,
@@ -551,7 +551,8 @@ static void sun4i_i2s_shutdown(struct snd_pcm_substream 
*substream,
   SUN4I_I2S_CTRL_SDO_EN_MASK, 0);
 
/* Disable the whole hardware block */
-   regmap_write(i2s->regmap, SUN4I_I2S_CTRL_REG, 0);
+   regmap_update_bits(i2s->regmap, SUN4I_I2S_CTRL_REG,
+  SUN4I_I2S_CTRL_GL_EN, 0);
 }
 
 static int sun4i_i2s_set_sysclk(struct snd_soc_dai *dai, int clk_id,
-- 
2.13.3



[PATCH v3 09/12] ASoC: sun4i-i2s: Add regmap field to set format

2017-07-29 Thread codekipper
From: Marcus Cooper 

On the newer SoCs the bits to configure the operational mode are
located in a different register. Add a regmap field so that this
location can be configured.

Signed-off-by: Marcus Cooper 
---
 sound/soc/sunxi/sun4i-i2s.c | 15 ---
 1 file changed, 12 insertions(+), 3 deletions(-)

diff --git a/sound/soc/sunxi/sun4i-i2s.c b/sound/soc/sunxi/sun4i-i2s.c
index 6d8d2c4a675b..9e060d1b73d5 100644
--- a/sound/soc/sunxi/sun4i-i2s.c
+++ b/sound/soc/sunxi/sun4i-i2s.c
@@ -106,6 +106,7 @@
  * @field_fmt_set_sr: regmap field to set sample resolution.
  * @field_fmt_set_bclk_polarity: regmap field to set clk polarity.
  * @field_fmt_set_lrclk_polarity: regmap field to set frame polarity.
+ * @field_fmt_set_mode: regmap field to set the operational mode.
  * @field_txchanmap: location of the tx channel mapping register.
  * @field_rxchanmap: location of the rx channel mapping register.
  * @field_txchansel: location of the tx channel select bit fields.
@@ -125,6 +126,7 @@ struct sun4i_i2s_quirks {
struct reg_fieldfield_fmt_set_sr;
struct reg_fieldfield_fmt_set_bclk_polarity;
struct reg_fieldfield_fmt_set_lrclk_polarity;
+   struct reg_fieldfield_fmt_set_mode;
struct reg_fieldfield_txchanmap;
struct reg_fieldfield_rxchanmap;
struct reg_fieldfield_txchansel;
@@ -148,6 +150,7 @@ struct sun4i_i2s {
struct regmap_field *field_fmt_set_sr;
struct regmap_field *field_fmt_set_bclk_polarity;
struct regmap_field *field_fmt_set_lrclk_polarity;
+   struct regmap_field *field_fmt_set_mode;
struct regmap_field *field_txchanmap;
struct regmap_field *field_rxchanmap;
struct regmap_field *field_txchansel;
@@ -362,9 +365,7 @@ static int sun4i_i2s_set_fmt(struct snd_soc_dai *dai, 
unsigned int fmt)
return -EINVAL;
}
 
-   regmap_update_bits(i2s->regmap, SUN4I_I2S_FMT0_REG,
-  SUN4I_I2S_FMT0_FMT_MASK,
-  val);
+   regmap_field_write(i2s->field_fmt_set_mode, val);
 
/* DAI clock polarity */
switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
@@ -721,6 +722,7 @@ static const struct sun4i_i2s_quirks sun4i_a10_i2s_quirks = 
{
.field_fmt_set_sr   = REG_FIELD(SUN4I_I2S_FMT0_REG, 4, 5),
.field_fmt_set_bclk_polarity = REG_FIELD(SUN4I_I2S_FMT0_REG, 6, 6),
.field_fmt_set_lrclk_polarity = REG_FIELD(SUN4I_I2S_FMT0_REG, 7, 7),
+   .field_fmt_set_mode = REG_FIELD(SUN4I_I2S_FMT0_REG, 0, 1),
.field_txchanmap= REG_FIELD(SUN4I_I2S_TX_CHAN_MAP_REG, 0, 31),
.field_rxchanmap= REG_FIELD(SUN4I_I2S_RX_CHAN_MAP_REG, 0, 31),
.field_txchansel= REG_FIELD(SUN4I_I2S_TX_CHAN_SEL_REG, 0, 2),
@@ -738,6 +740,7 @@ static const struct sun4i_i2s_quirks sun6i_a31_i2s_quirks = 
{
.field_fmt_set_sr   = REG_FIELD(SUN4I_I2S_FMT0_REG, 4, 5),
.field_fmt_set_bclk_polarity = REG_FIELD(SUN4I_I2S_FMT0_REG, 6, 6),
.field_fmt_set_lrclk_polarity = REG_FIELD(SUN4I_I2S_FMT0_REG, 7, 7),
+   .field_fmt_set_mode = REG_FIELD(SUN4I_I2S_FMT0_REG, 0, 1),
.field_txchanmap= REG_FIELD(SUN4I_I2S_TX_CHAN_MAP_REG, 0, 31),
.field_rxchanmap= REG_FIELD(SUN4I_I2S_RX_CHAN_MAP_REG, 0, 31),
.field_txchansel= REG_FIELD(SUN4I_I2S_TX_CHAN_SEL_REG, 0, 2),
@@ -770,6 +773,12 @@ static int sun4i_i2s_init_regmap_fields(struct device 
*dev, struct sun4i_i2s *i2
if (IS_ERR(i2s->field_fmt_set_lrclk_polarity))
return PTR_ERR(i2s->field_fmt_set_lrclk_polarity);
 
+   i2s->field_fmt_set_mode =
+   devm_regmap_field_alloc(dev, i2s->regmap,
+   i2s->variant->field_fmt_set_mode);
+   if (IS_ERR(i2s->field_fmt_set_mode))
+   return PTR_ERR(i2s->field_fmt_set_mode);
+
i2s->field_clkdiv_mclk_en =
devm_regmap_field_alloc(dev, i2s->regmap,
i2s->variant->field_clkdiv_mclk_en);
-- 
2.13.3



[PATCH v3 10/12] ASoC: sun4i-i2s: Check for slave select bit

2017-07-29 Thread codekipper
From: Marcus Cooper 

The newer SoCs do not have this setting. Instead they set the pin
direction. Add a check to see if the bit is valid and if so set
it accordingly.

Signed-off-by: Marcus Cooper 
---
 sound/soc/sunxi/sun4i-i2s.c | 38 ++
 1 file changed, 22 insertions(+), 16 deletions(-)

diff --git a/sound/soc/sunxi/sun4i-i2s.c b/sound/soc/sunxi/sun4i-i2s.c
index 9e060d1b73d5..1c4d763e3a8e 100644
--- a/sound/soc/sunxi/sun4i-i2s.c
+++ b/sound/soc/sunxi/sun4i-i2s.c
@@ -96,6 +96,7 @@
  * struct sun4i_i2s_quirks - Differences between SoC variants.
  *
  * @has_reset: SoC needs reset deasserted.
+ * @has_slave_select_bit: SoC has a bit to enable slave mode.
  * @reg_offset_txdata: offset of the tx fifo.
  * @sun4i_i2s_regmap: regmap config to use.
  * @mclk_offset: Value by which mclkdiv needs to be adjusted.
@@ -114,6 +115,7 @@
  */
 struct sun4i_i2s_quirks {
boolhas_reset;
+   boolhas_slave_select_bit;
unsigned intreg_offset_txdata;  /* TX FIFO */
const struct regmap_config  *sun4i_i2s_regmap;
unsigned intmclk_offset;
@@ -391,30 +393,32 @@ static int sun4i_i2s_set_fmt(struct snd_soc_dai *dai, 
unsigned int fmt)
regmap_field_write(i2s->field_fmt_set_bclk_polarity, bclk_polarity);
regmap_field_write(i2s->field_fmt_set_lrclk_polarity, lrclk_polarity);
 
-   /* DAI clock master masks */
-   switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
-   case SND_SOC_DAIFMT_CBS_CFS:
-   /* BCLK and LRCLK master */
-   val = SUN4I_I2S_CTRL_MODE_MASTER;
-   break;
-   case SND_SOC_DAIFMT_CBM_CFM:
-   /* BCLK and LRCLK slave */
-   val = SUN4I_I2S_CTRL_MODE_SLAVE;
-   break;
-   default:
-   return -EINVAL;
+   if (i2s->variant->has_slave_select_bit) {
+   /* DAI clock master masks */
+   switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+   case SND_SOC_DAIFMT_CBS_CFS:
+   /* BCLK and LRCLK master */
+   val = SUN4I_I2S_CTRL_MODE_MASTER;
+   break;
+   case SND_SOC_DAIFMT_CBM_CFM:
+   /* BCLK and LRCLK slave */
+   val = SUN4I_I2S_CTRL_MODE_SLAVE;
+   break;
+   default:
+   return -EINVAL;
+   }
+   regmap_update_bits(i2s->regmap, SUN4I_I2S_CTRL_REG,
+  SUN4I_I2S_CTRL_MODE_MASK,
+  val);
}
 
-   regmap_update_bits(i2s->regmap, SUN4I_I2S_CTRL_REG,
-  SUN4I_I2S_CTRL_MODE_MASK,
-  val);
-
/* Set significant bits in our FIFOs */
regmap_update_bits(i2s->regmap, SUN4I_I2S_FIFO_CTRL_REG,
   SUN4I_I2S_FIFO_CTRL_TX_MODE_MASK |
   SUN4I_I2S_FIFO_CTRL_RX_MODE_MASK,
   SUN4I_I2S_FIFO_CTRL_TX_MODE(1) |
   SUN4I_I2S_FIFO_CTRL_RX_MODE(1));
+
return 0;
 }
 
@@ -715,6 +719,7 @@ static const struct sun4i_i2s_quirks sun4i_a10_i2s_quirks = 
{
.has_reset  = false,
.reg_offset_txdata  = SUN4I_I2S_FIFO_TX_REG,
.sun4i_i2s_regmap   = _i2s_regmap_config,
+   .has_slave_select_bit   = true,
.field_clkdiv_mclk_en   = REG_FIELD(SUN4I_I2S_CLK_DIV_REG,
SUN4I_I2S_CLK_DIV_MCLK_EN,
SUN4I_I2S_CLK_DIV_MCLK_EN),
@@ -733,6 +738,7 @@ static const struct sun4i_i2s_quirks sun6i_a31_i2s_quirks = 
{
.has_reset  = true,
.reg_offset_txdata  = SUN4I_I2S_FIFO_TX_REG,
.sun4i_i2s_regmap   = _i2s_regmap_config,
+   .has_slave_select_bit   = true,
.field_clkdiv_mclk_en   = REG_FIELD(SUN4I_I2S_CLK_DIV_REG,
SUN4I_I2S_CLK_DIV_MCLK_EN,
SUN4I_I2S_CLK_DIV_MCLK_EN),
-- 
2.13.3



[PATCH v3 00/12] ASoC: Add I2S support for Allwinner H3 SoCs

2017-07-29 Thread codekipper
From: Marcus Cooper <codekip...@gmail.com>

Hi All,
please find attached a series of patches to bring i2s support to the
Allwinner H3 SoC. This has been tested with the following setups:

A20 Olimex EVB connected to a pcm5102
Orange Pi 2 connected to a uda1380
Orange Pi 2 hdmi audio playback
Pine 64 connected to the audio DAC board

To get i2s working some additional patches are required which will be
delivered later. For now they have been pushed here

https://github.com/codekipper/linux-sunxi/commits/sunxi-audio-h3

I don't own a A33 device which uses the i2s block for the audio codec
so if someone could test against that it would be much appreciated.

I'm also wondering if there is a preferred way of setting the lrclk
size in the dts?..currently it is set to the sample width but for example
the pcm5102a wants it to be 32 bits whatever the sample rate.

Thanks in advance,
CK

---

v3 changes compared to v2 are:
- initial changes to prepare driver for newer SoCs has been broken down
  into smaller patches
- reduce use of regmap fields to where just needed.
- clkdiv expansion will be delivered later.
- defines for H3 variant segregated.
- fixed regmap config issue with SUN8I_I2S_FIFO_TX_REG.


v2 changes compared to v1 are:
 - massive refactoring to remove duplicate code making use of regmap_fields.
 - extending the clock divisors.
 - removed code that should be delivered when we support 20/24bits

---

Marcus Cooper (12):
  ASoC: sun4i-i2s: Extend quirks scope
  ASoC: sun4i-i2s: Add clkdiv offsets to quirks
  ASoC: sun4i-i2s: Add regmap config to quirks
  ASoC: sun4i-i2s: Add TX FIFO offset to quirks
  ASoC: sun4i-i2s: Add regmap fields for channels
  ASoC: sun4i-i2s: Add changes for wss and sr
  ASoC: sun4i-i2s: bclk and lrclk polarity tidyup
  ASoC: sun4i-i2s: Add mclk enable regmap field
  ASoC: sun4i-i2s: Add regmap field to set format
  ASoC: sun4i-i2s: Check for slave select bit
  ASoC: sun4i-i2s: Update global enable with bitmask
  ASoC: sun4i-i2s: Add support for H3

 .../devicetree/bindings/sound/sun4i-i2s.txt|   2 +
 sound/soc/sunxi/sun4i-i2s.c| 460 ++---
 2 files changed, 398 insertions(+), 64 deletions(-)

-- 
2.13.3



[PATCH v3 05/12] ASoC: sun4i-i2s: Add regmap fields for channels

2017-07-29 Thread codekipper
From: Marcus Cooper 

On the original i2s block the channel mapping and selection were
configured for stereo audio by default: This is not the case with
the newer SoCs and they are also located at different offsets.

To support the newer SoC then regmap fields have been added to the
quirks and these are initialised to their correct settings during
probing.

Signed-off-by: Marcus Cooper 
---
 sound/soc/sunxi/sun4i-i2s.c | 80 -
 1 file changed, 72 insertions(+), 8 deletions(-)

diff --git a/sound/soc/sunxi/sun4i-i2s.c b/sound/soc/sunxi/sun4i-i2s.c
index 2a25df22c2f8..120f797a38e8 100644
--- a/sound/soc/sunxi/sun4i-i2s.c
+++ b/sound/soc/sunxi/sun4i-i2s.c
@@ -82,7 +82,7 @@
 #define SUN4I_I2S_TX_CNT_REG   0x2c
 
 #define SUN4I_I2S_TX_CHAN_SEL_REG  0x30
-#define SUN4I_I2S_TX_CHAN_SEL(num_chan)(((num_chan) - 1) << 0)
+#define SUN4I_I2S_CHAN_SEL(num_chan)   (((num_chan) - 1) << 0)
 
 #define SUN4I_I2S_TX_CHAN_MAP_REG  0x34
 #define SUN4I_I2S_TX_CHAN_MAP(chan, sample)((sample) << (chan << 2))
@@ -98,6 +98,10 @@
  * @sun4i_i2s_regmap: regmap config to use.
  * @mclk_offset: Value by which mclkdiv needs to be adjusted.
  * @bclk_offset: Value by which bclkdiv needs to be adjusted.
+ * @field_txchanmap: location of the tx channel mapping register.
+ * @field_rxchanmap: location of the rx channel mapping register.
+ * @field_txchansel: location of the tx channel select bit fields.
+ * @field_rxchansel: location of the rx channel select bit fields.
  */
 struct sun4i_i2s_quirks {
boolhas_reset;
@@ -105,6 +109,12 @@ struct sun4i_i2s_quirks {
const struct regmap_config  *sun4i_i2s_regmap;
unsigned intmclk_offset;
unsigned intbclk_offset;
+
+   /* Register fields for i2s */
+   struct reg_fieldfield_txchanmap;
+   struct reg_fieldfield_rxchanmap;
+   struct reg_fieldfield_txchansel;
+   struct reg_fieldfield_rxchansel;
 };
 
 struct sun4i_i2s {
@@ -118,6 +128,12 @@ struct sun4i_i2s {
struct snd_dmaengine_dai_dma_data   capture_dma_data;
struct snd_dmaengine_dai_dma_data   playback_dma_data;
 
+   /* Register fields for i2s */
+   struct regmap_field *field_txchanmap;
+   struct regmap_field *field_rxchanmap;
+   struct regmap_field *field_txchansel;
+   struct regmap_field *field_rxchansel;
+
const struct sun4i_i2s_quirks   *variant;
 };
 
@@ -264,6 +280,18 @@ static int sun4i_i2s_hw_params(struct snd_pcm_substream 
*substream,
if (params_channels(params) != 2)
return -EINVAL;
 
+   /* Map the channels for playback and capture */
+   regmap_field_write(i2s->field_txchanmap, 0x76543210);
+   regmap_field_write(i2s->field_rxchanmap, 0x3210);
+
+   /* Configure the channels */
+   regmap_field_write(i2s->field_txchansel,
+  SUN4I_I2S_CHAN_SEL(params_channels(params)));
+
+   regmap_field_write(i2s->field_rxchansel,
+  SUN4I_I2S_CHAN_SEL(params_channels(params)));
+
+
switch (params_physical_width(params)) {
case 16:
width = DMA_SLAVE_BUSWIDTH_2_BYTES;
@@ -486,13 +514,6 @@ static int sun4i_i2s_startup(struct snd_pcm_substream 
*substream,
   SUN4I_I2S_CTRL_SDO_EN_MASK,
   SUN4I_I2S_CTRL_SDO_EN(0));
 
-   /* Enable the first two channels */
-   regmap_write(i2s->regmap, SUN4I_I2S_TX_CHAN_SEL_REG,
-SUN4I_I2S_TX_CHAN_SEL(2));
-
-   /* Map them to the two first samples coming in */
-   regmap_write(i2s->regmap, SUN4I_I2S_TX_CHAN_MAP_REG,
-SUN4I_I2S_TX_CHAN_MAP(0, 0) | SUN4I_I2S_TX_CHAN_MAP(1, 1));
 
return clk_prepare_enable(i2s->mod_clk);
 }
@@ -677,14 +698,51 @@ static const struct sun4i_i2s_quirks sun4i_a10_i2s_quirks 
= {
.has_reset  = false,
.reg_offset_txdata  = SUN4I_I2S_FIFO_TX_REG,
.sun4i_i2s_regmap   = _i2s_regmap_config,
+   .field_txchanmap= REG_FIELD(SUN4I_I2S_TX_CHAN_MAP_REG, 0, 31),
+   .field_rxchanmap= REG_FIELD(SUN4I_I2S_RX_CHAN_MAP_REG, 0, 31),
+   .field_txchansel= REG_FIELD(SUN4I_I2S_TX_CHAN_SEL_REG, 0, 2),
+   .field_rxchansel= REG_FIELD(SUN4I_I2S_RX_CHAN_SEL_REG, 0, 2),
 };
 
 static const struct sun4i_i2s_quirks sun6i_a31_i2s_quirks = {
.has_reset  = true,
.reg_offset_txdata  = SUN4I_I2S_FIFO_TX_REG,
.sun4i_i2s_regmap   = _i2s_regmap_config,
+   .field_txchanmap= REG_FIELD(SUN4I_I2S_TX_CHAN_MAP_REG, 0, 31),
+   .field_rxchanmap= REG_FIELD(SUN4I_I2S_RX_CHAN_MAP_REG, 0, 31),
+   .field_txchansel= 

[PATCH v3 04/12] ASoC: sun4i-i2s: Add TX FIFO offset to quirks

2017-07-29 Thread codekipper
From: Marcus Cooper 

It has been seen that the newer SoCs have a different TX FIFO
address. Add this to the quirks structure.

Signed-off-by: Marcus Cooper 
---
 sound/soc/sunxi/sun4i-i2s.c | 7 ++-
 1 file changed, 6 insertions(+), 1 deletion(-)

diff --git a/sound/soc/sunxi/sun4i-i2s.c b/sound/soc/sunxi/sun4i-i2s.c
index 73e991f5a81e..2a25df22c2f8 100644
--- a/sound/soc/sunxi/sun4i-i2s.c
+++ b/sound/soc/sunxi/sun4i-i2s.c
@@ -94,12 +94,14 @@
  * struct sun4i_i2s_quirks - Differences between SoC variants.
  *
  * @has_reset: SoC needs reset deasserted.
+ * @reg_offset_txdata: offset of the tx fifo.
  * @sun4i_i2s_regmap: regmap config to use.
  * @mclk_offset: Value by which mclkdiv needs to be adjusted.
  * @bclk_offset: Value by which bclkdiv needs to be adjusted.
  */
 struct sun4i_i2s_quirks {
boolhas_reset;
+   unsigned intreg_offset_txdata;  /* TX FIFO */
const struct regmap_config  *sun4i_i2s_regmap;
unsigned intmclk_offset;
unsigned intbclk_offset;
@@ -673,11 +675,13 @@ static int sun4i_i2s_runtime_suspend(struct device *dev)
 
 static const struct sun4i_i2s_quirks sun4i_a10_i2s_quirks = {
.has_reset  = false,
+   .reg_offset_txdata  = SUN4I_I2S_FIFO_TX_REG,
.sun4i_i2s_regmap   = _i2s_regmap_config,
 };
 
 static const struct sun4i_i2s_quirks sun6i_a31_i2s_quirks = {
.has_reset  = true,
+   .reg_offset_txdata  = SUN4I_I2S_FIFO_TX_REG,
.sun4i_i2s_regmap   = _i2s_regmap_config,
 };
 
@@ -746,7 +750,8 @@ static int sun4i_i2s_probe(struct platform_device *pdev)
}
}
 
-   i2s->playback_dma_data.addr = res->start + SUN4I_I2S_FIFO_TX_REG;
+   i2s->playback_dma_data.addr = res->start +
+   i2s->variant->reg_offset_txdata;
i2s->playback_dma_data.maxburst = 8;
 
i2s->capture_dma_data.addr = res->start + SUN4I_I2S_FIFO_RX_REG;
-- 
2.13.3



[PATCH v3 06/12] ASoC: sun4i-i2s: Add changes for wss and sr

2017-07-29 Thread codekipper
From: Marcus Cooper 

On newer SoCs the location of the slot width select and sample
resolution are different and also there is a bigger range of
support.

For the current supported rates then an offset is required.

Signed-off-by: Marcus Cooper 
---
 sound/soc/sunxi/sun4i-i2s.c | 31 ---
 1 file changed, 28 insertions(+), 3 deletions(-)

diff --git a/sound/soc/sunxi/sun4i-i2s.c b/sound/soc/sunxi/sun4i-i2s.c
index 120f797a38e8..171df99a267e 100644
--- a/sound/soc/sunxi/sun4i-i2s.c
+++ b/sound/soc/sunxi/sun4i-i2s.c
@@ -98,6 +98,9 @@
  * @sun4i_i2s_regmap: regmap config to use.
  * @mclk_offset: Value by which mclkdiv needs to be adjusted.
  * @bclk_offset: Value by which bclkdiv needs to be adjusted.
+ * @fmt_offset: Value by which wss and sr needs to be adjusted.
+ * @field_fmt_set_wss: regmap field to set word select size.
+ * @field_fmt_set_sr: regmap field to set sample resolution.
  * @field_txchanmap: location of the tx channel mapping register.
  * @field_rxchanmap: location of the rx channel mapping register.
  * @field_txchansel: location of the tx channel select bit fields.
@@ -109,8 +112,11 @@ struct sun4i_i2s_quirks {
const struct regmap_config  *sun4i_i2s_regmap;
unsigned intmclk_offset;
unsigned intbclk_offset;
+   unsigned intfmt_offset;
 
/* Register fields for i2s */
+   struct reg_fieldfield_fmt_set_wss;
+   struct reg_fieldfield_fmt_set_sr;
struct reg_fieldfield_txchanmap;
struct reg_fieldfield_rxchanmap;
struct reg_fieldfield_txchansel;
@@ -129,6 +135,8 @@ struct sun4i_i2s {
struct snd_dmaengine_dai_dma_data   playback_dma_data;
 
/* Register fields for i2s */
+   struct regmap_field *field_fmt_set_wss;
+   struct regmap_field *field_fmt_set_sr;
struct regmap_field *field_txchanmap;
struct regmap_field *field_rxchanmap;
struct regmap_field *field_txchansel;
@@ -311,9 +319,10 @@ static int sun4i_i2s_hw_params(struct snd_pcm_substream 
*substream,
return -EINVAL;
}
 
-   regmap_update_bits(i2s->regmap, SUN4I_I2S_FMT0_REG,
-  SUN4I_I2S_FMT0_WSS_MASK | SUN4I_I2S_FMT0_SR_MASK,
-  SUN4I_I2S_FMT0_WSS(wss) | SUN4I_I2S_FMT0_SR(sr));
+   regmap_field_write(i2s->field_fmt_set_wss,
+  wss + i2s->variant->fmt_offset);
+   regmap_field_write(i2s->field_fmt_set_sr,
+  sr + i2s->variant->fmt_offset);
 
return sun4i_i2s_set_clk_rate(i2s, params_rate(params),
  params_width(params));
@@ -698,6 +707,8 @@ static const struct sun4i_i2s_quirks sun4i_a10_i2s_quirks = 
{
.has_reset  = false,
.reg_offset_txdata  = SUN4I_I2S_FIFO_TX_REG,
.sun4i_i2s_regmap   = _i2s_regmap_config,
+   .field_fmt_set_wss  = REG_FIELD(SUN4I_I2S_FMT0_REG, 2, 3),
+   .field_fmt_set_sr   = REG_FIELD(SUN4I_I2S_FMT0_REG, 4, 5),
.field_txchanmap= REG_FIELD(SUN4I_I2S_TX_CHAN_MAP_REG, 0, 31),
.field_rxchanmap= REG_FIELD(SUN4I_I2S_RX_CHAN_MAP_REG, 0, 31),
.field_txchansel= REG_FIELD(SUN4I_I2S_TX_CHAN_SEL_REG, 0, 2),
@@ -708,6 +719,8 @@ static const struct sun4i_i2s_quirks sun6i_a31_i2s_quirks = 
{
.has_reset  = true,
.reg_offset_txdata  = SUN4I_I2S_FIFO_TX_REG,
.sun4i_i2s_regmap   = _i2s_regmap_config,
+   .field_fmt_set_wss  = REG_FIELD(SUN4I_I2S_FMT0_REG, 2, 3),
+   .field_fmt_set_sr   = REG_FIELD(SUN4I_I2S_FMT0_REG, 4, 5),
.field_txchanmap= REG_FIELD(SUN4I_I2S_TX_CHAN_MAP_REG, 0, 31),
.field_rxchanmap= REG_FIELD(SUN4I_I2S_RX_CHAN_MAP_REG, 0, 31),
.field_txchansel= REG_FIELD(SUN4I_I2S_TX_CHAN_SEL_REG, 0, 2),
@@ -716,6 +729,18 @@ static const struct sun4i_i2s_quirks sun6i_a31_i2s_quirks 
= {
 
 static int sun4i_i2s_init_regmap_fields(struct device *dev, struct sun4i_i2s 
*i2s)
 {
+   i2s->field_fmt_set_wss =
+   devm_regmap_field_alloc(dev, i2s->regmap,
+   i2s->variant->field_fmt_set_wss);
+   if (IS_ERR(i2s->field_fmt_set_wss))
+   return PTR_ERR(i2s->field_fmt_set_wss);
+
+   i2s->field_fmt_set_sr =
+   devm_regmap_field_alloc(dev, i2s->regmap,
+   i2s->variant->field_fmt_set_sr);
+   if (IS_ERR(i2s->field_fmt_set_sr))
+   return PTR_ERR(i2s->field_fmt_set_sr);
+
i2s->field_txchanmap =
devm_regmap_field_alloc(dev, i2s->regmap,
i2s->variant->field_txchanmap);
-- 
2.13.3



[PATCH v3 08/12] ASoC: sun4i-i2s: Add mclk enable regmap field

2017-07-29 Thread codekipper
From: Marcus Cooper 

The location of the mclk output enable bit is different on newer
SoCs. Use a regmap field to enable it.

Signed-off-by: Marcus Cooper 
---
 sound/soc/sunxi/sun4i-i2s.c | 22 +++---
 1 file changed, 19 insertions(+), 3 deletions(-)

diff --git a/sound/soc/sunxi/sun4i-i2s.c b/sound/soc/sunxi/sun4i-i2s.c
index 90daa974bd27..6d8d2c4a675b 100644
--- a/sound/soc/sunxi/sun4i-i2s.c
+++ b/sound/soc/sunxi/sun4i-i2s.c
@@ -74,7 +74,7 @@
 #define SUN4I_I2S_INT_STA_REG  0x20
 
 #define SUN4I_I2S_CLK_DIV_REG  0x24
-#define SUN4I_I2S_CLK_DIV_MCLK_EN  BIT(7)
+#define SUN4I_I2S_CLK_DIV_MCLK_EN  7
 #define SUN4I_I2S_CLK_DIV_BCLK_MASKGENMASK(6, 4)
 #define SUN4I_I2S_CLK_DIV_BCLK(bclk)   ((bclk) << 4)
 #define SUN4I_I2S_CLK_DIV_MCLK_MASKGENMASK(3, 0)
@@ -101,6 +101,7 @@
  * @mclk_offset: Value by which mclkdiv needs to be adjusted.
  * @bclk_offset: Value by which bclkdiv needs to be adjusted.
  * @fmt_offset: Value by which wss and sr needs to be adjusted.
+ * @field_clkdiv_mclk_en: regmap field to enable mclk output.
  * @field_fmt_set_wss: regmap field to set word select size.
  * @field_fmt_set_sr: regmap field to set sample resolution.
  * @field_fmt_set_bclk_polarity: regmap field to set clk polarity.
@@ -119,6 +120,7 @@ struct sun4i_i2s_quirks {
unsigned intfmt_offset;
 
/* Register fields for i2s */
+   struct reg_fieldfield_clkdiv_mclk_en;
struct reg_fieldfield_fmt_set_wss;
struct reg_fieldfield_fmt_set_sr;
struct reg_fieldfield_fmt_set_bclk_polarity;
@@ -141,6 +143,7 @@ struct sun4i_i2s {
struct snd_dmaengine_dai_dma_data   playback_dma_data;
 
/* Register fields for i2s */
+   struct regmap_field *field_clkdiv_mclk_en;
struct regmap_field *field_fmt_set_wss;
struct regmap_field *field_fmt_set_sr;
struct regmap_field *field_fmt_set_bclk_polarity;
@@ -279,8 +282,9 @@ static int sun4i_i2s_set_clk_rate(struct sun4i_i2s *i2s,
 
regmap_write(i2s->regmap, SUN4I_I2S_CLK_DIV_REG,
 SUN4I_I2S_CLK_DIV_BCLK(bclk_div) |
-SUN4I_I2S_CLK_DIV_MCLK(mclk_div) |
-SUN4I_I2S_CLK_DIV_MCLK_EN);
+SUN4I_I2S_CLK_DIV_MCLK(mclk_div));
+
+   regmap_field_write(i2s->field_clkdiv_mclk_en, 1);
 
return 0;
 }
@@ -710,6 +714,9 @@ static const struct sun4i_i2s_quirks sun4i_a10_i2s_quirks = 
{
.has_reset  = false,
.reg_offset_txdata  = SUN4I_I2S_FIFO_TX_REG,
.sun4i_i2s_regmap   = _i2s_regmap_config,
+   .field_clkdiv_mclk_en   = REG_FIELD(SUN4I_I2S_CLK_DIV_REG,
+   SUN4I_I2S_CLK_DIV_MCLK_EN,
+   SUN4I_I2S_CLK_DIV_MCLK_EN),
.field_fmt_set_wss  = REG_FIELD(SUN4I_I2S_FMT0_REG, 2, 3),
.field_fmt_set_sr   = REG_FIELD(SUN4I_I2S_FMT0_REG, 4, 5),
.field_fmt_set_bclk_polarity = REG_FIELD(SUN4I_I2S_FMT0_REG, 6, 6),
@@ -724,6 +731,9 @@ static const struct sun4i_i2s_quirks sun6i_a31_i2s_quirks = 
{
.has_reset  = true,
.reg_offset_txdata  = SUN4I_I2S_FIFO_TX_REG,
.sun4i_i2s_regmap   = _i2s_regmap_config,
+   .field_clkdiv_mclk_en   = REG_FIELD(SUN4I_I2S_CLK_DIV_REG,
+   SUN4I_I2S_CLK_DIV_MCLK_EN,
+   SUN4I_I2S_CLK_DIV_MCLK_EN),
.field_fmt_set_wss  = REG_FIELD(SUN4I_I2S_FMT0_REG, 2, 3),
.field_fmt_set_sr   = REG_FIELD(SUN4I_I2S_FMT0_REG, 4, 5),
.field_fmt_set_bclk_polarity = REG_FIELD(SUN4I_I2S_FMT0_REG, 6, 6),
@@ -760,6 +770,12 @@ static int sun4i_i2s_init_regmap_fields(struct device 
*dev, struct sun4i_i2s *i2
if (IS_ERR(i2s->field_fmt_set_lrclk_polarity))
return PTR_ERR(i2s->field_fmt_set_lrclk_polarity);
 
+   i2s->field_clkdiv_mclk_en =
+   devm_regmap_field_alloc(dev, i2s->regmap,
+   i2s->variant->field_clkdiv_mclk_en);
+   if (IS_ERR(i2s->field_clkdiv_mclk_en))
+   return PTR_ERR(i2s->field_clkdiv_mclk_en);
+
i2s->field_txchanmap =
devm_regmap_field_alloc(dev, i2s->regmap,
i2s->variant->field_txchanmap);
-- 
2.13.3



[PATCH v3 03/12] ASoC: sun4i-i2s: Add regmap config to quirks

2017-07-29 Thread codekipper
From: Marcus Cooper 

The newer SoCs have a larger range than the original SoC that this
driver was developed for. By adding the regmap config to the quirks
then the driver can initialise the managed register map correctly.

Signed-off-by: Marcus Cooper 
---
 sound/soc/sunxi/sun4i-i2s.c | 10 +++---
 1 file changed, 7 insertions(+), 3 deletions(-)

diff --git a/sound/soc/sunxi/sun4i-i2s.c b/sound/soc/sunxi/sun4i-i2s.c
index 1d538de4e4d0..73e991f5a81e 100644
--- a/sound/soc/sunxi/sun4i-i2s.c
+++ b/sound/soc/sunxi/sun4i-i2s.c
@@ -94,11 +94,13 @@
  * struct sun4i_i2s_quirks - Differences between SoC variants.
  *
  * @has_reset: SoC needs reset deasserted.
+ * @sun4i_i2s_regmap: regmap config to use.
  * @mclk_offset: Value by which mclkdiv needs to be adjusted.
  * @bclk_offset: Value by which bclkdiv needs to be adjusted.
  */
 struct sun4i_i2s_quirks {
boolhas_reset;
+   const struct regmap_config  *sun4i_i2s_regmap;
unsigned intmclk_offset;
unsigned intbclk_offset;
 };
@@ -670,11 +672,13 @@ static int sun4i_i2s_runtime_suspend(struct device *dev)
 }
 
 static const struct sun4i_i2s_quirks sun4i_a10_i2s_quirks = {
-   .has_reset  = false,
+   .has_reset  = false,
+   .sun4i_i2s_regmap   = _i2s_regmap_config,
 };
 
 static const struct sun4i_i2s_quirks sun6i_a31_i2s_quirks = {
-   .has_reset  = true,
+   .has_reset  = true,
+   .sun4i_i2s_regmap   = _i2s_regmap_config,
 };
 
 static int sun4i_i2s_probe(struct platform_device *pdev)
@@ -713,7 +717,7 @@ static int sun4i_i2s_probe(struct platform_device *pdev)
}
 
i2s->regmap = devm_regmap_init_mmio(>dev, regs,
-   _i2s_regmap_config);
+   i2s->variant->sun4i_i2s_regmap);
if (IS_ERR(i2s->regmap)) {
dev_err(>dev, "Regmap initialisation failed\n");
return PTR_ERR(i2s->regmap);
-- 
2.13.3



[PATCH v3 01/12] ASoC: sun4i-i2s: Extend quirks scope

2017-07-29 Thread codekipper
From: Marcus Cooper 

In preparation for the changes required to support newer SoCs then
quirks has been moved and also added to the device structure.

Signed-off-by: Marcus Cooper 
---
 sound/soc/sunxi/sun4i-i2s.c | 22 ++
 1 file changed, 14 insertions(+), 8 deletions(-)

diff --git a/sound/soc/sunxi/sun4i-i2s.c b/sound/soc/sunxi/sun4i-i2s.c
index 62b307b0c846..d7ee7a443e4e 100644
--- a/sound/soc/sunxi/sun4i-i2s.c
+++ b/sound/soc/sunxi/sun4i-i2s.c
@@ -90,6 +90,15 @@
 #define SUN4I_I2S_RX_CHAN_SEL_REG  0x38
 #define SUN4I_I2S_RX_CHAN_MAP_REG  0x3c
 
+/**
+ * struct sun4i_i2s_quirks - Differences between SoC variants.
+ *
+ * @has_reset: SoC needs reset deasserted.
+ */
+struct sun4i_i2s_quirks {
+   boolhas_reset;
+};
+
 struct sun4i_i2s {
struct clk  *bus_clk;
struct clk  *mod_clk;
@@ -100,6 +109,8 @@ struct sun4i_i2s {
 
struct snd_dmaengine_dai_dma_data   capture_dma_data;
struct snd_dmaengine_dai_dma_data   playback_dma_data;
+
+   const struct sun4i_i2s_quirks   *variant;
 };
 
 struct sun4i_i2s_clk_div {
@@ -654,10 +665,6 @@ static int sun4i_i2s_runtime_suspend(struct device *dev)
return 0;
 }
 
-struct sun4i_i2s_quirks {
-   bool has_reset;
-};
-
 static const struct sun4i_i2s_quirks sun4i_a10_i2s_quirks = {
.has_reset  = false,
 };
@@ -669,7 +676,6 @@ static const struct sun4i_i2s_quirks sun6i_a31_i2s_quirks = 
{
 static int sun4i_i2s_probe(struct platform_device *pdev)
 {
struct sun4i_i2s *i2s;
-   const struct sun4i_i2s_quirks *quirks;
struct resource *res;
void __iomem *regs;
int irq, ret;
@@ -690,8 +696,8 @@ static int sun4i_i2s_probe(struct platform_device *pdev)
return irq;
}
 
-   quirks = of_device_get_match_data(>dev);
-   if (!quirks) {
+   i2s->variant = of_device_get_match_data(>dev);
+   if (!i2s->variant) {
dev_err(>dev, "Failed to determine the quirks to use\n");
return -ENODEV;
}
@@ -715,7 +721,7 @@ static int sun4i_i2s_probe(struct platform_device *pdev)
return PTR_ERR(i2s->mod_clk);
}
 
-   if (quirks->has_reset) {
+   if (i2s->variant->has_reset) {
i2s->rst = devm_reset_control_get_exclusive(>dev, NULL);
if (IS_ERR(i2s->rst)) {
dev_err(>dev, "Failed to get reset control\n");
-- 
2.13.3



[PATCH v3 08/11] ASoC: sun4i-i2s: Add regmap field to set DAI format

2017-08-12 Thread codekipper
From: Marcus Cooper 

On the newer SoCs the bits to configure the operational mode are
located in a different register. Add a regmap field so that this
location can be configured.

Signed-off-by: Marcus Cooper 
---
 sound/soc/sunxi/sun4i-i2s.c | 16 +---
 1 file changed, 13 insertions(+), 3 deletions(-)

diff --git a/sound/soc/sunxi/sun4i-i2s.c b/sound/soc/sunxi/sun4i-i2s.c
index 33af99076d62..b61ef87d0049 100644
--- a/sound/soc/sunxi/sun4i-i2s.c
+++ b/sound/soc/sunxi/sun4i-i2s.c
@@ -106,6 +106,7 @@
  * @field_fmt_sr: regmap field to set sample resolution.
  * @field_fmt_bclk: regmap field to set clk polarity.
  * @field_fmt_lrclk: regmap field to set frame polarity.
+ * @field_fmt_mode: regmap field to set the operational mode.
  * @field_txchanmap: location of the tx channel mapping register.
  * @field_rxchanmap: location of the rx channel mapping register.
  * @field_txchansel: location of the tx channel select bit fields.
@@ -125,6 +126,7 @@ struct sun4i_i2s_quirks {
struct reg_fieldfield_fmt_sr;
struct reg_fieldfield_fmt_bclk;
struct reg_fieldfield_fmt_lrclk;
+   struct reg_fieldfield_fmt_mode;
struct reg_fieldfield_txchanmap;
struct reg_fieldfield_rxchanmap;
struct reg_fieldfield_txchansel;
@@ -148,6 +150,7 @@ struct sun4i_i2s {
struct regmap_field *field_fmt_sr;
struct regmap_field *field_fmt_bclk;
struct regmap_field *field_fmt_lrclk;
+   struct regmap_field *field_fmt_mode;
struct regmap_field *field_txchanmap;
struct regmap_field *field_rxchanmap;
struct regmap_field *field_txchansel;
@@ -365,9 +368,7 @@ static int sun4i_i2s_set_fmt(struct snd_soc_dai *dai, 
unsigned int fmt)
return -EINVAL;
}
 
-   regmap_update_bits(i2s->regmap, SUN4I_I2S_FMT0_REG,
-  SUN4I_I2S_FMT0_FMT_MASK,
-  val);
+   regmap_field_write(i2s->field_fmt_mode, val);
 
/* DAI clock polarity */
switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
@@ -722,6 +723,7 @@ static const struct sun4i_i2s_quirks sun4i_a10_i2s_quirks = 
{
.field_fmt_sr   = REG_FIELD(SUN4I_I2S_FMT0_REG, 4, 5),
.field_fmt_bclk = REG_FIELD(SUN4I_I2S_FMT0_REG, 6, 6),
.field_fmt_lrclk= REG_FIELD(SUN4I_I2S_FMT0_REG, 7, 7),
+   .field_fmt_mode = REG_FIELD(SUN4I_I2S_FMT0_REG, 0, 1),
.field_txchanmap= REG_FIELD(SUN4I_I2S_TX_CHAN_MAP_REG, 0, 31),
.field_rxchanmap= REG_FIELD(SUN4I_I2S_RX_CHAN_MAP_REG, 0, 31),
.field_txchansel= REG_FIELD(SUN4I_I2S_TX_CHAN_SEL_REG, 0, 2),
@@ -737,6 +739,7 @@ static const struct sun4i_i2s_quirks sun6i_a31_i2s_quirks = 
{
.field_fmt_sr   = REG_FIELD(SUN4I_I2S_FMT0_REG, 4, 5),
.field_fmt_bclk = REG_FIELD(SUN4I_I2S_FMT0_REG, 6, 6),
.field_fmt_lrclk= REG_FIELD(SUN4I_I2S_FMT0_REG, 7, 7),
+   .field_fmt_mode = REG_FIELD(SUN4I_I2S_FMT0_REG, 0, 1),
.field_txchanmap= REG_FIELD(SUN4I_I2S_TX_CHAN_MAP_REG, 0, 31),
.field_rxchanmap= REG_FIELD(SUN4I_I2S_RX_CHAN_MAP_REG, 0, 31),
.field_txchansel= REG_FIELD(SUN4I_I2S_TX_CHAN_SEL_REG, 0, 2),
@@ -781,6 +784,13 @@ static int sun4i_i2s_init_regmap_fields(struct device *dev,
ret = PTR_ERR_OR_ZERO(i2s->field_rxchansel);
}
 
+   if (!ret) {
+   i2s->field_fmt_mode =
+   devm_regmap_field_alloc(dev, i2s->regmap,
+   i2s->variant->field_fmt_mode);
+   ret = PTR_ERR_OR_ZERO(i2s->field_fmt_mode);
+   }
+
if (!ret) {
i2s->field_fmt_wss =
devm_regmap_field_alloc(dev, i2s->regmap,
-- 
2.14.1



[PATCH v3 06/11] ASoC: sun4i-i2s: bclk and lrclk polarity tidyup

2017-08-12 Thread codekipper
From: Marcus Cooper 

On newer SoCs the bit fields for the blck and lrclk polarity are in
a different locations. Use regmap fields to set the polarity bits
as intended.

Signed-off-by: Marcus Cooper 
---
 sound/soc/sunxi/sun4i-i2s.c | 47 -
 1 file changed, 34 insertions(+), 13 deletions(-)

diff --git a/sound/soc/sunxi/sun4i-i2s.c b/sound/soc/sunxi/sun4i-i2s.c
index 482fe0c65c1f..a389cdf8c4dc 100644
--- a/sound/soc/sunxi/sun4i-i2s.c
+++ b/sound/soc/sunxi/sun4i-i2s.c
@@ -50,6 +50,8 @@
 #define SUN4I_I2S_FMT0_FMT_RIGHT_J (2 << 0)
 #define SUN4I_I2S_FMT0_FMT_LEFT_J  (1 << 0)
 #define SUN4I_I2S_FMT0_FMT_I2S (0 << 0)
+#define SUN4I_I2S_FMT0_POLARITY_INVERTED   (1)
+#define SUN4I_I2S_FMT0_POLARITY_NORMAL (0)
 
 #define SUN4I_I2S_FMT1_REG 0x08
 #define SUN4I_I2S_FIFO_TX_REG  0x0c
@@ -101,6 +103,8 @@
  * @fmt_offset: Value by which wss and sr needs to be adjusted.
  * @field_fmt_wss: regmap field to set word select size.
  * @field_fmt_sr: regmap field to set sample resolution.
+ * @field_fmt_bclk: regmap field to set clk polarity.
+ * @field_fmt_lrclk: regmap field to set frame polarity.
  * @field_txchanmap: location of the tx channel mapping register.
  * @field_rxchanmap: location of the rx channel mapping register.
  * @field_txchansel: location of the tx channel select bit fields.
@@ -117,6 +121,8 @@ struct sun4i_i2s_quirks {
/* Register fields for i2s */
struct reg_fieldfield_fmt_wss;
struct reg_fieldfield_fmt_sr;
+   struct reg_fieldfield_fmt_bclk;
+   struct reg_fieldfield_fmt_lrclk;
struct reg_fieldfield_txchanmap;
struct reg_fieldfield_rxchanmap;
struct reg_fieldfield_txchansel;
@@ -137,6 +143,8 @@ struct sun4i_i2s {
/* Register fields for i2s */
struct regmap_field *field_fmt_wss;
struct regmap_field *field_fmt_sr;
+   struct regmap_field *field_fmt_bclk;
+   struct regmap_field *field_fmt_lrclk;
struct regmap_field *field_txchanmap;
struct regmap_field *field_rxchanmap;
struct regmap_field *field_txchansel;
@@ -335,6 +343,8 @@ static int sun4i_i2s_set_fmt(struct snd_soc_dai *dai, 
unsigned int fmt)
 {
struct sun4i_i2s *i2s = snd_soc_dai_get_drvdata(dai);
u32 val;
+   u32 bclk_polarity = SUN4I_I2S_FMT0_POLARITY_NORMAL;
+   u32 lrclk_polarity = SUN4I_I2S_FMT0_POLARITY_NORMAL;
 
/* DAI Mode */
switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
@@ -359,32 +369,25 @@ static int sun4i_i2s_set_fmt(struct snd_soc_dai *dai, 
unsigned int fmt)
switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
case SND_SOC_DAIFMT_IB_IF:
/* Invert both clocks */
-   val = SUN4I_I2S_FMT0_BCLK_POLARITY_INVERTED |
-   SUN4I_I2S_FMT0_LRCLK_POLARITY_INVERTED;
+   bclk_polarity = SUN4I_I2S_FMT0_POLARITY_INVERTED;
+   lrclk_polarity = SUN4I_I2S_FMT0_POLARITY_INVERTED;
break;
case SND_SOC_DAIFMT_IB_NF:
/* Invert bit clock */
-   val = SUN4I_I2S_FMT0_BCLK_POLARITY_INVERTED |
-   SUN4I_I2S_FMT0_LRCLK_POLARITY_NORMAL;
+   bclk_polarity = SUN4I_I2S_FMT0_POLARITY_INVERTED;
break;
case SND_SOC_DAIFMT_NB_IF:
/* Invert frame clock */
-   val = SUN4I_I2S_FMT0_LRCLK_POLARITY_INVERTED |
-   SUN4I_I2S_FMT0_BCLK_POLARITY_NORMAL;
+   lrclk_polarity = SUN4I_I2S_FMT0_POLARITY_INVERTED;
break;
case SND_SOC_DAIFMT_NB_NF:
-   /* Nothing to do for both normal cases */
-   val = SUN4I_I2S_FMT0_BCLK_POLARITY_NORMAL |
-   SUN4I_I2S_FMT0_LRCLK_POLARITY_NORMAL;
break;
default:
return -EINVAL;
}
 
-   regmap_update_bits(i2s->regmap, SUN4I_I2S_FMT0_REG,
-  SUN4I_I2S_FMT0_BCLK_POLARITY_MASK |
-  SUN4I_I2S_FMT0_LRCLK_POLARITY_MASK,
-  val);
+   regmap_field_write(i2s->field_fmt_bclk, bclk_polarity);
+   regmap_field_write(i2s->field_fmt_lrclk, lrclk_polarity);
 
/* DAI clock master masks */
switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
@@ -712,6 +715,8 @@ static const struct sun4i_i2s_quirks sun4i_a10_i2s_quirks = 
{
.sun4i_i2s_regmap   = _i2s_regmap_config,
.field_fmt_wss  = REG_FIELD(SUN4I_I2S_FMT0_REG, 2, 3),
.field_fmt_sr   = REG_FIELD(SUN4I_I2S_FMT0_REG, 4, 5),
+   .field_fmt_bclk = REG_FIELD(SUN4I_I2S_FMT0_REG, 6, 6),
+   .field_fmt_lrclk= 

[PATCH v3 10/11] ASoC: sun4i-i2s: Update global enable with bitmask

2017-08-12 Thread codekipper
From: Marcus Cooper 

The default value of the config register is different on newer
SoCs and therefore enabling/disabling with a register write
will clear bits used to set the direction of the clock and frame
pins.

Signed-off-by: Marcus Cooper 
Reviewed-by: Chen-Yu Tsai 
---
 sound/soc/sunxi/sun4i-i2s.c | 7 ---
 1 file changed, 4 insertions(+), 3 deletions(-)

diff --git a/sound/soc/sunxi/sun4i-i2s.c b/sound/soc/sunxi/sun4i-i2s.c
index 475572e1c586..a6b464c8cc6c 100644
--- a/sound/soc/sunxi/sun4i-i2s.c
+++ b/sound/soc/sunxi/sun4i-i2s.c
@@ -529,8 +529,8 @@ static int sun4i_i2s_startup(struct snd_pcm_substream 
*substream,
struct sun4i_i2s *i2s = snd_soc_dai_get_drvdata(dai);
 
/* Enable the whole hardware block */
-   regmap_write(i2s->regmap, SUN4I_I2S_CTRL_REG,
-SUN4I_I2S_CTRL_GL_EN);
+   regmap_update_bits(i2s->regmap, SUN4I_I2S_CTRL_REG,
+  SUN4I_I2S_CTRL_GL_EN, SUN4I_I2S_CTRL_GL_EN);
 
/* Enable the first output line */
regmap_update_bits(i2s->regmap, SUN4I_I2S_CTRL_REG,
@@ -553,7 +553,8 @@ static void sun4i_i2s_shutdown(struct snd_pcm_substream 
*substream,
   SUN4I_I2S_CTRL_SDO_EN_MASK, 0);
 
/* Disable the whole hardware block */
-   regmap_write(i2s->regmap, SUN4I_I2S_CTRL_REG, 0);
+   regmap_update_bits(i2s->regmap, SUN4I_I2S_CTRL_REG,
+  SUN4I_I2S_CTRL_GL_EN, 0);
 }
 
 static int sun4i_i2s_set_sysclk(struct snd_soc_dai *dai, int clk_id,
-- 
2.14.1



[PATCH v3 01/11] ASoC: sun4i-i2s: Add clkdiv offsets to quirks

2017-08-12 Thread codekipper
From: Marcus Cooper 

The BCLKDIV and MCLKDIV found on newer SoCs start from an offset of 1.
Add the functionality to adjust the division values according to the
needs to the device being used.

Signed-off-by: Marcus Cooper 
---
 sound/soc/sunxi/sun4i-i2s.c | 8 
 1 file changed, 8 insertions(+)

diff --git a/sound/soc/sunxi/sun4i-i2s.c b/sound/soc/sunxi/sun4i-i2s.c
index d7ee7a443e4e..9a35313c4f9b 100644
--- a/sound/soc/sunxi/sun4i-i2s.c
+++ b/sound/soc/sunxi/sun4i-i2s.c
@@ -94,9 +94,13 @@
  * struct sun4i_i2s_quirks - Differences between SoC variants.
  *
  * @has_reset: SoC needs reset deasserted.
+ * @mclk_offset: Value by which mclkdiv needs to be adjusted.
+ * @bclk_offset: Value by which bclkdiv needs to be adjusted.
  */
 struct sun4i_i2s_quirks {
boolhas_reset;
+   unsigned intmclk_offset;
+   unsigned intbclk_offset;
 };
 
 struct sun4i_i2s {
@@ -237,6 +241,10 @@ static int sun4i_i2s_set_clk_rate(struct sun4i_i2s *i2s,
if (mclk_div < 0)
return -EINVAL;
 
+   /* Adjust the clock division values if needed */
+   bclk_div += i2s->variant->bclk_offset;
+   mclk_div += i2s->variant->mclk_offset;
+
regmap_write(i2s->regmap, SUN4I_I2S_CLK_DIV_REG,
 SUN4I_I2S_CLK_DIV_BCLK(bclk_div) |
 SUN4I_I2S_CLK_DIV_MCLK(mclk_div) |
-- 
2.14.1



[PATCH v3 09/11] ASoC: sun4i-i2s: Check for slave select bit

2017-08-12 Thread codekipper
From: Marcus Cooper 

The newer SoCs do not have this setting. Instead they set the pin
direction. Add a check to see if the bit is valid and if so set
it accordingly.

Signed-off-by: Marcus Cooper 
Reviewed-by: Chen-Yu Tsai 
---
 sound/soc/sunxi/sun4i-i2s.c | 37 +
 1 file changed, 21 insertions(+), 16 deletions(-)

diff --git a/sound/soc/sunxi/sun4i-i2s.c b/sound/soc/sunxi/sun4i-i2s.c
index b61ef87d0049..475572e1c586 100644
--- a/sound/soc/sunxi/sun4i-i2s.c
+++ b/sound/soc/sunxi/sun4i-i2s.c
@@ -96,6 +96,7 @@
  * struct sun4i_i2s_quirks - Differences between SoC variants.
  *
  * @has_reset: SoC needs reset deasserted.
+ * @has_slave_select_bit: SoC has a bit to enable slave mode.
  * @reg_offset_txdata: offset of the tx fifo.
  * @sun4i_i2s_regmap: regmap config to use.
  * @mclk_offset: Value by which mclkdiv needs to be adjusted.
@@ -114,6 +115,7 @@
  */
 struct sun4i_i2s_quirks {
boolhas_reset;
+   boolhas_slave_select_bit;
unsigned intreg_offset_txdata;  /* TX FIFO */
const struct regmap_config  *sun4i_i2s_regmap;
unsigned intmclk_offset;
@@ -394,24 +396,25 @@ static int sun4i_i2s_set_fmt(struct snd_soc_dai *dai, 
unsigned int fmt)
regmap_field_write(i2s->field_fmt_bclk, bclk_polarity);
regmap_field_write(i2s->field_fmt_lrclk, lrclk_polarity);
 
-   /* DAI clock master masks */
-   switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
-   case SND_SOC_DAIFMT_CBS_CFS:
-   /* BCLK and LRCLK master */
-   val = SUN4I_I2S_CTRL_MODE_MASTER;
-   break;
-   case SND_SOC_DAIFMT_CBM_CFM:
-   /* BCLK and LRCLK slave */
-   val = SUN4I_I2S_CTRL_MODE_SLAVE;
-   break;
-   default:
-   return -EINVAL;
+   if (i2s->variant->has_slave_select_bit) {
+   /* DAI clock master masks */
+   switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+   case SND_SOC_DAIFMT_CBS_CFS:
+   /* BCLK and LRCLK master */
+   val = SUN4I_I2S_CTRL_MODE_MASTER;
+   break;
+   case SND_SOC_DAIFMT_CBM_CFM:
+   /* BCLK and LRCLK slave */
+   val = SUN4I_I2S_CTRL_MODE_SLAVE;
+   break;
+   default:
+   return -EINVAL;
+   }
+   regmap_update_bits(i2s->regmap, SUN4I_I2S_CTRL_REG,
+  SUN4I_I2S_CTRL_MODE_MASK,
+  val);
}
 
-   regmap_update_bits(i2s->regmap, SUN4I_I2S_CTRL_REG,
-  SUN4I_I2S_CTRL_MODE_MASK,
-  val);
-
/* Set significant bits in our FIFOs */
regmap_update_bits(i2s->regmap, SUN4I_I2S_FIFO_CTRL_REG,
   SUN4I_I2S_FIFO_CTRL_TX_MODE_MASK |
@@ -723,6 +726,7 @@ static const struct sun4i_i2s_quirks sun4i_a10_i2s_quirks = 
{
.field_fmt_sr   = REG_FIELD(SUN4I_I2S_FMT0_REG, 4, 5),
.field_fmt_bclk = REG_FIELD(SUN4I_I2S_FMT0_REG, 6, 6),
.field_fmt_lrclk= REG_FIELD(SUN4I_I2S_FMT0_REG, 7, 7),
+   .has_slave_select_bit   = true,
.field_fmt_mode = REG_FIELD(SUN4I_I2S_FMT0_REG, 0, 1),
.field_txchanmap= REG_FIELD(SUN4I_I2S_TX_CHAN_MAP_REG, 0, 31),
.field_rxchanmap= REG_FIELD(SUN4I_I2S_RX_CHAN_MAP_REG, 0, 31),
@@ -739,6 +743,7 @@ static const struct sun4i_i2s_quirks sun6i_a31_i2s_quirks = 
{
.field_fmt_sr   = REG_FIELD(SUN4I_I2S_FMT0_REG, 4, 5),
.field_fmt_bclk = REG_FIELD(SUN4I_I2S_FMT0_REG, 6, 6),
.field_fmt_lrclk= REG_FIELD(SUN4I_I2S_FMT0_REG, 7, 7),
+   .has_slave_select_bit   = true,
.field_fmt_mode = REG_FIELD(SUN4I_I2S_FMT0_REG, 0, 1),
.field_txchanmap= REG_FIELD(SUN4I_I2S_TX_CHAN_MAP_REG, 0, 31),
.field_rxchanmap= REG_FIELD(SUN4I_I2S_RX_CHAN_MAP_REG, 0, 31),
-- 
2.14.1



[PATCH v3 03/11] ASoC: sun4i-i2s: Add TX FIFO offset to quirks

2017-08-12 Thread codekipper
From: Marcus Cooper 

It has been seen that the newer SoCs have a different TX FIFO
address. Add this to the quirks structure.

Signed-off-by: Marcus Cooper 
Reviewed-by: Chen-Yu Tsai 
---
 sound/soc/sunxi/sun4i-i2s.c | 7 ++-
 1 file changed, 6 insertions(+), 1 deletion(-)

diff --git a/sound/soc/sunxi/sun4i-i2s.c b/sound/soc/sunxi/sun4i-i2s.c
index f6f3c409f25e..dfb79492 100644
--- a/sound/soc/sunxi/sun4i-i2s.c
+++ b/sound/soc/sunxi/sun4i-i2s.c
@@ -94,12 +94,14 @@
  * struct sun4i_i2s_quirks - Differences between SoC variants.
  *
  * @has_reset: SoC needs reset deasserted.
+ * @reg_offset_txdata: offset of the tx fifo.
  * @sun4i_i2s_regmap: regmap config to use.
  * @mclk_offset: Value by which mclkdiv needs to be adjusted.
  * @bclk_offset: Value by which bclkdiv needs to be adjusted.
  */
 struct sun4i_i2s_quirks {
boolhas_reset;
+   unsigned intreg_offset_txdata;  /* TX FIFO */
const struct regmap_config  *sun4i_i2s_regmap;
unsigned intmclk_offset;
unsigned intbclk_offset;
@@ -677,11 +679,13 @@ static int sun4i_i2s_runtime_suspend(struct device *dev)
 
 static const struct sun4i_i2s_quirks sun4i_a10_i2s_quirks = {
.has_reset  = false,
+   .reg_offset_txdata  = SUN4I_I2S_FIFO_TX_REG,
.sun4i_i2s_regmap   = _i2s_regmap_config,
 };
 
 static const struct sun4i_i2s_quirks sun6i_a31_i2s_quirks = {
.has_reset  = true,
+   .reg_offset_txdata  = SUN4I_I2S_FIFO_TX_REG,
.sun4i_i2s_regmap   = _i2s_regmap_config,
 };
 
@@ -750,7 +754,8 @@ static int sun4i_i2s_probe(struct platform_device *pdev)
}
}
 
-   i2s->playback_dma_data.addr = res->start + SUN4I_I2S_FIFO_TX_REG;
+   i2s->playback_dma_data.addr = res->start +
+   i2s->variant->reg_offset_txdata;
i2s->playback_dma_data.maxburst = 8;
 
i2s->capture_dma_data.addr = res->start + SUN4I_I2S_FIFO_RX_REG;
-- 
2.14.1



[PATCH v3 11/11] ASoC: sun4i-i2s: Add support for H3

2017-08-12 Thread codekipper
From: Marcus Cooper 

The sun8i-h3 introduces a lot of changes to the i2s block such
as different register locations, extended clock division and
more operational modes. As we have to consider the earlier
implementation then these changes need to be isolated.

None of the new functionality has been implemented yet, the
driver has just been expanded to allow it work on the H3 SoC.

Signed-off-by: Marcus Cooper 
---
 .../devicetree/bindings/sound/sun4i-i2s.txt|   2 +
 sound/soc/sunxi/sun4i-i2s.c| 176 -
 2 files changed, 176 insertions(+), 2 deletions(-)

diff --git a/Documentation/devicetree/bindings/sound/sun4i-i2s.txt 
b/Documentation/devicetree/bindings/sound/sun4i-i2s.txt
index ee21da865771..fc5da6080759 100644
--- a/Documentation/devicetree/bindings/sound/sun4i-i2s.txt
+++ b/Documentation/devicetree/bindings/sound/sun4i-i2s.txt
@@ -8,6 +8,7 @@ Required properties:
 - compatible: should be one of the following:
- "allwinner,sun4i-a10-i2s"
- "allwinner,sun6i-a31-i2s"
+   - "allwinner,sun8i-h3-i2s"
 - reg: physical base address of the controller and length of memory mapped
   region.
 - interrupts: should contain the I2S interrupt.
@@ -22,6 +23,7 @@ Required properties:
 
 Required properties for the following compatibles:
- "allwinner,sun6i-a31-i2s"
+   - "allwinner,sun8i-h3-i2s"
 - resets: phandle to the reset line for this codec
 
 Example:
diff --git a/sound/soc/sunxi/sun4i-i2s.c b/sound/soc/sunxi/sun4i-i2s.c
index a6b464c8cc6c..b6faa95d972a 100644
--- a/sound/soc/sunxi/sun4i-i2s.c
+++ b/sound/soc/sunxi/sun4i-i2s.c
@@ -92,11 +92,41 @@
 #define SUN4I_I2S_RX_CHAN_SEL_REG  0x38
 #define SUN4I_I2S_RX_CHAN_MAP_REG  0x3c
 
+/* Defines required for sun8i-h3 support */
+#define SUN8I_I2S_CTRL_BCLK_OUTBIT(18)
+#define SUN8I_I2S_CTRL_LRCK_OUTBIT(17)
+
+#define SUN8I_I2S_FMT0_LRCK_PERIOD_MASKGENMASK(17, 8)
+#define SUN8I_I2S_FMT0_LRCK_PERIOD(period) ((period << 8) - 1)
+
+#define SUN8I_I2S_INT_STA_REG  0x0c
+#define SUN8I_I2S_FIFO_TX_REG  0x20
+
+#define SUN8I_I2S_CHAN_CFG_REG 0x30
+#define SUN8I_I2S_CHAN_CFG_RX_SLOT_NUM_MASKGENMASK(6, 4)
+#define SUN8I_I2S_CHAN_CFG_RX_SLOT_NUM(chan)   (chan - 1)
+#define SUN8I_I2S_CHAN_CFG_TX_SLOT_NUM_MASKGENMASK(2, 0)
+#define SUN8I_I2S_CHAN_CFG_TX_SLOT_NUM(chan)   (chan - 1)
+
+#define SUN8I_I2S_TX_CHAN_MAP_REG  0x44
+#define SUN8I_I2S_TX_CHAN_SEL_REG  0x34
+#define SUN8I_I2S_TX_CHAN_OFFSET_MASK  GENMASK(13, 11)
+#define SUN8I_I2S_TX_CHAN_OFFSET(offset)   (offset << 12)
+#define SUN8I_I2S_TX_CHAN_EN_MASK  GENMASK(11, 4)
+#define SUN8I_I2S_TX_CHAN_EN(num_chan) (((1 << num_chan) - 1) << 4)
+
+#define SUN8I_I2S_RX_CHAN_SEL_REG  0x54
+#define SUN8I_I2S_RX_CHAN_MAP_REG  0x58
+
 /**
  * struct sun4i_i2s_quirks - Differences between SoC variants.
  *
  * @has_reset: SoC needs reset deasserted.
  * @has_slave_select_bit: SoC has a bit to enable slave mode.
+ * @has_fmt_set_lrck_period: SoC requires lrclk period to be set.
+ * @has_chcfg: tx and rx slot number need to be set.
+ * @has_chsel_tx_chen: SoC requires that the tx channels are enabled.
+ * @has_chsel_offset: SoC uses offset for selecting dai operational mode.
  * @reg_offset_txdata: offset of the tx fifo.
  * @sun4i_i2s_regmap: regmap config to use.
  * @mclk_offset: Value by which mclkdiv needs to be adjusted.
@@ -116,6 +146,10 @@
 struct sun4i_i2s_quirks {
boolhas_reset;
boolhas_slave_select_bit;
+   boolhas_fmt_set_lrck_period;
+   boolhas_chcfg;
+   boolhas_chsel_tx_chen;
+   boolhas_chsel_offset;
unsigned intreg_offset_txdata;  /* TX FIFO */
const struct regmap_config  *sun4i_i2s_regmap;
unsigned intmclk_offset;
@@ -173,6 +207,7 @@ static const struct sun4i_i2s_clk_div sun4i_i2s_bclk_div[] 
= {
{ .div = 8, .val = 3 },
{ .div = 12, .val = 4 },
{ .div = 16, .val = 5 },
+   /* TODO - extend divide ratio supported by newer SoCs */
 };
 
 static const struct sun4i_i2s_clk_div sun4i_i2s_mclk_div[] = {
@@ -184,6 +219,7 @@ static const struct sun4i_i2s_clk_div sun4i_i2s_mclk_div[] 
= {
{ .div = 12, .val = 5 },
{ .div = 16, .val = 6 },
{ .div = 24, .val = 7 },
+   /* TODO - extend divide ratio supported by newer SoCs */
 };
 
 static int sun4i_i2s_get_bclk_div(struct sun4i_i2s *i2s,
@@ -295,6 +331,12 @@ static int sun4i_i2s_set_clk_rate(struct sun4i_i2s *i2s,
 
regmap_field_write(i2s->field_clkdiv_mclk_en, 1);
 
+   /* Set sync period */
+   if (i2s->variant->has_fmt_set_lrck_period)
+   

[PATCH v3 05/11] ASoC: sun4i-i2s: Add regfields for word size select and sample resolution

2017-08-12 Thread codekipper
From: Marcus Cooper 

On newer SoCs the location of the slot width select and sample
resolution are different and also there is a bigger range of
support.

For the current supported rates then an offset is required.

Signed-off-by: Marcus Cooper 
Reviewed-by: Chen-Yu Tsai 
---
 sound/soc/sunxi/sun4i-i2s.c | 33 ++---
 1 file changed, 30 insertions(+), 3 deletions(-)

diff --git a/sound/soc/sunxi/sun4i-i2s.c b/sound/soc/sunxi/sun4i-i2s.c
index a65dcb013247..482fe0c65c1f 100644
--- a/sound/soc/sunxi/sun4i-i2s.c
+++ b/sound/soc/sunxi/sun4i-i2s.c
@@ -98,6 +98,9 @@
  * @sun4i_i2s_regmap: regmap config to use.
  * @mclk_offset: Value by which mclkdiv needs to be adjusted.
  * @bclk_offset: Value by which bclkdiv needs to be adjusted.
+ * @fmt_offset: Value by which wss and sr needs to be adjusted.
+ * @field_fmt_wss: regmap field to set word select size.
+ * @field_fmt_sr: regmap field to set sample resolution.
  * @field_txchanmap: location of the tx channel mapping register.
  * @field_rxchanmap: location of the rx channel mapping register.
  * @field_txchansel: location of the tx channel select bit fields.
@@ -109,8 +112,11 @@ struct sun4i_i2s_quirks {
const struct regmap_config  *sun4i_i2s_regmap;
unsigned intmclk_offset;
unsigned intbclk_offset;
+   unsigned intfmt_offset;
 
/* Register fields for i2s */
+   struct reg_fieldfield_fmt_wss;
+   struct reg_fieldfield_fmt_sr;
struct reg_fieldfield_txchanmap;
struct reg_fieldfield_rxchanmap;
struct reg_fieldfield_txchansel;
@@ -129,6 +135,8 @@ struct sun4i_i2s {
struct snd_dmaengine_dai_dma_data   playback_dma_data;
 
/* Register fields for i2s */
+   struct regmap_field *field_fmt_wss;
+   struct regmap_field *field_fmt_sr;
struct regmap_field *field_txchanmap;
struct regmap_field *field_rxchanmap;
struct regmap_field *field_txchansel;
@@ -314,9 +322,10 @@ static int sun4i_i2s_hw_params(struct snd_pcm_substream 
*substream,
return -EINVAL;
}
 
-   regmap_update_bits(i2s->regmap, SUN4I_I2S_FMT0_REG,
-  SUN4I_I2S_FMT0_WSS_MASK | SUN4I_I2S_FMT0_SR_MASK,
-  SUN4I_I2S_FMT0_WSS(wss) | SUN4I_I2S_FMT0_SR(sr));
+   regmap_field_write(i2s->field_fmt_wss,
+  wss + i2s->variant->fmt_offset);
+   regmap_field_write(i2s->field_fmt_sr,
+  sr + i2s->variant->fmt_offset);
 
return sun4i_i2s_set_clk_rate(i2s, params_rate(params),
  params_width(params));
@@ -701,6 +710,8 @@ static const struct sun4i_i2s_quirks sun4i_a10_i2s_quirks = 
{
.has_reset  = false,
.reg_offset_txdata  = SUN4I_I2S_FIFO_TX_REG,
.sun4i_i2s_regmap   = _i2s_regmap_config,
+   .field_fmt_wss  = REG_FIELD(SUN4I_I2S_FMT0_REG, 2, 3),
+   .field_fmt_sr   = REG_FIELD(SUN4I_I2S_FMT0_REG, 4, 5),
.field_txchanmap= REG_FIELD(SUN4I_I2S_TX_CHAN_MAP_REG, 0, 31),
.field_rxchanmap= REG_FIELD(SUN4I_I2S_RX_CHAN_MAP_REG, 0, 31),
.field_txchansel= REG_FIELD(SUN4I_I2S_TX_CHAN_SEL_REG, 0, 2),
@@ -711,6 +722,8 @@ static const struct sun4i_i2s_quirks sun6i_a31_i2s_quirks = 
{
.has_reset  = true,
.reg_offset_txdata  = SUN4I_I2S_FIFO_TX_REG,
.sun4i_i2s_regmap   = _i2s_regmap_config,
+   .field_fmt_wss  = REG_FIELD(SUN4I_I2S_FMT0_REG, 2, 3),
+   .field_fmt_sr   = REG_FIELD(SUN4I_I2S_FMT0_REG, 4, 5),
.field_txchanmap= REG_FIELD(SUN4I_I2S_TX_CHAN_MAP_REG, 0, 31),
.field_rxchanmap= REG_FIELD(SUN4I_I2S_RX_CHAN_MAP_REG, 0, 31),
.field_txchansel= REG_FIELD(SUN4I_I2S_TX_CHAN_SEL_REG, 0, 2),
@@ -748,6 +761,20 @@ static int sun4i_i2s_init_regmap_fields(struct device *dev,
ret = PTR_ERR_OR_ZERO(i2s->field_rxchansel);
}
 
+   if (!ret) {
+   i2s->field_fmt_wss =
+   devm_regmap_field_alloc(dev, i2s->regmap,
+   i2s->variant->field_fmt_wss);
+   ret = PTR_ERR_OR_ZERO(i2s->field_fmt_wss);
+   }
+
+   if (!ret) {
+   i2s->field_fmt_sr =
+   devm_regmap_field_alloc(dev, i2s->regmap,
+   i2s->variant->field_fmt_sr);
+   ret = PTR_ERR_OR_ZERO(i2s->field_fmt_sr);
+   }
+
return ret;
 }
 
-- 
2.14.1



[PATCH v3 07/11] ASoC: sun4i-i2s: Add mclk enable regmap field

2017-08-12 Thread codekipper
From: Marcus Cooper 

The location of the mclk output enable bit is different on newer
SoCs. Use a regmap field to enable it.

Signed-off-by: Marcus Cooper 
---
 sound/soc/sunxi/sun4i-i2s.c | 23 ++-
 1 file changed, 18 insertions(+), 5 deletions(-)

diff --git a/sound/soc/sunxi/sun4i-i2s.c b/sound/soc/sunxi/sun4i-i2s.c
index a389cdf8c4dc..33af99076d62 100644
--- a/sound/soc/sunxi/sun4i-i2s.c
+++ b/sound/soc/sunxi/sun4i-i2s.c
@@ -101,6 +101,7 @@
  * @mclk_offset: Value by which mclkdiv needs to be adjusted.
  * @bclk_offset: Value by which bclkdiv needs to be adjusted.
  * @fmt_offset: Value by which wss and sr needs to be adjusted.
+ * @field_clkdiv_mclk_en: regmap field to enable mclk output.
  * @field_fmt_wss: regmap field to set word select size.
  * @field_fmt_sr: regmap field to set sample resolution.
  * @field_fmt_bclk: regmap field to set clk polarity.
@@ -119,6 +120,7 @@ struct sun4i_i2s_quirks {
unsigned intfmt_offset;
 
/* Register fields for i2s */
+   struct reg_fieldfield_clkdiv_mclk_en;
struct reg_fieldfield_fmt_wss;
struct reg_fieldfield_fmt_sr;
struct reg_fieldfield_fmt_bclk;
@@ -141,6 +143,7 @@ struct sun4i_i2s {
struct snd_dmaengine_dai_dma_data   playback_dma_data;
 
/* Register fields for i2s */
+   struct regmap_field *field_clkdiv_mclk_en;
struct regmap_field *field_fmt_wss;
struct regmap_field *field_fmt_sr;
struct regmap_field *field_fmt_bclk;
@@ -283,8 +286,9 @@ static int sun4i_i2s_set_clk_rate(struct sun4i_i2s *i2s,
 
regmap_write(i2s->regmap, SUN4I_I2S_CLK_DIV_REG,
 SUN4I_I2S_CLK_DIV_BCLK(bclk_div) |
-SUN4I_I2S_CLK_DIV_MCLK(mclk_div) |
-SUN4I_I2S_CLK_DIV_MCLK_EN);
+SUN4I_I2S_CLK_DIV_MCLK(mclk_div));
+
+   regmap_field_write(i2s->field_clkdiv_mclk_en, 1);
 
return 0;
 }
@@ -713,6 +717,7 @@ static const struct sun4i_i2s_quirks sun4i_a10_i2s_quirks = 
{
.has_reset  = false,
.reg_offset_txdata  = SUN4I_I2S_FIFO_TX_REG,
.sun4i_i2s_regmap   = _i2s_regmap_config,
+   .field_clkdiv_mclk_en   = REG_FIELD(SUN4I_I2S_CLK_DIV_REG, 7, 7),
.field_fmt_wss  = REG_FIELD(SUN4I_I2S_FMT0_REG, 2, 3),
.field_fmt_sr   = REG_FIELD(SUN4I_I2S_FMT0_REG, 4, 5),
.field_fmt_bclk = REG_FIELD(SUN4I_I2S_FMT0_REG, 6, 6),
@@ -727,6 +732,7 @@ static const struct sun4i_i2s_quirks sun6i_a31_i2s_quirks = 
{
.has_reset  = true,
.reg_offset_txdata  = SUN4I_I2S_FIFO_TX_REG,
.sun4i_i2s_regmap   = _i2s_regmap_config,
+   .field_clkdiv_mclk_en   = REG_FIELD(SUN4I_I2S_CLK_DIV_REG, 7, 7),
.field_fmt_wss  = REG_FIELD(SUN4I_I2S_FMT0_REG, 2, 3),
.field_fmt_sr   = REG_FIELD(SUN4I_I2S_FMT0_REG, 4, 5),
.field_fmt_bclk = REG_FIELD(SUN4I_I2S_FMT0_REG, 6, 6),
@@ -742,10 +748,17 @@ static int sun4i_i2s_init_regmap_fields(struct device 
*dev,
 {
int ret;
 
-   i2s->field_txchanmap =
+   i2s->field_clkdiv_mclk_en =
devm_regmap_field_alloc(dev, i2s->regmap,
-   i2s->variant->field_txchanmap);
-   ret = PTR_ERR_OR_ZERO(i2s->field_txchanmap);
+   i2s->variant->field_clkdiv_mclk_en);
+   ret = PTR_ERR_OR_ZERO(i2s->field_clkdiv_mclk_en);
+
+   if (!ret) {
+   i2s->field_txchanmap =
+   devm_regmap_field_alloc(dev, i2s->regmap,
+   i2s->variant->field_txchanmap);
+   ret = PTR_ERR_OR_ZERO(i2s->field_txchanmap);
+   }
 
if (!ret) {
i2s->field_rxchanmap =
-- 
2.14.1



[PATCH v3 02/11] ASoC: sun4i-i2s: Add regmap config to quirks

2017-08-12 Thread codekipper
From: Marcus Cooper 

The newer SoCs have a larger range than the original SoC that this
driver was developed for. By adding the regmap config to the quirks
then the driver can initialise the managed register map correctly.

Signed-off-by: Marcus Cooper 
Reviewed-by: Chen-Yu Tsai 
---
 sound/soc/sunxi/sun4i-i2s.c | 10 +++---
 1 file changed, 7 insertions(+), 3 deletions(-)

diff --git a/sound/soc/sunxi/sun4i-i2s.c b/sound/soc/sunxi/sun4i-i2s.c
index 9a35313c4f9b..f6f3c409f25e 100644
--- a/sound/soc/sunxi/sun4i-i2s.c
+++ b/sound/soc/sunxi/sun4i-i2s.c
@@ -94,11 +94,13 @@
  * struct sun4i_i2s_quirks - Differences between SoC variants.
  *
  * @has_reset: SoC needs reset deasserted.
+ * @sun4i_i2s_regmap: regmap config to use.
  * @mclk_offset: Value by which mclkdiv needs to be adjusted.
  * @bclk_offset: Value by which bclkdiv needs to be adjusted.
  */
 struct sun4i_i2s_quirks {
boolhas_reset;
+   const struct regmap_config  *sun4i_i2s_regmap;
unsigned intmclk_offset;
unsigned intbclk_offset;
 };
@@ -674,11 +676,13 @@ static int sun4i_i2s_runtime_suspend(struct device *dev)
 }
 
 static const struct sun4i_i2s_quirks sun4i_a10_i2s_quirks = {
-   .has_reset  = false,
+   .has_reset  = false,
+   .sun4i_i2s_regmap   = _i2s_regmap_config,
 };
 
 static const struct sun4i_i2s_quirks sun6i_a31_i2s_quirks = {
-   .has_reset  = true,
+   .has_reset  = true,
+   .sun4i_i2s_regmap   = _i2s_regmap_config,
 };
 
 static int sun4i_i2s_probe(struct platform_device *pdev)
@@ -717,7 +721,7 @@ static int sun4i_i2s_probe(struct platform_device *pdev)
}
 
i2s->regmap = devm_regmap_init_mmio(>dev, regs,
-   _i2s_regmap_config);
+   i2s->variant->sun4i_i2s_regmap);
if (IS_ERR(i2s->regmap)) {
dev_err(>dev, "Regmap initialisation failed\n");
return PTR_ERR(i2s->regmap);
-- 
2.14.1



[PATCH v3 00/11] ASoC: Add I2S support for Allwinner H3 SoCs

2017-08-12 Thread codekipper
From: Marcus Cooper <codekip...@gmail.com>

Hi All,
please find attached a series of patches to bring i2s support to the
Allwinner H3 SoC. This has been tested with the following setups:

A20 Olimex EVB connected to a pcm5102
Orange Pi 2 connected to a uda1380
Orange Pi 2 hdmi audio playback
Pine 64 connected to the audio DAC board

To get i2s working some additional patches are required which will be
delivered later. For now they have been pushed here

https://github.com/codekipper/linux-sunxi/commits/sunxi-audio-h3

I don't own a A33 device which uses the i2s block for the audio codec
so if someone could test against that it would be much appreciated.

I'm also wondering if there is a preferred way of setting the lrclk
size in the dts?..currently it is set to the sample width but for example
the pcm5102a wants it to be 32 bits whatever the sample rate.

Thanks in advance,
CK

---

v4 changes compared to v3 are:
- moved clkdiv variant adjustment out of function
- used PTR_ERR_OR_ZERO for checks
- tidy up of extra lines and lines over 80 chars.
- reduced names of polarity, wss and sr reg fields.
- added reviewed-by to commit messages
- added comments for functionality that hasn't been implemented yet.

v3 changes compared to v2 are:
- initial changes to prepare driver for newer SoCs has been broken down
  into smaller patches
- reduce use of regmap fields to where just needed.
- clkdiv expansion will be delivered later.
- defines for H3 variant segregated.
- fixed regmap config issue with SUN8I_I2S_FIFO_TX_REG.


v2 changes compared to v1 are:
 - massive refactoring to remove duplicate code making use of regmap_fields.
 - extending the clock divisors.
 - removed code that should be delivered when we support 20/24bits

---

Marcus Cooper (11):
  ASoC: sun4i-i2s: Add clkdiv offsets to quirks
  ASoC: sun4i-i2s: Add regmap config to quirks
  ASoC: sun4i-i2s: Add TX FIFO offset to quirks
  ASoC: sun4i-i2s: Add regmap fields for channels
  ASoC: sun4i-i2s: Add regfields for word size select and sample
resolution
  ASoC: sun4i-i2s: bclk and lrclk polarity tidyup
  ASoC: sun4i-i2s: Add mclk enable regmap field
  ASoC: sun4i-i2s: Add regmap field to set DAI format
  ASoC: sun4i-i2s: Check for slave select bit
  ASoC: sun4i-i2s: Update global enable with bitmask
  ASoC: sun4i-i2s: Add support for H3

 .../devicetree/bindings/sound/sun4i-i2s.txt|   2 +
 sound/soc/sunxi/sun4i-i2s.c| 444 ++---
 2 files changed, 391 insertions(+), 55 deletions(-)

-- 
2.14.1



[PATCH v3 04/11] ASoC: sun4i-i2s: Add regmap fields for channels

2017-08-12 Thread codekipper
From: Marcus Cooper 

On the original i2s block the channel mapping and selection were
configured for stereo audio by default: This is not the case with
the newer SoCs and they are also located at different offsets.

To support the newer SoC then regmap fields have been added to the
quirks and these are initialised to their correct settings during
probing.

Signed-off-by: Marcus Cooper 
Reviewed-by: Chen-Yu Tsai 
---
 sound/soc/sunxi/sun4i-i2s.c | 84 -
 1 file changed, 76 insertions(+), 8 deletions(-)

diff --git a/sound/soc/sunxi/sun4i-i2s.c b/sound/soc/sunxi/sun4i-i2s.c
index dfb79492..a65dcb013247 100644
--- a/sound/soc/sunxi/sun4i-i2s.c
+++ b/sound/soc/sunxi/sun4i-i2s.c
@@ -82,7 +82,7 @@
 #define SUN4I_I2S_TX_CNT_REG   0x2c
 
 #define SUN4I_I2S_TX_CHAN_SEL_REG  0x30
-#define SUN4I_I2S_TX_CHAN_SEL(num_chan)(((num_chan) - 1) << 0)
+#define SUN4I_I2S_CHAN_SEL(num_chan)   (((num_chan) - 1) << 0)
 
 #define SUN4I_I2S_TX_CHAN_MAP_REG  0x34
 #define SUN4I_I2S_TX_CHAN_MAP(chan, sample)((sample) << (chan << 2))
@@ -98,6 +98,10 @@
  * @sun4i_i2s_regmap: regmap config to use.
  * @mclk_offset: Value by which mclkdiv needs to be adjusted.
  * @bclk_offset: Value by which bclkdiv needs to be adjusted.
+ * @field_txchanmap: location of the tx channel mapping register.
+ * @field_rxchanmap: location of the rx channel mapping register.
+ * @field_txchansel: location of the tx channel select bit fields.
+ * @field_rxchansel: location of the rx channel select bit fields.
  */
 struct sun4i_i2s_quirks {
boolhas_reset;
@@ -105,6 +109,12 @@ struct sun4i_i2s_quirks {
const struct regmap_config  *sun4i_i2s_regmap;
unsigned intmclk_offset;
unsigned intbclk_offset;
+
+   /* Register fields for i2s */
+   struct reg_fieldfield_txchanmap;
+   struct reg_fieldfield_rxchanmap;
+   struct reg_fieldfield_txchansel;
+   struct reg_fieldfield_rxchansel;
 };
 
 struct sun4i_i2s {
@@ -118,6 +128,12 @@ struct sun4i_i2s {
struct snd_dmaengine_dai_dma_data   capture_dma_data;
struct snd_dmaengine_dai_dma_data   playback_dma_data;
 
+   /* Register fields for i2s */
+   struct regmap_field *field_txchanmap;
+   struct regmap_field *field_rxchanmap;
+   struct regmap_field *field_txchansel;
+   struct regmap_field *field_rxchansel;
+
const struct sun4i_i2s_quirks   *variant;
 };
 
@@ -268,6 +284,17 @@ static int sun4i_i2s_hw_params(struct snd_pcm_substream 
*substream,
if (params_channels(params) != 2)
return -EINVAL;
 
+   /* Map the channels for playback and capture */
+   regmap_field_write(i2s->field_txchanmap, 0x76543210);
+   regmap_field_write(i2s->field_rxchanmap, 0x3210);
+
+   /* Configure the channels */
+   regmap_field_write(i2s->field_txchansel,
+  SUN4I_I2S_CHAN_SEL(params_channels(params)));
+
+   regmap_field_write(i2s->field_rxchansel,
+  SUN4I_I2S_CHAN_SEL(params_channels(params)));
+
switch (params_physical_width(params)) {
case 16:
width = DMA_SLAVE_BUSWIDTH_2_BYTES;
@@ -490,13 +517,6 @@ static int sun4i_i2s_startup(struct snd_pcm_substream 
*substream,
   SUN4I_I2S_CTRL_SDO_EN_MASK,
   SUN4I_I2S_CTRL_SDO_EN(0));
 
-   /* Enable the first two channels */
-   regmap_write(i2s->regmap, SUN4I_I2S_TX_CHAN_SEL_REG,
-SUN4I_I2S_TX_CHAN_SEL(2));
-
-   /* Map them to the two first samples coming in */
-   regmap_write(i2s->regmap, SUN4I_I2S_TX_CHAN_MAP_REG,
-SUN4I_I2S_TX_CHAN_MAP(0, 0) | SUN4I_I2S_TX_CHAN_MAP(1, 1));
 
return clk_prepare_enable(i2s->mod_clk);
 }
@@ -681,14 +701,56 @@ static const struct sun4i_i2s_quirks sun4i_a10_i2s_quirks 
= {
.has_reset  = false,
.reg_offset_txdata  = SUN4I_I2S_FIFO_TX_REG,
.sun4i_i2s_regmap   = _i2s_regmap_config,
+   .field_txchanmap= REG_FIELD(SUN4I_I2S_TX_CHAN_MAP_REG, 0, 31),
+   .field_rxchanmap= REG_FIELD(SUN4I_I2S_RX_CHAN_MAP_REG, 0, 31),
+   .field_txchansel= REG_FIELD(SUN4I_I2S_TX_CHAN_SEL_REG, 0, 2),
+   .field_rxchansel= REG_FIELD(SUN4I_I2S_RX_CHAN_SEL_REG, 0, 2),
 };
 
 static const struct sun4i_i2s_quirks sun6i_a31_i2s_quirks = {
.has_reset  = true,
.reg_offset_txdata  = SUN4I_I2S_FIFO_TX_REG,
.sun4i_i2s_regmap   = _i2s_regmap_config,
+   .field_txchanmap= REG_FIELD(SUN4I_I2S_TX_CHAN_MAP_REG, 0, 31),
+   .field_rxchanmap= REG_FIELD(SUN4I_I2S_RX_CHAN_MAP_REG, 0, 31),
+   

[PATCH v2 1/2] ASoC: sun4i-i2s: Add more quirks for newer SoCs

2017-07-22 Thread codekipper
From: Marcus Cooper 

In preparation for changing this driver to support newer SoC
implementations then where needed there has been a switch from
regmap_update_bits to regmap_field. Also included are adjustment
variables although they are not set as no adjustment is required
for the current support.

Signed-off-by: Marcus Cooper 
---
 sound/soc/sunxi/sun4i-i2s.c | 267 +---
 1 file changed, 203 insertions(+), 64 deletions(-)

diff --git a/sound/soc/sunxi/sun4i-i2s.c b/sound/soc/sunxi/sun4i-i2s.c
index 62b307b0c846..1854405cbcb1 100644
--- a/sound/soc/sunxi/sun4i-i2s.c
+++ b/sound/soc/sunxi/sun4i-i2s.c
@@ -50,6 +50,8 @@
 #define SUN4I_I2S_FMT0_FMT_RIGHT_J (2 << 0)
 #define SUN4I_I2S_FMT0_FMT_LEFT_J  (1 << 0)
 #define SUN4I_I2S_FMT0_FMT_I2S (0 << 0)
+#define SUN4I_I2S_FMT0_POLARITY_INVERTED   (1)
+#define SUN4I_I2S_FMT0_POLARITY_NORMAL (0)
 
 #define SUN4I_I2S_FMT1_REG 0x08
 #define SUN4I_I2S_FIFO_TX_REG  0x0c
@@ -72,7 +74,7 @@
 #define SUN4I_I2S_INT_STA_REG  0x20
 
 #define SUN4I_I2S_CLK_DIV_REG  0x24
-#define SUN4I_I2S_CLK_DIV_MCLK_EN  BIT(7)
+#define SUN4I_I2S_CLK_DIV_MCLK_EN  7
 #define SUN4I_I2S_CLK_DIV_BCLK_MASKGENMASK(6, 4)
 #define SUN4I_I2S_CLK_DIV_BCLK(bclk)   ((bclk) << 4)
 #define SUN4I_I2S_CLK_DIV_MCLK_MASKGENMASK(3, 0)
@@ -82,15 +84,39 @@
 #define SUN4I_I2S_TX_CNT_REG   0x2c
 
 #define SUN4I_I2S_TX_CHAN_SEL_REG  0x30
-#define SUN4I_I2S_TX_CHAN_SEL(num_chan)(((num_chan) - 1) << 0)
+#define SUN4I_I2S_CHAN_SEL(num_chan)   (((num_chan) - 1) << 0)
 
 #define SUN4I_I2S_TX_CHAN_MAP_REG  0x34
 #define SUN4I_I2S_TX_CHAN_MAP(chan, sample)((sample) << (chan << 2))
+#define SUN4I_I2S_TX_CHAN_EN(num_chan) (((1 << num_chan) - 1))
 
 #define SUN4I_I2S_RX_CHAN_SEL_REG  0x38
 #define SUN4I_I2S_RX_CHAN_MAP_REG  0x3c
 
+struct sun4i_i2s_quirks {
+   boolhas_reset;
+   boolhas_master_slave_sel;
+   unsigned intreg_offset_txdata;  /* TX FIFO */
+   unsigned intreg_offset_txchanmap;
+   unsigned intreg_offset_rxchanmap;
+   const struct regmap_config  *sun4i_i2s_regmap;
+   unsigned intmclk_adjust;
+   unsigned intbclk_adjust;
+   unsigned intfmt_adjust;
+
+   /* Register fields for i2s */
+   struct reg_fieldfield_clkdiv_mclk_en;
+   struct reg_fieldfield_fmt_set_wss;
+   struct reg_fieldfield_fmt_set_sr;
+   struct reg_fieldfield_fmt_set_bclk_polarity;
+   struct reg_fieldfield_fmt_set_lrclk_polarity;
+   struct reg_fieldfield_fmt_set_mode;
+   struct reg_fieldfield_txchansel;
+   struct reg_fieldfield_rxchansel;
+};
+
 struct sun4i_i2s {
+   struct device   *dev;
struct clk  *bus_clk;
struct clk  *mod_clk;
struct regmap   *regmap;
@@ -100,6 +126,18 @@ struct sun4i_i2s {
 
struct snd_dmaengine_dai_dma_data   capture_dma_data;
struct snd_dmaengine_dai_dma_data   playback_dma_data;
+
+   /* Register fields for i2s */
+   struct regmap_field *field_clkdiv_mclk_en;
+   struct regmap_field *field_fmt_set_wss;
+   struct regmap_field *field_fmt_set_sr;
+   struct regmap_field *field_fmt_set_bclk_polarity;
+   struct regmap_field *field_fmt_set_lrclk_polarity;
+   struct regmap_field *field_fmt_set_mode;
+   struct regmap_field *field_txchansel;
+   struct regmap_field *field_rxchansel;
+
+   const struct sun4i_i2s_quirks   *variant;
 };
 
 struct sun4i_i2s_clk_div {
@@ -138,7 +176,7 @@ static int sun4i_i2s_get_bclk_div(struct sun4i_i2s *i2s,
const struct sun4i_i2s_clk_div *bdiv = _i2s_bclk_div[i];
 
if (bdiv->div == div)
-   return bdiv->val;
+   return bdiv->val + i2s->variant->bclk_adjust;
}
 
return -EINVAL;
@@ -156,7 +194,7 @@ static int sun4i_i2s_get_mclk_div(struct sun4i_i2s *i2s,
const struct sun4i_i2s_clk_div *mdiv = _i2s_mclk_div[i];
 
if (mdiv->div == div)
-   return mdiv->val;
+   return mdiv->val + i2s->variant->mclk_adjust;
}
 
return -EINVAL;
@@ -228,8 +266,9 @@ static int sun4i_i2s_set_clk_rate(struct sun4i_i2s *i2s,
 
regmap_write(i2s->regmap, SUN4I_I2S_CLK_DIV_REG,
 SUN4I_I2S_CLK_DIV_BCLK(bclk_div) |
-SUN4I_I2S_CLK_DIV_MCLK(mclk_div) |
-

[PATCH v2 2/2] ASoC: sun4i-i2s: Add support for H3

2017-07-22 Thread codekipper
From: Marcus Cooper 

The sun8i-h3 introduces a lot of changes to the i2s block such
as different register locations, extended clock division and
more operational modes. As we have to consider the earlier
implementation then these changes need to be isolated.

Signed-off-by: Marcus Cooper 
---
 .../devicetree/bindings/sound/sun4i-i2s.txt|   2 +
 sound/soc/sunxi/sun4i-i2s.c| 202 +
 2 files changed, 204 insertions(+)

diff --git a/Documentation/devicetree/bindings/sound/sun4i-i2s.txt 
b/Documentation/devicetree/bindings/sound/sun4i-i2s.txt
index ee21da865771..fc5da6080759 100644
--- a/Documentation/devicetree/bindings/sound/sun4i-i2s.txt
+++ b/Documentation/devicetree/bindings/sound/sun4i-i2s.txt
@@ -8,6 +8,7 @@ Required properties:
 - compatible: should be one of the following:
- "allwinner,sun4i-a10-i2s"
- "allwinner,sun6i-a31-i2s"
+   - "allwinner,sun8i-h3-i2s"
 - reg: physical base address of the controller and length of memory mapped
   region.
 - interrupts: should contain the I2S interrupt.
@@ -22,6 +23,7 @@ Required properties:
 
 Required properties for the following compatibles:
- "allwinner,sun6i-a31-i2s"
+   - "allwinner,sun8i-h3-i2s"
 - resets: phandle to the reset line for this codec
 
 Example:
diff --git a/sound/soc/sunxi/sun4i-i2s.c b/sound/soc/sunxi/sun4i-i2s.c
index 1854405cbcb1..2b3c2b28059c 100644
--- a/sound/soc/sunxi/sun4i-i2s.c
+++ b/sound/soc/sunxi/sun4i-i2s.c
@@ -26,6 +26,8 @@
 #include 
 
 #define SUN4I_I2S_CTRL_REG 0x00
+#define SUN8I_I2S_CTRL_BCLK_OUTBIT(18)
+#define SUN8I_I2S_CTRL_LRCK_OUTBIT(17)
 #define SUN4I_I2S_CTRL_SDO_EN_MASK GENMASK(11, 8)
 #define SUN4I_I2S_CTRL_SDO_EN(sdo) BIT(8 + (sdo))
 #define SUN4I_I2S_CTRL_MODE_MASK   BIT(5)
@@ -55,6 +57,7 @@
 
 #define SUN4I_I2S_FMT1_REG 0x08
 #define SUN4I_I2S_FIFO_TX_REG  0x0c
+#define SUN8I_I2S_INT_STA_REG  0x0c
 #define SUN4I_I2S_FIFO_RX_REG  0x10
 
 #define SUN4I_I2S_FIFO_CTRL_REG0x14
@@ -72,8 +75,10 @@
 #define SUN4I_I2S_DMA_INT_CTRL_RX_DRQ_EN   BIT(3)
 
 #define SUN4I_I2S_INT_STA_REG  0x20
+#define SUN8I_I2S_FIFO_TX_REG  0x20
 
 #define SUN4I_I2S_CLK_DIV_REG  0x24
+#define SUN8I_I2S_CLK_DIV_MCLK_EN  8
 #define SUN4I_I2S_CLK_DIV_MCLK_EN  7
 #define SUN4I_I2S_CLK_DIV_BCLK_MASKGENMASK(6, 4)
 #define SUN4I_I2S_CLK_DIV_BCLK(bclk)   ((bclk) << 4)
@@ -86,16 +91,29 @@
 #define SUN4I_I2S_TX_CHAN_SEL_REG  0x30
 #define SUN4I_I2S_CHAN_SEL(num_chan)   (((num_chan) - 1) << 0)
 
+#define SUN8I_I2S_CHAN_CFG_REG 0x30
+
 #define SUN4I_I2S_TX_CHAN_MAP_REG  0x34
 #define SUN4I_I2S_TX_CHAN_MAP(chan, sample)((sample) << (chan << 2))
+#define SUN8I_I2S_TX_CHAN_SEL_REG  0x34
+#define SUN8I_I2S_TX_CHAN_OFFSET(offset)   (offset << 12)
 #define SUN4I_I2S_TX_CHAN_EN(num_chan) (((1 << num_chan) - 1))
 
 #define SUN4I_I2S_RX_CHAN_SEL_REG  0x38
 #define SUN4I_I2S_RX_CHAN_MAP_REG  0x3c
 
+#define SUN8I_I2S_TX_CHAN_MAP_REG  0x44
+
+#define SUN8I_I2S_RX_CHAN_SEL_REG  0x54
+#define SUN8I_I2S_RX_CHAN_MAP_REG  0x58
+
 struct sun4i_i2s_quirks {
boolhas_reset;
boolhas_master_slave_sel;
+   boolhas_fmt_set_lrck_period;
+   boolhas_chcfg;
+   boolhas_chsel_tx_chen;
+   boolhas_chsel_offset;
unsigned intreg_offset_txdata;  /* TX FIFO */
unsigned intreg_offset_txchanmap;
unsigned intreg_offset_rxchanmap;
@@ -113,6 +131,11 @@ struct sun4i_i2s_quirks {
struct reg_fieldfield_fmt_set_mode;
struct reg_fieldfield_txchansel;
struct reg_fieldfield_rxchansel;
+   struct reg_fieldfield_fmt_set_lrck_period;
+   struct reg_fieldfield_chcfg_tx_slot_num;
+   struct reg_fieldfield_chcfg_rx_slot_num;
+   struct reg_fieldfield_chsel_tx_chen;
+   struct reg_fieldfield_chsel_offset;
 };
 
 struct sun4i_i2s {
@@ -136,6 +159,11 @@ struct sun4i_i2s {
struct regmap_field *field_fmt_set_mode;
struct regmap_field *field_txchansel;
struct regmap_field *field_rxchansel;
+   struct regmap_field *field_fmt_set_lrck_period;
+   struct regmap_field *field_chcfg_tx_slot_num;
+   struct regmap_field *field_chcfg_rx_slot_num;
+   struct regmap_field *field_chsel_tx_chen;
+   struct regmap_field *field_chsel_offset;
 
const struct sun4i_i2s_quirks   

[PATCH v2 0/2] ASoC: Add I2S support for Allwinner H3 SoCs

2017-07-22 Thread codekipper
From: Marcus Cooper <codekip...@gmail.com>

Hi All,
please find attached a series of patches to bring i2s support to the
Allwinner H3 SoC. This has been tested with the following setups:

A20 Olimex EVB connected to a pcm5102
Orange Pi 2 connected to a uda1380
Orange Pi 2 hdmi audio playback
Pine 64 connected to the audio DAC board

To get i2s working some additional patches are required which will be
delivered later. For now they have been pushed here

https://github.com/codekipper/linux-sunxi/commits/sunxi-audio-h3

I don't own a A33 device which uses the i2s block for the audio codec
so if someone could test against that it would be much appreciated.

I'm also wondering if there is a preferred way of setting the lrclk
size in the dts?..currently it is set to the sample width but for example
the pcm5102a wants it to be 32 bits whatever the sample rate.

Thanks in advance,
CK

v2 changes compared to v1 are:
 - massive refactoring to remove duplicate code making use of regmap_fields.
 - extending the clock divisors.
 - removed code that should be delivered when we support 20/24bits

---

Marcus Cooper (2):
  ASoC: sun4i-i2s: Add more quirks for newer SoCs
  ASoC: sun4i-i2s: Add support for H3

 .../devicetree/bindings/sound/sun4i-i2s.txt|   2 +
 sound/soc/sunxi/sun4i-i2s.c| 469 ++---
 2 files changed, 407 insertions(+), 64 deletions(-)

-- 
2.13.3



[PATCH 3/3] ASoC: sun4i-i2s: Add support for H3

2017-07-05 Thread codekipper
From: Marcus Cooper 

There are a lot of changes to the sun8i-h3 i2s block but not enough
to warrant to a new driver.

Signed-off-by: Marcus Cooper 
---
 .../devicetree/bindings/sound/sun4i-i2s.txt|   2 +
 sound/soc/sunxi/sun4i-i2s.c| 339 -
 2 files changed, 337 insertions(+), 4 deletions(-)

diff --git a/Documentation/devicetree/bindings/sound/sun4i-i2s.txt 
b/Documentation/devicetree/bindings/sound/sun4i-i2s.txt
index ee21da865771..fc5da6080759 100644
--- a/Documentation/devicetree/bindings/sound/sun4i-i2s.txt
+++ b/Documentation/devicetree/bindings/sound/sun4i-i2s.txt
@@ -8,6 +8,7 @@ Required properties:
 - compatible: should be one of the following:
- "allwinner,sun4i-a10-i2s"
- "allwinner,sun6i-a31-i2s"
+   - "allwinner,sun8i-h3-i2s"
 - reg: physical base address of the controller and length of memory mapped
   region.
 - interrupts: should contain the I2S interrupt.
@@ -22,6 +23,7 @@ Required properties:
 
 Required properties for the following compatibles:
- "allwinner,sun6i-a31-i2s"
+   - "allwinner,sun8i-h3-i2s"
 - resets: phandle to the reset line for this codec
 
 Example:
diff --git a/sound/soc/sunxi/sun4i-i2s.c b/sound/soc/sunxi/sun4i-i2s.c
index bb7affd53002..0b853fe320e0 100644
--- a/sound/soc/sunxi/sun4i-i2s.c
+++ b/sound/soc/sunxi/sun4i-i2s.c
@@ -26,9 +26,16 @@
 #include 
 
 #define SUN4I_I2S_CTRL_REG 0x00
+#define SUN4I_I2S_CTRL_BCLK_OUTBIT(18)
+#define SUN4I_I2S_CTRL_LRCK_OUTBIT(17)
+#define SUN4I_I2S_CTRL_LRCKR_OUT   BIT(16)
 #define SUN4I_I2S_CTRL_SDO_EN_MASK GENMASK(11, 8)
 #define SUN4I_I2S_CTRL_SDO_EN(sdo) BIT(8 + (sdo))
 #define SUN4I_I2S_CTRL_MODE_MASK   BIT(5)
+#define SUN8I_I2S_CTRL_MODE_MASK   GENMASK(5, 4)
+#define SUN8I_I2S_CTRL_MODE_RIGHT_J(2 << 4)
+#define SUN8I_I2S_CTRL_MODE_I2S(1 << 4)
+#define SUN8I_I2S_CTRL_MODE_PCM(0 << 4)
 #define SUN4I_I2S_CTRL_MODE_SLAVE  (1 << 5)
 #define SUN4I_I2S_CTRL_MODE_MASTER (0 << 5)
 #define SUN4I_I2S_CTRL_TX_EN   BIT(2)
@@ -36,16 +43,27 @@
 #define SUN4I_I2S_CTRL_GL_EN   BIT(0)
 
 #define SUN4I_I2S_FMT0_REG 0x04
+#define SUN8I_I2S_FMT0_LRCLK_POLARITY_MASK BIT(19)
+#define SUN8I_I2S_FMT0_LRCLK_POLARITY_INVERTED (1 << 19)
+#define SUN8I_I2S_FMT0_LRCLK_POLARITY_NORMAL   (0 << 19)
+#define SUN8I_I2S_FMT0_LRCK_PERIOD_MASKGENMASK(17, 8)
+#define SUN8I_I2S_FMT0_LRCK_PERIOD(period) ((period) << 8)
 #define SUN4I_I2S_FMT0_LRCLK_POLARITY_MASK BIT(7)
 #define SUN4I_I2S_FMT0_LRCLK_POLARITY_INVERTED (1 << 7)
 #define SUN4I_I2S_FMT0_LRCLK_POLARITY_NORMAL   (0 << 7)
+#define SUN8I_I2S_FMT0_BCLK_POLARITY_MASK  BIT(7)
+#define SUN8I_I2S_FMT0_BCLK_POLARITY_INVERTED  (1 << 7)
+#define SUN8I_I2S_FMT0_BCLK_POLARITY_NORMAL(0 << 7)
 #define SUN4I_I2S_FMT0_BCLK_POLARITY_MASK  BIT(6)
 #define SUN4I_I2S_FMT0_BCLK_POLARITY_INVERTED  (1 << 6)
 #define SUN4I_I2S_FMT0_BCLK_POLARITY_NORMAL(0 << 6)
 #define SUN4I_I2S_FMT0_SR_MASK GENMASK(5, 4)
+#define SUN8I_I2S_FMT0_SR_MASK GENMASK(6, 4)
 #define SUN4I_I2S_FMT0_SR(sr)  ((sr) << 4)
 #define SUN4I_I2S_FMT0_WSS_MASKGENMASK(3, 2)
 #define SUN4I_I2S_FMT0_WSS(wss)((wss) << 2)
+#define SUN8I_I2S_FMT0_WSS_MASKGENMASK(2, 0)
+#define SUN8I_I2S_FMT0_WSS(wss)(wss)
 #define SUN4I_I2S_FMT0_FMT_MASKGENMASK(1, 0)
 #define SUN4I_I2S_FMT0_FMT_RIGHT_J (2 << 0)
 #define SUN4I_I2S_FMT0_FMT_LEFT_J  (1 << 0)
@@ -53,6 +71,7 @@
 
 #define SUN4I_I2S_FMT1_REG 0x08
 #define SUN4I_I2S_FIFO_TX_REG  0x0c
+#define SUN8I_I2S_INT_STA_REG  0x0c
 #define SUN4I_I2S_FIFO_RX_REG  0x10
 
 #define SUN4I_I2S_FIFO_CTRL_REG0x14
@@ -70,10 +89,13 @@
 #define SUN4I_I2S_DMA_INT_CTRL_RX_DRQ_EN   BIT(3)
 
 #define SUN4I_I2S_INT_STA_REG  0x20
+#define SUN8I_I2S_FIFO_TX_REG  0x20
 
 #define SUN4I_I2S_CLK_DIV_REG  0x24
+#define SUN8I_I2S_CLK_DIV_MCLK_EN  BIT(8)
 #define SUN4I_I2S_CLK_DIV_MCLK_EN  BIT(7)
 #define SUN4I_I2S_CLK_DIV_BCLK_MASKGENMASK(6, 4)
+#define SUN8I_I2S_CLK_DIV_BCLK_MASKGENMASK(7, 4)
 #define SUN4I_I2S_CLK_DIV_BCLK(bclk)   ((bclk) << 4)
 #define SUN4I_I2S_CLK_DIV_MCLK_MASKGENMASK(3, 0)
 #define SUN4I_I2S_CLK_DIV_MCLK(mclk)   ((mclk) << 0)
@@ -82,14 +104,27 @@
 #define SUN4I_I2S_TX_CNT_REG   0x2c
 
 #define SUN4I_I2S_TX_CHAN_SEL_REG  0x30

[PATCH 1/3] ASoC: sun4i-i2s: Add more quirks for newer SoCs

2017-07-05 Thread codekipper
From: Marcus Cooper 

The Allwinner H3 has some differences to its I2S block such as a
different address for the TXFIFO and various register changes.

This patch prepares the driver for these changes.

Signed-off-by: Marcus Cooper 
---
 sound/soc/sunxi/sun4i-i2s.c | 28 ++--
 1 file changed, 22 insertions(+), 6 deletions(-)

diff --git a/sound/soc/sunxi/sun4i-i2s.c b/sound/soc/sunxi/sun4i-i2s.c
index 3635bbc72cbc..38ab0144f897 100644
--- a/sound/soc/sunxi/sun4i-i2s.c
+++ b/sound/soc/sunxi/sun4i-i2s.c
@@ -544,7 +544,6 @@ static struct snd_soc_dai_driver sun4i_i2s_dai = {
.rates = SNDRV_PCM_RATE_8000_192000,
.formats = SNDRV_PCM_FMTBIT_S16_LE,
},
-   .ops = _i2s_dai_ops,
.symmetric_rates = 1,
 };
 
@@ -655,15 +654,24 @@ static int sun4i_i2s_runtime_suspend(struct device *dev)
 }
 
 struct sun4i_i2s_quirks {
-   bool has_reset;
+   boolhas_reset;
+   unsigned intreg_offset_txdata;  /* TX FIFO */
+   const struct regmap_config  *sun4i_i2s_regmap;
+   const struct snd_soc_dai_ops*ops;
 };
 
 static const struct sun4i_i2s_quirks sun4i_a10_i2s_quirks = {
-   .has_reset  = false,
+   .has_reset  = false,
+   .reg_offset_txdata  = SUN4I_I2S_FIFO_TX_REG,
+   .sun4i_i2s_regmap   = _i2s_regmap_config,
+   .ops= _i2s_dai_ops,
 };
 
 static const struct sun4i_i2s_quirks sun6i_a31_i2s_quirks = {
-   .has_reset  = true,
+   .has_reset  = true,
+   .reg_offset_txdata  = SUN4I_I2S_FIFO_TX_REG,
+   .sun4i_i2s_regmap   = _i2s_regmap_config,
+   .ops= _i2s_dai_ops,
 };
 
 static int sun4i_i2s_probe(struct platform_device *pdev)
@@ -702,8 +710,14 @@ static int sun4i_i2s_probe(struct platform_device *pdev)
return PTR_ERR(i2s->bus_clk);
}
 
+   quirks = of_device_get_match_data(>dev);
+   if (quirks == NULL) {
+   dev_err(>dev, "Failed to determine the quirks to use\n");
+   return -ENODEV;
+   }
+
i2s->regmap = devm_regmap_init_mmio(>dev, regs,
-   _i2s_regmap_config);
+   quirks->sun4i_i2s_regmap);
if (IS_ERR(i2s->regmap)) {
dev_err(>dev, "Regmap initialisation failed\n");
return PTR_ERR(i2s->regmap);
@@ -732,7 +746,7 @@ static int sun4i_i2s_probe(struct platform_device *pdev)
}
}
 
-   i2s->playback_dma_data.addr = res->start + SUN4I_I2S_FIFO_TX_REG;
+   i2s->playback_dma_data.addr = res->start + quirks->reg_offset_txdata;
i2s->playback_dma_data.maxburst = 8;
 
i2s->capture_dma_data.addr = res->start + SUN4I_I2S_FIFO_RX_REG;
@@ -745,6 +759,8 @@ static int sun4i_i2s_probe(struct platform_device *pdev)
goto err_pm_disable;
}
 
+   /* Register ops with dai */
+   sun4i_i2s_dai.ops = quirks->ops;
ret = devm_snd_soc_register_component(>dev,
  _i2s_component,
  _i2s_dai, 1);
-- 
2.13.2



[PATCH 0/3] ASoC: Add I2S support for Allwinner H3 SoCs

2017-07-05 Thread codekipper
From: Marcus Cooper <codekip...@gmail.com>

Hi All,
please find attached a series of patches to bring i2s support to the
Allwinner H3 SoC. This has been tested with the following setups:

A20 Olimex EVB connected to a pcm5102
Orange Pi 2 connected to a uda1380
Orange Pi 2 hdmi audio playback
Pine 64 connected to the audio DAC board

To get i2s working some additional patches are required which will be
delivered later. For now they have been pushed here

https://github.com/codekipper/linux-sunxi/commits/sunxi-audio-h3

Thanks in advance,
CK

Marcus Cooper (3):
  ASoC: sun4i-i2s: Add more quirks for newer SoCs
  ASoC: sun4i-i2s: Get startup to call set_fmt
  ASoC: sun4i-i2s: Add support for H3

 .../devicetree/bindings/sound/sun4i-i2s.txt|   2 +
 sound/soc/sunxi/sun4i-i2s.c| 391 -
 2 files changed, 376 insertions(+), 17 deletions(-)

-- 
2.13.2



[PATCH 2/3] ASoC: sun4i-i2s: Get startup to call set_fmt

2017-07-05 Thread codekipper
From: Marcus Cooper 

The set_fmt function pointer is called during probing and this is whilst
the block is disabled. It is over writing the default register values with
the same settings so isn't noticed.
This wasn't a problem with the older SoCs but with the desire to reuse as
much functionlity as possible for the newer devices then set_fmt needs to
be called whilst the block is enabled.

Signed-off-by: Marcus Cooper 
---
 sound/soc/sunxi/sun4i-i2s.c | 24 +---
 1 file changed, 17 insertions(+), 7 deletions(-)

diff --git a/sound/soc/sunxi/sun4i-i2s.c b/sound/soc/sunxi/sun4i-i2s.c
index 38ab0144f897..bb7affd53002 100644
--- a/sound/soc/sunxi/sun4i-i2s.c
+++ b/sound/soc/sunxi/sun4i-i2s.c
@@ -351,6 +351,15 @@ static int sun4i_i2s_set_fmt(struct snd_soc_dai *dai, 
unsigned int fmt)
   SUN4I_I2S_FIFO_CTRL_RX_MODE_MASK,
   SUN4I_I2S_FIFO_CTRL_TX_MODE(1) |
   SUN4I_I2S_FIFO_CTRL_RX_MODE(1));
+
+   /* Enable the first two channels */
+   regmap_write(i2s->regmap, SUN4I_I2S_TX_CHAN_SEL_REG,
+SUN4I_I2S_TX_CHAN_SEL(2));
+
+   /* Map them to the two first samples coming in */
+   regmap_write(i2s->regmap, SUN4I_I2S_TX_CHAN_MAP_REG,
+SUN4I_I2S_TX_CHAN_MAP(0, 0) | SUN4I_I2S_TX_CHAN_MAP(1, 1));
+
return 0;
 }
 
@@ -457,6 +466,9 @@ static int sun4i_i2s_startup(struct snd_pcm_substream 
*substream,
 struct snd_soc_dai *dai)
 {
struct sun4i_i2s *i2s = snd_soc_dai_get_drvdata(dai);
+   struct snd_soc_pcm_runtime *rtd = substream->private_data;
+   struct device *dev = rtd->card->dev;
+   int ret = 0;
 
/* Enable the whole hardware block */
regmap_write(i2s->regmap, SUN4I_I2S_CTRL_REG,
@@ -467,13 +479,11 @@ static int sun4i_i2s_startup(struct snd_pcm_substream 
*substream,
   SUN4I_I2S_CTRL_SDO_EN_MASK,
   SUN4I_I2S_CTRL_SDO_EN(0));
 
-   /* Enable the first two channels */
-   regmap_write(i2s->regmap, SUN4I_I2S_TX_CHAN_SEL_REG,
-SUN4I_I2S_TX_CHAN_SEL(2));
-
-   /* Map them to the two first samples coming in */
-   regmap_write(i2s->regmap, SUN4I_I2S_TX_CHAN_MAP_REG,
-SUN4I_I2S_TX_CHAN_MAP(0, 0) | SUN4I_I2S_TX_CHAN_MAP(1, 1));
+   ret = snd_soc_dai_set_fmt(rtd->cpu_dai, rtd->dai_link->dai_fmt);
+   if (ret < 0) {
+   dev_err(dev, "can't set cpu_dai set fmt: %d\n", ret);
+   return ret;
+   }
 
return clk_prepare_enable(i2s->mod_clk);
 }
-- 
2.13.2



[PATCH v5 4/8] ASoC: sun4i-i2s: Add mclk enable regmap field

2017-08-19 Thread codekipper
From: Marcus Cooper 

The location of the mclk output enable bit is different on newer
SoCs. Use a regmap field to enable it.

Signed-off-by: Marcus Cooper 
---
 sound/soc/sunxi/sun4i-i2s.c | 16 ++--
 1 file changed, 14 insertions(+), 2 deletions(-)

diff --git a/sound/soc/sunxi/sun4i-i2s.c b/sound/soc/sunxi/sun4i-i2s.c
index 8c7ad5bfe821..761b7c0f6a32 100644
--- a/sound/soc/sunxi/sun4i-i2s.c
+++ b/sound/soc/sunxi/sun4i-i2s.c
@@ -101,6 +101,7 @@
  * @mclk_offset: Value by which mclkdiv needs to be adjusted.
  * @bclk_offset: Value by which bclkdiv needs to be adjusted.
  * @fmt_offset: Value by which wss and sr needs to be adjusted.
+ * @field_clkdiv_mclk_en: regmap field to enable mclk output.
  * @field_fmt_wss: regmap field to set word select size.
  * @field_fmt_sr: regmap field to set sample resolution.
  * @field_fmt_bclk: regmap field to set clk polarity.
@@ -119,6 +120,7 @@ struct sun4i_i2s_quirks {
unsigned intfmt_offset;
 
/* Register fields for i2s */
+   struct reg_fieldfield_clkdiv_mclk_en;
struct reg_fieldfield_fmt_wss;
struct reg_fieldfield_fmt_sr;
struct reg_fieldfield_fmt_bclk;
@@ -141,6 +143,7 @@ struct sun4i_i2s {
struct snd_dmaengine_dai_dma_data   playback_dma_data;
 
/* Register fields for i2s */
+   struct regmap_field *field_clkdiv_mclk_en;
struct regmap_field *field_fmt_wss;
struct regmap_field *field_fmt_sr;
struct regmap_field *field_fmt_bclk;
@@ -283,8 +286,9 @@ static int sun4i_i2s_set_clk_rate(struct sun4i_i2s *i2s,
 
regmap_write(i2s->regmap, SUN4I_I2S_CLK_DIV_REG,
 SUN4I_I2S_CLK_DIV_BCLK(bclk_div) |
-SUN4I_I2S_CLK_DIV_MCLK(mclk_div) |
-SUN4I_I2S_CLK_DIV_MCLK_EN);
+SUN4I_I2S_CLK_DIV_MCLK(mclk_div));
+
+   regmap_field_write(i2s->field_clkdiv_mclk_en, 1);
 
return 0;
 }
@@ -713,6 +717,7 @@ static const struct sun4i_i2s_quirks sun4i_a10_i2s_quirks = 
{
.has_reset  = false,
.reg_offset_txdata  = SUN4I_I2S_FIFO_TX_REG,
.sun4i_i2s_regmap   = _i2s_regmap_config,
+   .field_clkdiv_mclk_en   = REG_FIELD(SUN4I_I2S_CLK_DIV_REG, 7, 7),
.field_fmt_wss  = REG_FIELD(SUN4I_I2S_FMT0_REG, 2, 3),
.field_fmt_sr   = REG_FIELD(SUN4I_I2S_FMT0_REG, 4, 5),
.field_fmt_bclk = REG_FIELD(SUN4I_I2S_FMT0_REG, 6, 6),
@@ -727,6 +732,7 @@ static const struct sun4i_i2s_quirks sun6i_a31_i2s_quirks = 
{
.has_reset  = true,
.reg_offset_txdata  = SUN4I_I2S_FIFO_TX_REG,
.sun4i_i2s_regmap   = _i2s_regmap_config,
+   .field_clkdiv_mclk_en   = REG_FIELD(SUN4I_I2S_CLK_DIV_REG, 7, 7),
.field_fmt_wss  = REG_FIELD(SUN4I_I2S_FMT0_REG, 2, 3),
.field_fmt_sr   = REG_FIELD(SUN4I_I2S_FMT0_REG, 4, 5),
.field_fmt_bclk = REG_FIELD(SUN4I_I2S_FMT0_REG, 6, 6),
@@ -740,6 +746,12 @@ static const struct sun4i_i2s_quirks sun6i_a31_i2s_quirks 
= {
 static int sun4i_i2s_init_regmap_fields(struct device *dev,
struct sun4i_i2s *i2s)
 {
+   i2s->field_clkdiv_mclk_en =
+   devm_regmap_field_alloc(dev, i2s->regmap,
+   i2s->variant->field_clkdiv_mclk_en);
+   if (IS_ERR(i2s->field_clkdiv_mclk_en))
+   return PTR_ERR(i2s->field_clkdiv_mclk_en);
+
i2s->field_fmt_wss =
devm_regmap_field_alloc(dev, i2s->regmap,
i2s->variant->field_fmt_wss);
-- 
2.14.1



[PATCH v5 1/8] ASoC: sun4i-i2s: Add regmap fields for channels

2017-08-19 Thread codekipper
From: Marcus Cooper 

On the original i2s block the channel mapping and selection were
configured for stereo audio by default: This is not the case with
the newer SoCs and they are also located at different offsets.

To support the newer SoC then regmap fields have been added to the
quirks and these are initialised to their correct settings during
probing.

Signed-off-by: Marcus Cooper 
Reviewed-by: Chen-Yu Tsai 
---
 sound/soc/sunxi/sun4i-i2s.c | 77 -
 1 file changed, 69 insertions(+), 8 deletions(-)

diff --git a/sound/soc/sunxi/sun4i-i2s.c b/sound/soc/sunxi/sun4i-i2s.c
index dfb79492..87feb5a14cff 100644
--- a/sound/soc/sunxi/sun4i-i2s.c
+++ b/sound/soc/sunxi/sun4i-i2s.c
@@ -82,7 +82,7 @@
 #define SUN4I_I2S_TX_CNT_REG   0x2c
 
 #define SUN4I_I2S_TX_CHAN_SEL_REG  0x30
-#define SUN4I_I2S_TX_CHAN_SEL(num_chan)(((num_chan) - 1) << 0)
+#define SUN4I_I2S_CHAN_SEL(num_chan)   (((num_chan) - 1) << 0)
 
 #define SUN4I_I2S_TX_CHAN_MAP_REG  0x34
 #define SUN4I_I2S_TX_CHAN_MAP(chan, sample)((sample) << (chan << 2))
@@ -98,6 +98,10 @@
  * @sun4i_i2s_regmap: regmap config to use.
  * @mclk_offset: Value by which mclkdiv needs to be adjusted.
  * @bclk_offset: Value by which bclkdiv needs to be adjusted.
+ * @field_txchanmap: location of the tx channel mapping register.
+ * @field_rxchanmap: location of the rx channel mapping register.
+ * @field_txchansel: location of the tx channel select bit fields.
+ * @field_rxchansel: location of the rx channel select bit fields.
  */
 struct sun4i_i2s_quirks {
boolhas_reset;
@@ -105,6 +109,12 @@ struct sun4i_i2s_quirks {
const struct regmap_config  *sun4i_i2s_regmap;
unsigned intmclk_offset;
unsigned intbclk_offset;
+
+   /* Register fields for i2s */
+   struct reg_fieldfield_txchanmap;
+   struct reg_fieldfield_rxchanmap;
+   struct reg_fieldfield_txchansel;
+   struct reg_fieldfield_rxchansel;
 };
 
 struct sun4i_i2s {
@@ -118,6 +128,12 @@ struct sun4i_i2s {
struct snd_dmaengine_dai_dma_data   capture_dma_data;
struct snd_dmaengine_dai_dma_data   playback_dma_data;
 
+   /* Register fields for i2s */
+   struct regmap_field *field_txchanmap;
+   struct regmap_field *field_rxchanmap;
+   struct regmap_field *field_txchansel;
+   struct regmap_field *field_rxchansel;
+
const struct sun4i_i2s_quirks   *variant;
 };
 
@@ -268,6 +284,17 @@ static int sun4i_i2s_hw_params(struct snd_pcm_substream 
*substream,
if (params_channels(params) != 2)
return -EINVAL;
 
+   /* Map the channels for playback and capture */
+   regmap_field_write(i2s->field_txchanmap, 0x76543210);
+   regmap_field_write(i2s->field_rxchanmap, 0x3210);
+
+   /* Configure the channels */
+   regmap_field_write(i2s->field_txchansel,
+  SUN4I_I2S_CHAN_SEL(params_channels(params)));
+
+   regmap_field_write(i2s->field_rxchansel,
+  SUN4I_I2S_CHAN_SEL(params_channels(params)));
+
switch (params_physical_width(params)) {
case 16:
width = DMA_SLAVE_BUSWIDTH_2_BYTES;
@@ -490,13 +517,6 @@ static int sun4i_i2s_startup(struct snd_pcm_substream 
*substream,
   SUN4I_I2S_CTRL_SDO_EN_MASK,
   SUN4I_I2S_CTRL_SDO_EN(0));
 
-   /* Enable the first two channels */
-   regmap_write(i2s->regmap, SUN4I_I2S_TX_CHAN_SEL_REG,
-SUN4I_I2S_TX_CHAN_SEL(2));
-
-   /* Map them to the two first samples coming in */
-   regmap_write(i2s->regmap, SUN4I_I2S_TX_CHAN_MAP_REG,
-SUN4I_I2S_TX_CHAN_MAP(0, 0) | SUN4I_I2S_TX_CHAN_MAP(1, 1));
 
return clk_prepare_enable(i2s->mod_clk);
 }
@@ -681,14 +701,49 @@ static const struct sun4i_i2s_quirks sun4i_a10_i2s_quirks 
= {
.has_reset  = false,
.reg_offset_txdata  = SUN4I_I2S_FIFO_TX_REG,
.sun4i_i2s_regmap   = _i2s_regmap_config,
+   .field_txchanmap= REG_FIELD(SUN4I_I2S_TX_CHAN_MAP_REG, 0, 31),
+   .field_rxchanmap= REG_FIELD(SUN4I_I2S_RX_CHAN_MAP_REG, 0, 31),
+   .field_txchansel= REG_FIELD(SUN4I_I2S_TX_CHAN_SEL_REG, 0, 2),
+   .field_rxchansel= REG_FIELD(SUN4I_I2S_RX_CHAN_SEL_REG, 0, 2),
 };
 
 static const struct sun4i_i2s_quirks sun6i_a31_i2s_quirks = {
.has_reset  = true,
.reg_offset_txdata  = SUN4I_I2S_FIFO_TX_REG,
.sun4i_i2s_regmap   = _i2s_regmap_config,
+   .field_txchanmap= REG_FIELD(SUN4I_I2S_TX_CHAN_MAP_REG, 0, 31),
+   .field_rxchanmap= REG_FIELD(SUN4I_I2S_RX_CHAN_MAP_REG, 0, 31),
+   

[PATCH v5 2/8] ASoC: sun4i-i2s: Add regfields for word size select and sample resolution

2017-08-19 Thread codekipper
From: Marcus Cooper 

On newer SoCs the location of the slot width select and sample
resolution are different and also there is a bigger range of
support.

For the current supported rates then an offset is required.

Signed-off-by: Marcus Cooper 
Reviewed-by: Chen-Yu Tsai 
---
 sound/soc/sunxi/sun4i-i2s.c | 31 ---
 1 file changed, 28 insertions(+), 3 deletions(-)

diff --git a/sound/soc/sunxi/sun4i-i2s.c b/sound/soc/sunxi/sun4i-i2s.c
index 87feb5a14cff..563de785d639 100644
--- a/sound/soc/sunxi/sun4i-i2s.c
+++ b/sound/soc/sunxi/sun4i-i2s.c
@@ -98,6 +98,9 @@
  * @sun4i_i2s_regmap: regmap config to use.
  * @mclk_offset: Value by which mclkdiv needs to be adjusted.
  * @bclk_offset: Value by which bclkdiv needs to be adjusted.
+ * @fmt_offset: Value by which wss and sr needs to be adjusted.
+ * @field_fmt_wss: regmap field to set word select size.
+ * @field_fmt_sr: regmap field to set sample resolution.
  * @field_txchanmap: location of the tx channel mapping register.
  * @field_rxchanmap: location of the rx channel mapping register.
  * @field_txchansel: location of the tx channel select bit fields.
@@ -109,8 +112,11 @@ struct sun4i_i2s_quirks {
const struct regmap_config  *sun4i_i2s_regmap;
unsigned intmclk_offset;
unsigned intbclk_offset;
+   unsigned intfmt_offset;
 
/* Register fields for i2s */
+   struct reg_fieldfield_fmt_wss;
+   struct reg_fieldfield_fmt_sr;
struct reg_fieldfield_txchanmap;
struct reg_fieldfield_rxchanmap;
struct reg_fieldfield_txchansel;
@@ -129,6 +135,8 @@ struct sun4i_i2s {
struct snd_dmaengine_dai_dma_data   playback_dma_data;
 
/* Register fields for i2s */
+   struct regmap_field *field_fmt_wss;
+   struct regmap_field *field_fmt_sr;
struct regmap_field *field_txchanmap;
struct regmap_field *field_rxchanmap;
struct regmap_field *field_txchansel;
@@ -314,9 +322,10 @@ static int sun4i_i2s_hw_params(struct snd_pcm_substream 
*substream,
return -EINVAL;
}
 
-   regmap_update_bits(i2s->regmap, SUN4I_I2S_FMT0_REG,
-  SUN4I_I2S_FMT0_WSS_MASK | SUN4I_I2S_FMT0_SR_MASK,
-  SUN4I_I2S_FMT0_WSS(wss) | SUN4I_I2S_FMT0_SR(sr));
+   regmap_field_write(i2s->field_fmt_wss,
+  wss + i2s->variant->fmt_offset);
+   regmap_field_write(i2s->field_fmt_sr,
+  sr + i2s->variant->fmt_offset);
 
return sun4i_i2s_set_clk_rate(i2s, params_rate(params),
  params_width(params));
@@ -701,6 +710,8 @@ static const struct sun4i_i2s_quirks sun4i_a10_i2s_quirks = 
{
.has_reset  = false,
.reg_offset_txdata  = SUN4I_I2S_FIFO_TX_REG,
.sun4i_i2s_regmap   = _i2s_regmap_config,
+   .field_fmt_wss  = REG_FIELD(SUN4I_I2S_FMT0_REG, 2, 3),
+   .field_fmt_sr   = REG_FIELD(SUN4I_I2S_FMT0_REG, 4, 5),
.field_txchanmap= REG_FIELD(SUN4I_I2S_TX_CHAN_MAP_REG, 0, 31),
.field_rxchanmap= REG_FIELD(SUN4I_I2S_RX_CHAN_MAP_REG, 0, 31),
.field_txchansel= REG_FIELD(SUN4I_I2S_TX_CHAN_SEL_REG, 0, 2),
@@ -711,6 +722,8 @@ static const struct sun4i_i2s_quirks sun6i_a31_i2s_quirks = 
{
.has_reset  = true,
.reg_offset_txdata  = SUN4I_I2S_FIFO_TX_REG,
.sun4i_i2s_regmap   = _i2s_regmap_config,
+   .field_fmt_wss  = REG_FIELD(SUN4I_I2S_FMT0_REG, 2, 3),
+   .field_fmt_sr   = REG_FIELD(SUN4I_I2S_FMT0_REG, 4, 5),
.field_txchanmap= REG_FIELD(SUN4I_I2S_TX_CHAN_MAP_REG, 0, 31),
.field_rxchanmap= REG_FIELD(SUN4I_I2S_RX_CHAN_MAP_REG, 0, 31),
.field_txchansel= REG_FIELD(SUN4I_I2S_TX_CHAN_SEL_REG, 0, 2),
@@ -720,6 +733,18 @@ static const struct sun4i_i2s_quirks sun6i_a31_i2s_quirks 
= {
 static int sun4i_i2s_init_regmap_fields(struct device *dev,
struct sun4i_i2s *i2s)
 {
+   i2s->field_fmt_wss =
+   devm_regmap_field_alloc(dev, i2s->regmap,
+   i2s->variant->field_fmt_wss);
+   if (IS_ERR(i2s->field_fmt_wss))
+   return PTR_ERR(i2s->field_fmt_wss);
+
+   i2s->field_fmt_sr =
+   devm_regmap_field_alloc(dev, i2s->regmap,
+   i2s->variant->field_fmt_sr);
+   if (IS_ERR(i2s->field_fmt_sr))
+   return PTR_ERR(i2s->field_fmt_sr);
+
i2s->field_txchanmap =
devm_regmap_field_alloc(dev, i2s->regmap,

[PATCH v5 3/8] ASoC: sun4i-i2s: bclk and lrclk polarity tidyup

2017-08-19 Thread codekipper
From: Marcus Cooper 

On newer SoCs the bit fields for the blck and lrclk polarity are in
a different locations. Use regmap fields to set the polarity bits
as intended.

Signed-off-by: Marcus Cooper 
---
 sound/soc/sunxi/sun4i-i2s.c | 45 -
 1 file changed, 32 insertions(+), 13 deletions(-)

diff --git a/sound/soc/sunxi/sun4i-i2s.c b/sound/soc/sunxi/sun4i-i2s.c
index 563de785d639..8c7ad5bfe821 100644
--- a/sound/soc/sunxi/sun4i-i2s.c
+++ b/sound/soc/sunxi/sun4i-i2s.c
@@ -50,6 +50,8 @@
 #define SUN4I_I2S_FMT0_FMT_RIGHT_J (2 << 0)
 #define SUN4I_I2S_FMT0_FMT_LEFT_J  (1 << 0)
 #define SUN4I_I2S_FMT0_FMT_I2S (0 << 0)
+#define SUN4I_I2S_FMT0_POLARITY_INVERTED   (1)
+#define SUN4I_I2S_FMT0_POLARITY_NORMAL (0)
 
 #define SUN4I_I2S_FMT1_REG 0x08
 #define SUN4I_I2S_FIFO_TX_REG  0x0c
@@ -101,6 +103,8 @@
  * @fmt_offset: Value by which wss and sr needs to be adjusted.
  * @field_fmt_wss: regmap field to set word select size.
  * @field_fmt_sr: regmap field to set sample resolution.
+ * @field_fmt_bclk: regmap field to set clk polarity.
+ * @field_fmt_lrclk: regmap field to set frame polarity.
  * @field_txchanmap: location of the tx channel mapping register.
  * @field_rxchanmap: location of the rx channel mapping register.
  * @field_txchansel: location of the tx channel select bit fields.
@@ -117,6 +121,8 @@ struct sun4i_i2s_quirks {
/* Register fields for i2s */
struct reg_fieldfield_fmt_wss;
struct reg_fieldfield_fmt_sr;
+   struct reg_fieldfield_fmt_bclk;
+   struct reg_fieldfield_fmt_lrclk;
struct reg_fieldfield_txchanmap;
struct reg_fieldfield_rxchanmap;
struct reg_fieldfield_txchansel;
@@ -137,6 +143,8 @@ struct sun4i_i2s {
/* Register fields for i2s */
struct regmap_field *field_fmt_wss;
struct regmap_field *field_fmt_sr;
+   struct regmap_field *field_fmt_bclk;
+   struct regmap_field *field_fmt_lrclk;
struct regmap_field *field_txchanmap;
struct regmap_field *field_rxchanmap;
struct regmap_field *field_txchansel;
@@ -335,6 +343,8 @@ static int sun4i_i2s_set_fmt(struct snd_soc_dai *dai, 
unsigned int fmt)
 {
struct sun4i_i2s *i2s = snd_soc_dai_get_drvdata(dai);
u32 val;
+   u32 bclk_polarity = SUN4I_I2S_FMT0_POLARITY_NORMAL;
+   u32 lrclk_polarity = SUN4I_I2S_FMT0_POLARITY_NORMAL;
 
/* DAI Mode */
switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
@@ -359,32 +369,25 @@ static int sun4i_i2s_set_fmt(struct snd_soc_dai *dai, 
unsigned int fmt)
switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
case SND_SOC_DAIFMT_IB_IF:
/* Invert both clocks */
-   val = SUN4I_I2S_FMT0_BCLK_POLARITY_INVERTED |
-   SUN4I_I2S_FMT0_LRCLK_POLARITY_INVERTED;
+   bclk_polarity = SUN4I_I2S_FMT0_POLARITY_INVERTED;
+   lrclk_polarity = SUN4I_I2S_FMT0_POLARITY_INVERTED;
break;
case SND_SOC_DAIFMT_IB_NF:
/* Invert bit clock */
-   val = SUN4I_I2S_FMT0_BCLK_POLARITY_INVERTED |
-   SUN4I_I2S_FMT0_LRCLK_POLARITY_NORMAL;
+   bclk_polarity = SUN4I_I2S_FMT0_POLARITY_INVERTED;
break;
case SND_SOC_DAIFMT_NB_IF:
/* Invert frame clock */
-   val = SUN4I_I2S_FMT0_LRCLK_POLARITY_INVERTED |
-   SUN4I_I2S_FMT0_BCLK_POLARITY_NORMAL;
+   lrclk_polarity = SUN4I_I2S_FMT0_POLARITY_INVERTED;
break;
case SND_SOC_DAIFMT_NB_NF:
-   /* Nothing to do for both normal cases */
-   val = SUN4I_I2S_FMT0_BCLK_POLARITY_NORMAL |
-   SUN4I_I2S_FMT0_LRCLK_POLARITY_NORMAL;
break;
default:
return -EINVAL;
}
 
-   regmap_update_bits(i2s->regmap, SUN4I_I2S_FMT0_REG,
-  SUN4I_I2S_FMT0_BCLK_POLARITY_MASK |
-  SUN4I_I2S_FMT0_LRCLK_POLARITY_MASK,
-  val);
+   regmap_field_write(i2s->field_fmt_bclk, bclk_polarity);
+   regmap_field_write(i2s->field_fmt_lrclk, lrclk_polarity);
 
/* DAI clock master masks */
switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
@@ -712,6 +715,8 @@ static const struct sun4i_i2s_quirks sun4i_a10_i2s_quirks = 
{
.sun4i_i2s_regmap   = _i2s_regmap_config,
.field_fmt_wss  = REG_FIELD(SUN4I_I2S_FMT0_REG, 2, 3),
.field_fmt_sr   = REG_FIELD(SUN4I_I2S_FMT0_REG, 4, 5),
+   .field_fmt_bclk = REG_FIELD(SUN4I_I2S_FMT0_REG, 6, 6),
+   .field_fmt_lrclk= 

[PATCH v5 5/8] ASoC: sun4i-i2s: Add regmap field to set DAI format

2017-08-19 Thread codekipper
From: Marcus Cooper 

On the newer SoCs the bits to configure the operational mode are
located in a different register. Add a regmap field so that this
location can be configured.

Signed-off-by: Marcus Cooper 
---
 sound/soc/sunxi/sun4i-i2s.c | 15 ---
 1 file changed, 12 insertions(+), 3 deletions(-)

diff --git a/sound/soc/sunxi/sun4i-i2s.c b/sound/soc/sunxi/sun4i-i2s.c
index 761b7c0f6a32..d9910f6617ad 100644
--- a/sound/soc/sunxi/sun4i-i2s.c
+++ b/sound/soc/sunxi/sun4i-i2s.c
@@ -106,6 +106,7 @@
  * @field_fmt_sr: regmap field to set sample resolution.
  * @field_fmt_bclk: regmap field to set clk polarity.
  * @field_fmt_lrclk: regmap field to set frame polarity.
+ * @field_fmt_mode: regmap field to set the operational mode.
  * @field_txchanmap: location of the tx channel mapping register.
  * @field_rxchanmap: location of the rx channel mapping register.
  * @field_txchansel: location of the tx channel select bit fields.
@@ -125,6 +126,7 @@ struct sun4i_i2s_quirks {
struct reg_fieldfield_fmt_sr;
struct reg_fieldfield_fmt_bclk;
struct reg_fieldfield_fmt_lrclk;
+   struct reg_fieldfield_fmt_mode;
struct reg_fieldfield_txchanmap;
struct reg_fieldfield_rxchanmap;
struct reg_fieldfield_txchansel;
@@ -148,6 +150,7 @@ struct sun4i_i2s {
struct regmap_field *field_fmt_sr;
struct regmap_field *field_fmt_bclk;
struct regmap_field *field_fmt_lrclk;
+   struct regmap_field *field_fmt_mode;
struct regmap_field *field_txchanmap;
struct regmap_field *field_rxchanmap;
struct regmap_field *field_txchansel;
@@ -365,9 +368,7 @@ static int sun4i_i2s_set_fmt(struct snd_soc_dai *dai, 
unsigned int fmt)
return -EINVAL;
}
 
-   regmap_update_bits(i2s->regmap, SUN4I_I2S_FMT0_REG,
-  SUN4I_I2S_FMT0_FMT_MASK,
-  val);
+   regmap_field_write(i2s->field_fmt_mode, val);
 
/* DAI clock polarity */
switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
@@ -722,6 +723,7 @@ static const struct sun4i_i2s_quirks sun4i_a10_i2s_quirks = 
{
.field_fmt_sr   = REG_FIELD(SUN4I_I2S_FMT0_REG, 4, 5),
.field_fmt_bclk = REG_FIELD(SUN4I_I2S_FMT0_REG, 6, 6),
.field_fmt_lrclk= REG_FIELD(SUN4I_I2S_FMT0_REG, 7, 7),
+   .field_fmt_mode = REG_FIELD(SUN4I_I2S_FMT0_REG, 0, 1),
.field_txchanmap= REG_FIELD(SUN4I_I2S_TX_CHAN_MAP_REG, 0, 31),
.field_rxchanmap= REG_FIELD(SUN4I_I2S_RX_CHAN_MAP_REG, 0, 31),
.field_txchansel= REG_FIELD(SUN4I_I2S_TX_CHAN_SEL_REG, 0, 2),
@@ -737,6 +739,7 @@ static const struct sun4i_i2s_quirks sun6i_a31_i2s_quirks = 
{
.field_fmt_sr   = REG_FIELD(SUN4I_I2S_FMT0_REG, 4, 5),
.field_fmt_bclk = REG_FIELD(SUN4I_I2S_FMT0_REG, 6, 6),
.field_fmt_lrclk= REG_FIELD(SUN4I_I2S_FMT0_REG, 7, 7),
+   .field_fmt_mode = REG_FIELD(SUN4I_I2S_FMT0_REG, 0, 1),
.field_txchanmap= REG_FIELD(SUN4I_I2S_TX_CHAN_MAP_REG, 0, 31),
.field_rxchanmap= REG_FIELD(SUN4I_I2S_RX_CHAN_MAP_REG, 0, 31),
.field_txchansel= REG_FIELD(SUN4I_I2S_TX_CHAN_SEL_REG, 0, 2),
@@ -776,6 +779,12 @@ static int sun4i_i2s_init_regmap_fields(struct device *dev,
if (IS_ERR(i2s->field_fmt_lrclk))
return PTR_ERR(i2s->field_fmt_lrclk);
 
+   i2s->field_fmt_mode =
+   devm_regmap_field_alloc(dev, i2s->regmap,
+   i2s->variant->field_fmt_mode);
+   if (IS_ERR(i2s->field_fmt_mode))
+   return PTR_ERR(i2s->field_fmt_mode);
+
i2s->field_txchanmap =
devm_regmap_field_alloc(dev, i2s->regmap,
i2s->variant->field_txchanmap);
-- 
2.14.1



[PATCH v5 6/8] ASoC: sun4i-i2s: Check for slave select bit

2017-08-19 Thread codekipper
From: Marcus Cooper 

The newer SoCs do not have this setting. Instead they set the pin
direction. Add a check to see if the bit is valid and if so set
it accordingly.

Signed-off-by: Marcus Cooper 
Reviewed-by: Chen-Yu Tsai 
---
 sound/soc/sunxi/sun4i-i2s.c | 37 +
 1 file changed, 21 insertions(+), 16 deletions(-)

diff --git a/sound/soc/sunxi/sun4i-i2s.c b/sound/soc/sunxi/sun4i-i2s.c
index d9910f6617ad..573acca24a2c 100644
--- a/sound/soc/sunxi/sun4i-i2s.c
+++ b/sound/soc/sunxi/sun4i-i2s.c
@@ -96,6 +96,7 @@
  * struct sun4i_i2s_quirks - Differences between SoC variants.
  *
  * @has_reset: SoC needs reset deasserted.
+ * @has_slave_select_bit: SoC has a bit to enable slave mode.
  * @reg_offset_txdata: offset of the tx fifo.
  * @sun4i_i2s_regmap: regmap config to use.
  * @mclk_offset: Value by which mclkdiv needs to be adjusted.
@@ -114,6 +115,7 @@
  */
 struct sun4i_i2s_quirks {
boolhas_reset;
+   boolhas_slave_select_bit;
unsigned intreg_offset_txdata;  /* TX FIFO */
const struct regmap_config  *sun4i_i2s_regmap;
unsigned intmclk_offset;
@@ -394,24 +396,25 @@ static int sun4i_i2s_set_fmt(struct snd_soc_dai *dai, 
unsigned int fmt)
regmap_field_write(i2s->field_fmt_bclk, bclk_polarity);
regmap_field_write(i2s->field_fmt_lrclk, lrclk_polarity);
 
-   /* DAI clock master masks */
-   switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
-   case SND_SOC_DAIFMT_CBS_CFS:
-   /* BCLK and LRCLK master */
-   val = SUN4I_I2S_CTRL_MODE_MASTER;
-   break;
-   case SND_SOC_DAIFMT_CBM_CFM:
-   /* BCLK and LRCLK slave */
-   val = SUN4I_I2S_CTRL_MODE_SLAVE;
-   break;
-   default:
-   return -EINVAL;
+   if (i2s->variant->has_slave_select_bit) {
+   /* DAI clock master masks */
+   switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+   case SND_SOC_DAIFMT_CBS_CFS:
+   /* BCLK and LRCLK master */
+   val = SUN4I_I2S_CTRL_MODE_MASTER;
+   break;
+   case SND_SOC_DAIFMT_CBM_CFM:
+   /* BCLK and LRCLK slave */
+   val = SUN4I_I2S_CTRL_MODE_SLAVE;
+   break;
+   default:
+   return -EINVAL;
+   }
+   regmap_update_bits(i2s->regmap, SUN4I_I2S_CTRL_REG,
+  SUN4I_I2S_CTRL_MODE_MASK,
+  val);
}
 
-   regmap_update_bits(i2s->regmap, SUN4I_I2S_CTRL_REG,
-  SUN4I_I2S_CTRL_MODE_MASK,
-  val);
-
/* Set significant bits in our FIFOs */
regmap_update_bits(i2s->regmap, SUN4I_I2S_FIFO_CTRL_REG,
   SUN4I_I2S_FIFO_CTRL_TX_MODE_MASK |
@@ -723,6 +726,7 @@ static const struct sun4i_i2s_quirks sun4i_a10_i2s_quirks = 
{
.field_fmt_sr   = REG_FIELD(SUN4I_I2S_FMT0_REG, 4, 5),
.field_fmt_bclk = REG_FIELD(SUN4I_I2S_FMT0_REG, 6, 6),
.field_fmt_lrclk= REG_FIELD(SUN4I_I2S_FMT0_REG, 7, 7),
+   .has_slave_select_bit   = true,
.field_fmt_mode = REG_FIELD(SUN4I_I2S_FMT0_REG, 0, 1),
.field_txchanmap= REG_FIELD(SUN4I_I2S_TX_CHAN_MAP_REG, 0, 31),
.field_rxchanmap= REG_FIELD(SUN4I_I2S_RX_CHAN_MAP_REG, 0, 31),
@@ -739,6 +743,7 @@ static const struct sun4i_i2s_quirks sun6i_a31_i2s_quirks = 
{
.field_fmt_sr   = REG_FIELD(SUN4I_I2S_FMT0_REG, 4, 5),
.field_fmt_bclk = REG_FIELD(SUN4I_I2S_FMT0_REG, 6, 6),
.field_fmt_lrclk= REG_FIELD(SUN4I_I2S_FMT0_REG, 7, 7),
+   .has_slave_select_bit   = true,
.field_fmt_mode = REG_FIELD(SUN4I_I2S_FMT0_REG, 0, 1),
.field_txchanmap= REG_FIELD(SUN4I_I2S_TX_CHAN_MAP_REG, 0, 31),
.field_rxchanmap= REG_FIELD(SUN4I_I2S_RX_CHAN_MAP_REG, 0, 31),
-- 
2.14.1



[PATCH v5 8/8] ASoC: sun4i-i2s: Add support for H3

2017-08-19 Thread codekipper
From: Marcus Cooper 

The sun8i-h3 introduces a lot of changes to the i2s block such
as different register locations, extended clock division and
more operational modes. As we have to consider the earlier
implementation then these changes need to be isolated.

None of the new functionality has been implemented yet, the
driver has just been expanded to allow it work on the H3 SoC.

Signed-off-by: Marcus Cooper 
Reviewed-by: Chen-Yu Tsai 
---
 .../devicetree/bindings/sound/sun4i-i2s.txt|   2 +
 sound/soc/sunxi/sun4i-i2s.c| 176 -
 2 files changed, 176 insertions(+), 2 deletions(-)

diff --git a/Documentation/devicetree/bindings/sound/sun4i-i2s.txt 
b/Documentation/devicetree/bindings/sound/sun4i-i2s.txt
index ee21da865771..fc5da6080759 100644
--- a/Documentation/devicetree/bindings/sound/sun4i-i2s.txt
+++ b/Documentation/devicetree/bindings/sound/sun4i-i2s.txt
@@ -8,6 +8,7 @@ Required properties:
 - compatible: should be one of the following:
- "allwinner,sun4i-a10-i2s"
- "allwinner,sun6i-a31-i2s"
+   - "allwinner,sun8i-h3-i2s"
 - reg: physical base address of the controller and length of memory mapped
   region.
 - interrupts: should contain the I2S interrupt.
@@ -22,6 +23,7 @@ Required properties:
 
 Required properties for the following compatibles:
- "allwinner,sun6i-a31-i2s"
+   - "allwinner,sun8i-h3-i2s"
 - resets: phandle to the reset line for this codec
 
 Example:
diff --git a/sound/soc/sunxi/sun4i-i2s.c b/sound/soc/sunxi/sun4i-i2s.c
index 19d50ca10d1f..04f92583a969 100644
--- a/sound/soc/sunxi/sun4i-i2s.c
+++ b/sound/soc/sunxi/sun4i-i2s.c
@@ -92,11 +92,41 @@
 #define SUN4I_I2S_RX_CHAN_SEL_REG  0x38
 #define SUN4I_I2S_RX_CHAN_MAP_REG  0x3c
 
+/* Defines required for sun8i-h3 support */
+#define SUN8I_I2S_CTRL_BCLK_OUTBIT(18)
+#define SUN8I_I2S_CTRL_LRCK_OUTBIT(17)
+
+#define SUN8I_I2S_FMT0_LRCK_PERIOD_MASKGENMASK(17, 8)
+#define SUN8I_I2S_FMT0_LRCK_PERIOD(period) ((period - 1) << 8)
+
+#define SUN8I_I2S_INT_STA_REG  0x0c
+#define SUN8I_I2S_FIFO_TX_REG  0x20
+
+#define SUN8I_I2S_CHAN_CFG_REG 0x30
+#define SUN8I_I2S_CHAN_CFG_RX_SLOT_NUM_MASKGENMASK(6, 4)
+#define SUN8I_I2S_CHAN_CFG_RX_SLOT_NUM(chan)   (chan - 1)
+#define SUN8I_I2S_CHAN_CFG_TX_SLOT_NUM_MASKGENMASK(2, 0)
+#define SUN8I_I2S_CHAN_CFG_TX_SLOT_NUM(chan)   (chan - 1)
+
+#define SUN8I_I2S_TX_CHAN_MAP_REG  0x44
+#define SUN8I_I2S_TX_CHAN_SEL_REG  0x34
+#define SUN8I_I2S_TX_CHAN_OFFSET_MASK  GENMASK(13, 11)
+#define SUN8I_I2S_TX_CHAN_OFFSET(offset)   (offset << 12)
+#define SUN8I_I2S_TX_CHAN_EN_MASK  GENMASK(11, 4)
+#define SUN8I_I2S_TX_CHAN_EN(num_chan) (((1 << num_chan) - 1) << 4)
+
+#define SUN8I_I2S_RX_CHAN_SEL_REG  0x54
+#define SUN8I_I2S_RX_CHAN_MAP_REG  0x58
+
 /**
  * struct sun4i_i2s_quirks - Differences between SoC variants.
  *
  * @has_reset: SoC needs reset deasserted.
  * @has_slave_select_bit: SoC has a bit to enable slave mode.
+ * @has_fmt_set_lrck_period: SoC requires lrclk period to be set.
+ * @has_chcfg: tx and rx slot number need to be set.
+ * @has_chsel_tx_chen: SoC requires that the tx channels are enabled.
+ * @has_chsel_offset: SoC uses offset for selecting dai operational mode.
  * @reg_offset_txdata: offset of the tx fifo.
  * @sun4i_i2s_regmap: regmap config to use.
  * @mclk_offset: Value by which mclkdiv needs to be adjusted.
@@ -116,6 +146,10 @@
 struct sun4i_i2s_quirks {
boolhas_reset;
boolhas_slave_select_bit;
+   boolhas_fmt_set_lrck_period;
+   boolhas_chcfg;
+   boolhas_chsel_tx_chen;
+   boolhas_chsel_offset;
unsigned intreg_offset_txdata;  /* TX FIFO */
const struct regmap_config  *sun4i_i2s_regmap;
unsigned intmclk_offset;
@@ -173,6 +207,7 @@ static const struct sun4i_i2s_clk_div sun4i_i2s_bclk_div[] 
= {
{ .div = 8, .val = 3 },
{ .div = 12, .val = 4 },
{ .div = 16, .val = 5 },
+   /* TODO - extend divide ratio supported by newer SoCs */
 };
 
 static const struct sun4i_i2s_clk_div sun4i_i2s_mclk_div[] = {
@@ -184,6 +219,7 @@ static const struct sun4i_i2s_clk_div sun4i_i2s_mclk_div[] 
= {
{ .div = 12, .val = 5 },
{ .div = 16, .val = 6 },
{ .div = 24, .val = 7 },
+   /* TODO - extend divide ratio supported by newer SoCs */
 };
 
 static int sun4i_i2s_get_bclk_div(struct sun4i_i2s *i2s,
@@ -295,6 +331,12 @@ static int sun4i_i2s_set_clk_rate(struct sun4i_i2s *i2s,
 
regmap_field_write(i2s->field_clkdiv_mclk_en, 1);
 
+   /* Set sync period */
+   if (i2s->variant->has_fmt_set_lrck_period)

[PATCH v5 0/8] ASoC: Add I2S support for Allwinner H3 SoCs

2017-08-19 Thread codekipper
From: Marcus Cooper <codekip...@gmail.com>

Hi All,
please find attached a series of patches to bring i2s support to the
Allwinner H3 SoC. This has been tested with the following setups:

A20 Olimex EVB connected to a pcm5102
Orange Pi 2 connected to a uda1380
Orange Pi 2 hdmi audio playback
Pine 64 connected to the audio DAC board

To get i2s working some additional patches are required which will be
delivered later. For now they have been pushed here

https://github.com/codekipper/linux-sunxi/commits/sunxi-audio-h3

I don't own a A33 device which uses the i2s block for the audio codec
so if someone could test against that it would be much appreciated.

I'm also wondering if there is a preferred way of setting the lrclk
size in the dts?..currently it is set to the sample width but for example
the pcm5102a wants it to be 32 bits whatever the sample rate.

Thanks in advance,
CK

---

v5 changes compared to v4 are:
- fixed bad logic in fmt0 set LRCK period define.
- fixed PTR_ERR checks in init of regmap fields
- added reviewed-by to commit messages
- removed delivered patches

v4 changes compared to v3 are:
- moved clkdiv variant adjustment out of function
- used PTR_ERR_OR_ZERO for checks
- tidy up of extra lines and lines over 80 chars.
- reduced names of polarity, wss and sr reg fields.
- added reviewed-by to commit messages
- added comments for functionality that hasn't been implemented yet.
- removed delivered patches

v3 changes compared to v2 are:
- initial changes to prepare driver for newer SoCs has been broken down
  into smaller patches
- reduce use of regmap fields to where just needed.
- clkdiv expansion will be delivered later.
- defines for H3 variant segregated.
- fixed regmap config issue with SUN8I_I2S_FIFO_TX_REG.

v2 changes compared to v1 are:
 - massive refactoring to remove duplicate code making use of regmap_fields.
 - extending the clock divisors.
 - removed code that should be delivered when we support 20/24bits

---

Marcus Cooper (8):
  ASoC: sun4i-i2s: Add regmap fields for channels
  ASoC: sun4i-i2s: Add regfields for word size select and sample
resolution
  ASoC: sun4i-i2s: bclk and lrclk polarity tidyup
  ASoC: sun4i-i2s: Add mclk enable regmap field
  ASoC: sun4i-i2s: Add regmap field to set DAI format
  ASoC: sun4i-i2s: Check for slave select bit
  ASoC: sun4i-i2s: Update global enable with bitmask
  ASoC: sun4i-i2s: Add support for H3

 .../devicetree/bindings/sound/sun4i-i2s.txt|   2 +
 sound/soc/sunxi/sun4i-i2s.c| 406 ++---
 2 files changed, 357 insertions(+), 51 deletions(-)

-- 
2.14.1



[PATCH v5 7/8] ASoC: sun4i-i2s: Update global enable with bitmask

2017-08-19 Thread codekipper
From: Marcus Cooper 

The default value of the config register is different on newer
SoCs and therefore enabling/disabling with a register write
will clear bits used to set the direction of the clock and frame
pins.

Signed-off-by: Marcus Cooper 
Reviewed-by: Chen-Yu Tsai 
---
 sound/soc/sunxi/sun4i-i2s.c | 7 ---
 1 file changed, 4 insertions(+), 3 deletions(-)

diff --git a/sound/soc/sunxi/sun4i-i2s.c b/sound/soc/sunxi/sun4i-i2s.c
index 573acca24a2c..19d50ca10d1f 100644
--- a/sound/soc/sunxi/sun4i-i2s.c
+++ b/sound/soc/sunxi/sun4i-i2s.c
@@ -529,8 +529,8 @@ static int sun4i_i2s_startup(struct snd_pcm_substream 
*substream,
struct sun4i_i2s *i2s = snd_soc_dai_get_drvdata(dai);
 
/* Enable the whole hardware block */
-   regmap_write(i2s->regmap, SUN4I_I2S_CTRL_REG,
-SUN4I_I2S_CTRL_GL_EN);
+   regmap_update_bits(i2s->regmap, SUN4I_I2S_CTRL_REG,
+  SUN4I_I2S_CTRL_GL_EN, SUN4I_I2S_CTRL_GL_EN);
 
/* Enable the first output line */
regmap_update_bits(i2s->regmap, SUN4I_I2S_CTRL_REG,
@@ -553,7 +553,8 @@ static void sun4i_i2s_shutdown(struct snd_pcm_substream 
*substream,
   SUN4I_I2S_CTRL_SDO_EN_MASK, 0);
 
/* Disable the whole hardware block */
-   regmap_write(i2s->regmap, SUN4I_I2S_CTRL_REG, 0);
+   regmap_update_bits(i2s->regmap, SUN4I_I2S_CTRL_REG,
+  SUN4I_I2S_CTRL_GL_EN, 0);
 }
 
 static int sun4i_i2s_set_sysclk(struct snd_soc_dai *dai, int clk_id,
-- 
2.14.1



[PATCH 1/2] devicetree: add Itead vendor prefix

2017-05-10 Thread codekipper
From: Marcus Cooper 

Add the "itead" vendor prefix for ITEAD Intelligent Systems Co.Ltd.

Signed-off-by: Marcus Cooper 
---
 Documentation/devicetree/bindings/vendor-prefixes.txt | 1 +
 1 file changed, 1 insertion(+)

diff --git a/Documentation/devicetree/bindings/vendor-prefixes.txt 
b/Documentation/devicetree/bindings/vendor-prefixes.txt
index c03d20140366..832759934517 100644
--- a/Documentation/devicetree/bindings/vendor-prefixes.txt
+++ b/Documentation/devicetree/bindings/vendor-prefixes.txt
@@ -158,6 +158,7 @@ iom Iomega Corporation
 isee   ISEE 2007 S.L.
 isil   Intersil
 issi   Integrated Silicon Solutions Inc.
+itead  ITEAD Intelligent Systems Co.Ltd
 jdiJapan Display Inc.
 jedec  JEDEC Solid State Technology Association
 karo   Ka-Ro electronics GmbH
-- 
2.12.2



[PATCH 2/2] devicetree: add Roofull vendor prefix

2017-05-10 Thread codekipper
From: Marcus Cooper 

Add the "roofull" vendor prefix for Shenzhen Roofull Technology Co, Ltd.

Signed-off-by: Marcus Cooper 
---
 Documentation/devicetree/bindings/vendor-prefixes.txt | 1 +
 1 file changed, 1 insertion(+)

diff --git a/Documentation/devicetree/bindings/vendor-prefixes.txt 
b/Documentation/devicetree/bindings/vendor-prefixes.txt
index 832759934517..4c16c63d7108 100644
--- a/Documentation/devicetree/bindings/vendor-prefixes.txt
+++ b/Documentation/devicetree/bindings/vendor-prefixes.txt
@@ -269,6 +269,7 @@ ricoh   Ricoh Co. Ltd.
 rikomagic  Rikomagic Tech Corp. Ltd
 rockchip   Fuzhou Rockchip Electronics Co., Ltd
 rohm   ROHM Semiconductor Co., Ltd
+roofullShenzhen Roofull Technology Co, Ltd
 samsungSamsung Semiconductor
 samtec Samtec/Softing company
 sandiskSandisk Corporation
-- 
2.12.2



[PATCH 0/3] ASoC: sun4i-i2s: Updates to the driver

2018-01-24 Thread codekipper
From: Marcus Cooper <codekip...@gmail.com>

Hi All,

here is a patch series to add some improvements to the sun4i-i2s driver
found whilst getting slave clocking and hdmi audio working on the newer
SoCs.
This has been tested on a Pine64 using the ES9023 audio POT board
(https://github.com/codekipper/linux-sunxi/commits/upstream)
BR,
CK

Marcus Cooper (3):
  ASoC: sun4i-i2s: Add set_tdm_slot functionality
  ASoC: sun4i-i2s: Do not divide clocks when slave
  ASoC: sun4i-i2s: Add regmap field to sign extend sample

 sound/soc/sunxi/sun4i-i2s.c | 154 
 1 file changed, 100 insertions(+), 54 deletions(-)

-- 
2.16.0



[PATCH 2/3] ASoC: sun4i-i2s: Do not divide clocks when slave

2018-01-24 Thread codekipper
From: Marcus Cooper 

There is no need to set the clock and calculate the division of
the audio pll for the bclk and sync signals when they are not
required.

Signed-off-by: Marcus Cooper 
---
 sound/soc/sunxi/sun4i-i2s.c | 116 
 1 file changed, 64 insertions(+), 52 deletions(-)

diff --git a/sound/soc/sunxi/sun4i-i2s.c b/sound/soc/sunxi/sun4i-i2s.c
index d7a9141514cf..626679057d0f 100644
--- a/sound/soc/sunxi/sun4i-i2s.c
+++ b/sound/soc/sunxi/sun4i-i2s.c
@@ -195,6 +195,8 @@ struct sun4i_i2s {
 
const struct sun4i_i2s_quirks   *variant;
 
+   bool bit_clk_master;
+
unsigned inttdm_slots;
unsigned intslot_width;
 };
@@ -282,67 +284,73 @@ static int sun4i_i2s_set_clk_rate(struct snd_soc_dai *dai,
int bclk_div, mclk_div;
int ret;
 
-   switch (rate) {
-   case 176400:
-   case 88200:
-   case 44100:
-   case 22050:
-   case 11025:
-   clk_rate = 22579200;
-   break;
+   if (i2s->bit_clk_master) {
+   switch (rate) {
+   case 176400:
+   case 88200:
+   case 44100:
+   case 22050:
+   case 11025:
+   clk_rate = 22579200;
+   break;
 
-   case 192000:
-   case 128000:
-   case 96000:
-   case 64000:
-   case 48000:
-   case 32000:
-   case 24000:
-   case 16000:
-   case 12000:
-   case 8000:
-   clk_rate = 24576000;
-   break;
+   case 192000:
+   case 128000:
+   case 96000:
+   case 64000:
+   case 48000:
+   case 32000:
+   case 24000:
+   case 16000:
+   case 12000:
+   case 8000:
+   clk_rate = 24576000;
+   break;
 
-   default:
-   dev_err(dai->dev, "Unsupported sample rate: %u\n", rate);
-   return -EINVAL;
-   }
+   default:
+   dev_err(dai->dev, "Unsupported sample rate: %u\n", 
rate);
+   return -EINVAL;
+   }
 
-   ret = clk_set_rate(i2s->mod_clk, clk_rate);
-   if (ret)
-   return ret;
+   ret = clk_set_rate(i2s->mod_clk, clk_rate);
+   if (ret) {
+   dev_err(dai->dev, "Unable to set clock\n");
+   return ret;
+   }
 
-   oversample_rate = i2s->mclk_freq / rate;
-   if (!sun4i_i2s_oversample_is_valid(oversample_rate)) {
-   dev_err(dai->dev, "Unsupported oversample rate: %d\n",
-   oversample_rate);
-   return -EINVAL;
-   }
+   oversample_rate = i2s->mclk_freq / rate;
+   if (!sun4i_i2s_oversample_is_valid(oversample_rate)) {
+   dev_err(dai->dev, "Unsupported oversample rate: %d\n",
+   oversample_rate);
+   return -EINVAL;
+   }
 
-   bclk_div = sun4i_i2s_get_bclk_div(i2s, oversample_rate,
- word_size);
-   if (bclk_div < 0) {
-   dev_err(dai->dev, "Unsupported BCLK divider: %d\n", bclk_div);
-   return -EINVAL;
-   }
+   bclk_div = sun4i_i2s_get_bclk_div(i2s, oversample_rate,
+ word_size);
+   if (bclk_div < 0) {
+   dev_err(dai->dev, "Unsupported BCLK divider: %d\n",
+   bclk_div);
+   return -EINVAL;
+   }
 
-   mclk_div = sun4i_i2s_get_mclk_div(i2s, oversample_rate,
- clk_rate, rate);
-   if (mclk_div < 0) {
-   dev_err(dai->dev, "Unsupported MCLK divider: %d\n", mclk_div);
-   return -EINVAL;
-   }
+   mclk_div = sun4i_i2s_get_mclk_div(i2s, oversample_rate,
+ clk_rate, rate);
+   if (mclk_div < 0) {
+   dev_err(dai->dev, "Unsupported MCLK divider: %d\n",
+   mclk_div);
+   return -EINVAL;
+   }
 
-   /* Adjust the clock division values if needed */
-   bclk_div += i2s->variant->bclk_offset;
-   mclk_div += i2s->variant->mclk_offset;
+   /* Adjust the clock division values if needed */
+   bclk_div += i2s->variant->bclk_offset;
+   mclk_div += i2s->variant->mclk_offset;
 
-   regmap_write(i2s->regmap, SUN4I_I2S_CLK_DIV_REG,
-SUN4I_I2S_CLK_DIV_BCLK(bclk_div) |
-SUN4I_I2S_CLK_DIV_MCLK(mclk_div));
+   regmap_write(i2s->regmap, SUN4I_I2S_CLK_DIV_REG,
+

[PATCH 1/3] ASoC: sun4i-i2s: Add set_tdm_slot functionality

2018-01-24 Thread codekipper
From: Marcus Cooper 

Some codecs require a different amount of a bit clocks per frame than
what is calculated by the sample width. Use the tdm slot bindings to
provide this mechanism.

Signed-off-by: Marcus Cooper 
---
 sound/soc/sunxi/sun4i-i2s.c | 23 +--
 1 file changed, 21 insertions(+), 2 deletions(-)

diff --git a/sound/soc/sunxi/sun4i-i2s.c b/sound/soc/sunxi/sun4i-i2s.c
index dca1143c1150..d7a9141514cf 100644
--- a/sound/soc/sunxi/sun4i-i2s.c
+++ b/sound/soc/sunxi/sun4i-i2s.c
@@ -96,6 +96,7 @@
 #define SUN8I_I2S_CTRL_BCLK_OUTBIT(18)
 #define SUN8I_I2S_CTRL_LRCK_OUTBIT(17)
 
+#define SUN8I_I2S_FMT0_LRCK_MAX_PERIOD (GENMASK(17, 8) >> 8)
 #define SUN8I_I2S_FMT0_LRCK_PERIOD_MASKGENMASK(17, 8)
 #define SUN8I_I2S_FMT0_LRCK_PERIOD(period) ((period - 1) << 8)
 
@@ -193,6 +194,9 @@ struct sun4i_i2s {
struct regmap_field *field_rxchansel;
 
const struct sun4i_i2s_quirks   *variant;
+
+   unsigned inttdm_slots;
+   unsigned intslot_width;
 };
 
 struct sun4i_i2s_clk_div {
@@ -344,7 +348,7 @@ static int sun4i_i2s_set_clk_rate(struct snd_soc_dai *dai,
if (i2s->variant->has_fmt_set_lrck_period)
regmap_update_bits(i2s->regmap, SUN4I_I2S_FMT0_REG,
   SUN8I_I2S_FMT0_LRCK_PERIOD_MASK,
-  SUN8I_I2S_FMT0_LRCK_PERIOD(32));
+  SUN8I_I2S_FMT0_LRCK_PERIOD(word_size));
 
return 0;
 }
@@ -418,7 +422,8 @@ static int sun4i_i2s_hw_params(struct snd_pcm_substream 
*substream,
   sr + i2s->variant->fmt_offset);
 
return sun4i_i2s_set_clk_rate(dai, params_rate(params),
- params_width(params));
+ i2s->tdm_slots ?
+ i2s->slot_width : params_width(params));
 }
 
 static int sun4i_i2s_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
@@ -691,6 +696,19 @@ static int sun4i_i2s_set_sysclk(struct snd_soc_dai *dai, 
int clk_id,
return 0;
 }
 
+static int sun4i_i2s_set_dai_tdm_slot(struct snd_soc_dai *dai,
+   unsigned int tx_mask, unsigned int rx_mask,
+   int slots, int width)
+{
+   struct sun4i_i2s *i2s = snd_soc_dai_get_drvdata(dai);
+
+   i2s->tdm_slots = slots;
+
+   i2s->slot_width = width;
+
+   return 0;
+}
+
 static const struct snd_soc_dai_ops sun4i_i2s_dai_ops = {
.hw_params  = sun4i_i2s_hw_params,
.set_fmt= sun4i_i2s_set_fmt,
@@ -698,6 +716,7 @@ static const struct snd_soc_dai_ops sun4i_i2s_dai_ops = {
.shutdown   = sun4i_i2s_shutdown,
.startup= sun4i_i2s_startup,
.trigger= sun4i_i2s_trigger,
+   .set_tdm_slot   = sun4i_i2s_set_dai_tdm_slot,
 };
 
 static int sun4i_i2s_dai_probe(struct snd_soc_dai *dai)
-- 
2.16.0



[PATCH 3/3] ASoC: sun4i-i2s: Add regmap field to sign extend sample

2018-01-24 Thread codekipper
From: Marcus Cooper 

On the newer SoCs this is set by default to transfer a 0 after
each sample in each slot. Add the regmap field to configure this
and set it so that it pads the sample with 0s.

Signed-off-by: Marcus Cooper 
---
 sound/soc/sunxi/sun4i-i2s.c | 15 +++
 1 file changed, 15 insertions(+)

diff --git a/sound/soc/sunxi/sun4i-i2s.c b/sound/soc/sunxi/sun4i-i2s.c
index 626679057d0f..9fda1240b717 100644
--- a/sound/soc/sunxi/sun4i-i2s.c
+++ b/sound/soc/sunxi/sun4i-i2s.c
@@ -139,6 +139,7 @@
  * @field_fmt_bclk: regmap field to set clk polarity.
  * @field_fmt_lrclk: regmap field to set frame polarity.
  * @field_fmt_mode: regmap field to set the operational mode.
+ * @field_fmt_sext: regmap field to set the sign extension.
  * @field_txchanmap: location of the tx channel mapping register.
  * @field_rxchanmap: location of the rx channel mapping register.
  * @field_txchansel: location of the tx channel select bit fields.
@@ -164,6 +165,7 @@ struct sun4i_i2s_quirks {
struct reg_fieldfield_fmt_bclk;
struct reg_fieldfield_fmt_lrclk;
struct reg_fieldfield_fmt_mode;
+   struct reg_fieldfield_fmt_sext;
struct reg_fieldfield_txchanmap;
struct reg_fieldfield_rxchanmap;
struct reg_fieldfield_txchansel;
@@ -188,6 +190,7 @@ struct sun4i_i2s {
struct regmap_field *field_fmt_bclk;
struct regmap_field *field_fmt_lrclk;
struct regmap_field *field_fmt_mode;
+   struct regmap_field *field_fmt_sext;
struct regmap_field *field_txchanmap;
struct regmap_field *field_rxchanmap;
struct regmap_field *field_txchansel;
@@ -358,6 +361,9 @@ static int sun4i_i2s_set_clk_rate(struct snd_soc_dai *dai,
   SUN8I_I2S_FMT0_LRCK_PERIOD_MASK,
   SUN8I_I2S_FMT0_LRCK_PERIOD(word_size));
 
+   /* Set sign extension to pad out LSB with 0 */
+   regmap_field_write(i2s->field_fmt_sext, 0);
+
return 0;
 }
 
@@ -929,6 +935,7 @@ static const struct sun4i_i2s_quirks sun4i_a10_i2s_quirks = 
{
.field_fmt_lrclk= REG_FIELD(SUN4I_I2S_FMT0_REG, 7, 7),
.has_slave_select_bit   = true,
.field_fmt_mode = REG_FIELD(SUN4I_I2S_FMT0_REG, 0, 1),
+   .field_fmt_sext = REG_FIELD(SUN4I_I2S_FMT1_REG, 8, 8),
.field_txchanmap= REG_FIELD(SUN4I_I2S_TX_CHAN_MAP_REG, 0, 31),
.field_rxchanmap= REG_FIELD(SUN4I_I2S_RX_CHAN_MAP_REG, 0, 31),
.field_txchansel= REG_FIELD(SUN4I_I2S_TX_CHAN_SEL_REG, 0, 2),
@@ -946,6 +953,7 @@ static const struct sun4i_i2s_quirks sun6i_a31_i2s_quirks = 
{
.field_fmt_lrclk= REG_FIELD(SUN4I_I2S_FMT0_REG, 7, 7),
.has_slave_select_bit   = true,
.field_fmt_mode = REG_FIELD(SUN4I_I2S_FMT0_REG, 0, 1),
+   .field_fmt_sext = REG_FIELD(SUN4I_I2S_FMT1_REG, 8, 8),
.field_txchanmap= REG_FIELD(SUN4I_I2S_TX_CHAN_MAP_REG, 0, 31),
.field_rxchanmap= REG_FIELD(SUN4I_I2S_RX_CHAN_MAP_REG, 0, 31),
.field_txchansel= REG_FIELD(SUN4I_I2S_TX_CHAN_SEL_REG, 0, 2),
@@ -986,6 +994,7 @@ static const struct sun4i_i2s_quirks sun8i_h3_i2s_quirks = {
.field_fmt_bclk = REG_FIELD(SUN4I_I2S_FMT0_REG, 7, 7),
.field_fmt_lrclk= REG_FIELD(SUN4I_I2S_FMT0_REG, 19, 19),
.field_fmt_mode = REG_FIELD(SUN4I_I2S_CTRL_REG, 4, 5),
+   .field_fmt_sext = REG_FIELD(SUN4I_I2S_FMT1_REG, 4, 5),
.field_txchanmap= REG_FIELD(SUN8I_I2S_TX_CHAN_MAP_REG, 0, 31),
.field_rxchanmap= REG_FIELD(SUN8I_I2S_RX_CHAN_MAP_REG, 0, 31),
.field_txchansel= REG_FIELD(SUN8I_I2S_TX_CHAN_SEL_REG, 0, 2),
@@ -1031,6 +1040,12 @@ static int sun4i_i2s_init_regmap_fields(struct device 
*dev,
if (IS_ERR(i2s->field_fmt_mode))
return PTR_ERR(i2s->field_fmt_mode);
 
+   i2s->field_fmt_sext =
+   devm_regmap_field_alloc(dev, i2s->regmap,
+   i2s->variant->field_fmt_sext);
+   if (IS_ERR(i2s->field_fmt_sext))
+   return PTR_ERR(i2s->field_fmt_sext);
+
i2s->field_txchanmap =
devm_regmap_field_alloc(dev, i2s->regmap,
i2s->variant->field_txchanmap);
-- 
2.16.0



[PATCH v2 3/6] ASoC: sun4i-i2s: Correct divider calculations

2018-03-12 Thread codekipper
From: Marcus Cooper 

The clock division circuitry is different on the H3 and later SoCs.
The division of bclk is now based on pll2.

Signed-off-by: Marcus Cooper 
---
 sound/soc/sunxi/sun4i-i2s.c | 76 +++--
 1 file changed, 52 insertions(+), 24 deletions(-)

diff --git a/sound/soc/sunxi/sun4i-i2s.c b/sound/soc/sunxi/sun4i-i2s.c
index 396b11346361..2bd0befa02a8 100644
--- a/sound/soc/sunxi/sun4i-i2s.c
+++ b/sound/soc/sunxi/sun4i-i2s.c
@@ -129,10 +129,10 @@
  * @has_chsel_offset: SoC uses offset for selecting dai operational mode.
  * @reg_offset_txdata: offset of the tx fifo.
  * @sun4i_i2s_regmap: regmap config to use.
- * @mclk_offset: Value by which mclkdiv needs to be adjusted.
- * @bclk_offset: Value by which bclkdiv needs to be adjusted.
  * @fmt_offset: Value by which wss and sr needs to be adjusted.
  * @field_clkdiv_mclk_en: regmap field to enable mclk output.
+ * @field_clkdiv_mclk: regmap field for mclkdiv.
+ * @field_clkdiv_bclk: regmap field for bclkdiv.
  * @field_fmt_wss: regmap field to set word select size.
  * @field_fmt_sr: regmap field to set sample resolution.
  * @field_fmt_bclk: regmap field to set clk polarity.
@@ -153,8 +153,6 @@ struct sun4i_i2s_quirks {
boolhas_chsel_offset;
unsigned intreg_offset_txdata;  /* TX FIFO */
const struct regmap_config  *sun4i_i2s_regmap;
-   unsigned intmclk_offset;
-   unsigned intbclk_offset;
unsigned intfmt_offset;
 
/* Register fields for i2s */
@@ -212,7 +210,25 @@ static const struct sun4i_i2s_clk_div sun4i_i2s_bclk_div[] 
= {
{ .div = 8, .val = 3 },
{ .div = 12, .val = 4 },
{ .div = 16, .val = 5 },
-   /* TODO - extend divide ratio supported by newer SoCs */
+};
+
+static const struct sun4i_i2s_clk_div sun8i_i2s_clk_div[] = {
+   { .div = 0, .val = 0 },
+   { .div = 1, .val = 1 },
+   { .div = 2, .val = 2 },
+   { .div = 4, .val = 3 },
+   { .div = 6, .val = 4 },
+   { .div = 8, .val = 5 },
+   { .div = 12, .val = 6 },
+   { .div = 16, .val = 7 },
+   { .div = 24, .val = 8 },
+   { .div = 32, .val = 9 },
+   { .div = 48, .val = 10 },
+   { .div = 64, .val = 11 },
+   { .div = 96, .val = 12 },
+   { .div = 128, .val = 13 },
+   { .div = 176, .val = 14 },
+   { .div = 192, .val = 15 },
 };
 
 static const struct sun4i_i2s_clk_div sun4i_i2s_mclk_div[] = {
@@ -224,21 +240,21 @@ static const struct sun4i_i2s_clk_div 
sun4i_i2s_mclk_div[] = {
{ .div = 12, .val = 5 },
{ .div = 16, .val = 6 },
{ .div = 24, .val = 7 },
-   /* TODO - extend divide ratio supported by newer SoCs */
 };
 
 static int sun4i_i2s_get_bclk_div(struct sun4i_i2s *i2s,
  unsigned int oversample_rate,
- unsigned int word_size)
+ unsigned int word_size,
+ const struct sun4i_i2s_clk_div *bdiv,
+ unsigned int size)
 {
int div = oversample_rate / word_size / 2;
int i;
 
-   for (i = 0; i < ARRAY_SIZE(sun4i_i2s_bclk_div); i++) {
-   const struct sun4i_i2s_clk_div *bdiv = _i2s_bclk_div[i];
-
+   for (i = 0; i < size; i++) {
if (bdiv->div == div)
return bdiv->val;
+   bdiv++;
}
 
return -EINVAL;
@@ -247,16 +263,17 @@ static int sun4i_i2s_get_bclk_div(struct sun4i_i2s *i2s,
 static int sun4i_i2s_get_mclk_div(struct sun4i_i2s *i2s,
  unsigned int oversample_rate,
  unsigned int module_rate,
- unsigned int sampling_rate)
+ unsigned int sampling_rate,
+ const struct sun4i_i2s_clk_div *mdiv,
+ unsigned int size)
 {
int div = module_rate / sampling_rate / oversample_rate;
int i;
 
-   for (i = 0; i < ARRAY_SIZE(sun4i_i2s_mclk_div); i++) {
-   const struct sun4i_i2s_clk_div *mdiv = _i2s_mclk_div[i];
-
+   for (i = 0; i < size; i++) {
if (mdiv->div == div)
return mdiv->val;
+   mdiv++;
}
 
return -EINVAL;
@@ -321,24 +338,37 @@ static int sun4i_i2s_set_clk_rate(struct snd_soc_dai *dai,
return -EINVAL;
}
 
-   bclk_div = sun4i_i2s_get_bclk_div(i2s, oversample_rate,
- word_size);
+   if (i2s->variant->has_fmt_set_lrck_period)
+   bclk_div = sun4i_i2s_get_bclk_div(i2s, clk_rate / rate,
+ word_size,
+ 

[PATCH v2 6/6] ASoC: sun4i-i2s: Add support for loopback

2018-03-12 Thread codekipper
From: Marcus Cooper 

The DAI has a loopback register which can be set and therefore routes
the transmit fifo to receive fifo. This is useful for testing the block
without the need for any external hardware.

Signed-off-by: Marcus Cooper 
---
 Documentation/devicetree/bindings/sound/sun4i-i2s.txt |  3 +++
 sound/soc/sunxi/sun4i-i2s.c   | 11 +++
 2 files changed, 14 insertions(+)

diff --git a/Documentation/devicetree/bindings/sound/sun4i-i2s.txt 
b/Documentation/devicetree/bindings/sound/sun4i-i2s.txt
index 3f966ac61b9e..325e3d4571f1 100644
--- a/Documentation/devicetree/bindings/sound/sun4i-i2s.txt
+++ b/Documentation/devicetree/bindings/sound/sun4i-i2s.txt
@@ -32,6 +32,9 @@ Optional properties:
 - allwinner,slot-width-override:if this property is present then the dai is
configured to extend the slot width to the
value specified. Min 8, Max 32.
+- loopback:if this property is present then the dai is configured in
+   loopback mode where the output fifo is redirected to the input
+   fifo.
 
 - allwinner,playback-channels:  if this property is present then the number
of available channels is extended and the
diff --git a/sound/soc/sunxi/sun4i-i2s.c b/sound/soc/sunxi/sun4i-i2s.c
index 7cf4dfe440de..a3c33814d33e 100644
--- a/sound/soc/sunxi/sun4i-i2s.c
+++ b/sound/soc/sunxi/sun4i-i2s.c
@@ -31,6 +31,7 @@
 #define SUN4I_I2S_CTRL_MODE_MASK   BIT(5)
 #define SUN4I_I2S_CTRL_MODE_SLAVE  (1 << 5)
 #define SUN4I_I2S_CTRL_MODE_MASTER (0 << 5)
+#define SUN4I_I2S_CTRL_LOOPBIT(3)
 #define SUN4I_I2S_CTRL_TX_EN   BIT(2)
 #define SUN4I_I2S_CTRL_RX_EN   BIT(1)
 #define SUN4I_I2S_CTRL_GL_EN   BIT(0)
@@ -195,6 +196,8 @@ struct sun4i_i2s {
 
const struct sun4i_i2s_quirks   *variant;
 
+   bool loopback;
+
unsigned intslot_width;
 };
 
@@ -639,6 +642,11 @@ static void sun4i_i2s_start_capture(struct sun4i_i2s *i2s)
regmap_update_bits(i2s->regmap, SUN4I_I2S_DMA_INT_CTRL_REG,
   SUN4I_I2S_DMA_INT_CTRL_RX_DRQ_EN,
   SUN4I_I2S_DMA_INT_CTRL_RX_DRQ_EN);
+
+   /* Debugging without codec */
+   if (i2s->loopback)
+   regmap_update_bits(i2s->regmap, SUN4I_I2S_CTRL_REG,
+  SUN4I_I2S_CTRL_LOOP, SUN4I_I2S_CTRL_LOOP);
 }
 
 static void sun4i_i2s_start_playback(struct sun4i_i2s *i2s)
@@ -1204,6 +1212,9 @@ static int sun4i_i2s_probe(struct platform_device *pdev)
soc_dai->playback.channels_max = val;
}
 
+   if (of_property_read_bool(pdev->dev.of_node, "loopback"))
+   i2s->loopback = true;
+
pm_runtime_enable(>dev);
if (!pm_runtime_enabled(>dev)) {
ret = sun4i_i2s_runtime_resume(>dev);
-- 
2.16.2



[PATCH v2 1/6] ASoC: sun4i-i2s: Add slot width override

2018-03-12 Thread codekipper
From: Marcus Cooper 

Some codecs require a different amount of a bit clocks per frame
than what is calculated by using the sample width. Use a slot
width override property to provide this mechanism.

Signed-off-by: Marcus Cooper 
---
 Documentation/devicetree/bindings/sound/sun4i-i2s.txt |  5 +
 sound/soc/sunxi/sun4i-i2s.c   | 15 ---
 2 files changed, 17 insertions(+), 3 deletions(-)

diff --git a/Documentation/devicetree/bindings/sound/sun4i-i2s.txt 
b/Documentation/devicetree/bindings/sound/sun4i-i2s.txt
index b9d50d6cdef3..48addef65b8f 100644
--- a/Documentation/devicetree/bindings/sound/sun4i-i2s.txt
+++ b/Documentation/devicetree/bindings/sound/sun4i-i2s.txt
@@ -28,6 +28,11 @@ Required properties for the following compatibles:
- "allwinner,sun8i-h3-i2s"
 - resets: phandle to the reset line for this codec
 
+Optional properties:
+- allwinner,slot-width-override:if this property is present then the dai is
+   configured to extend the slot width to the
+   value specified. Min 8, Max 32.
+
 Example:
 
 i2s0: i2s@1c22400 {
diff --git a/sound/soc/sunxi/sun4i-i2s.c b/sound/soc/sunxi/sun4i-i2s.c
index a4aa931ebfae..873054a6c3be 100644
--- a/sound/soc/sunxi/sun4i-i2s.c
+++ b/sound/soc/sunxi/sun4i-i2s.c
@@ -193,6 +193,8 @@ struct sun4i_i2s {
struct regmap_field *field_rxchansel;
 
const struct sun4i_i2s_quirks   *variant;
+
+   unsigned intslot_width;
 };
 
 struct sun4i_i2s_clk_div {
@@ -344,7 +346,7 @@ static int sun4i_i2s_set_clk_rate(struct snd_soc_dai *dai,
if (i2s->variant->has_fmt_set_lrck_period)
regmap_update_bits(i2s->regmap, SUN4I_I2S_FMT0_REG,
   SUN8I_I2S_FMT0_LRCK_PERIOD_MASK,
-  SUN8I_I2S_FMT0_LRCK_PERIOD(32));
+  SUN8I_I2S_FMT0_LRCK_PERIOD(word_size));
 
return 0;
 }
@@ -418,7 +420,8 @@ static int sun4i_i2s_hw_params(struct snd_pcm_substream 
*substream,
   sr + i2s->variant->fmt_offset);
 
return sun4i_i2s_set_clk_rate(dai, params_rate(params),
- params_width(params));
+ i2s->slot_width ?
+ i2s->slot_width : params_width(params));
 }
 
 static int sun4i_i2s_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
@@ -1029,7 +1032,7 @@ static int sun4i_i2s_probe(struct platform_device *pdev)
struct sun4i_i2s *i2s;
struct resource *res;
void __iomem *regs;
-   int irq, ret;
+   int irq, ret, val;
 
i2s = devm_kzalloc(>dev, sizeof(*i2s), GFP_KERNEL);
if (!i2s)
@@ -1096,6 +1099,12 @@ static int sun4i_i2s_probe(struct platform_device *pdev)
i2s->capture_dma_data.addr = res->start + SUN4I_I2S_FIFO_RX_REG;
i2s->capture_dma_data.maxburst = 8;
 
+   if (!of_property_read_u32(pdev->dev.of_node,
+ "allwinner,slot-width-override", )) {
+   if (val >= 8 && val <= 32)
+   i2s->slot_width = val;
+   }
+
pm_runtime_enable(>dev);
if (!pm_runtime_enabled(>dev)) {
ret = sun4i_i2s_runtime_resume(>dev);
-- 
2.16.2



[PATCH v2 4/6] ASoC: sun4i-i2s: Add multi-lane functionality

2018-03-12 Thread codekipper
From: Marcus Cooper 

The i2s block supports multi-lane i2s output however this functionality
is only possible in earlier SoCs where the pins are exposed and for
the i2s block used for HDMI audio on the later SoCs.

To enable this functionality, an optional property has been added to
the bindings.

Signed-off-by: Marcus Cooper 
---
 .../devicetree/bindings/sound/sun4i-i2s.txt|  3 ++
 sound/soc/sunxi/sun4i-i2s.c| 48 +-
 2 files changed, 41 insertions(+), 10 deletions(-)

diff --git a/Documentation/devicetree/bindings/sound/sun4i-i2s.txt 
b/Documentation/devicetree/bindings/sound/sun4i-i2s.txt
index 48addef65b8f..3f966ac61b9e 100644
--- a/Documentation/devicetree/bindings/sound/sun4i-i2s.txt
+++ b/Documentation/devicetree/bindings/sound/sun4i-i2s.txt
@@ -33,6 +33,9 @@ Optional properties:
configured to extend the slot width to the
value specified. Min 8, Max 32.
 
+- allwinner,playback-channels:  if this property is present then the number
+   of available channels is extended and the
+   outputs enabled.
 Example:
 
 i2s0: i2s@1c22400 {
diff --git a/sound/soc/sunxi/sun4i-i2s.c b/sound/soc/sunxi/sun4i-i2s.c
index 2bd0befa02a8..436480df1844 100644
--- a/sound/soc/sunxi/sun4i-i2s.c
+++ b/sound/soc/sunxi/sun4i-i2s.c
@@ -27,7 +27,7 @@
 
 #define SUN4I_I2S_CTRL_REG 0x00
 #define SUN4I_I2S_CTRL_SDO_EN_MASK GENMASK(11, 8)
-#define SUN4I_I2S_CTRL_SDO_EN(sdo) BIT(8 + (sdo))
+#define SUN4I_I2S_CTRL_SDO_EN(lines)   (((1 << lines) - 1) << 8)
 #define SUN4I_I2S_CTRL_MODE_MASK   BIT(5)
 #define SUN4I_I2S_CTRL_MODE_SLAVE  (1 << 5)
 #define SUN4I_I2S_CTRL_MODE_MASTER (0 << 5)
@@ -394,14 +394,23 @@ static int sun4i_i2s_hw_params(struct snd_pcm_substream 
*substream,
struct sun4i_i2s *i2s = snd_soc_dai_get_drvdata(dai);
int sr, wss, channels;
u32 width;
+   int lines;
 
channels = params_channels(params);
-   if (channels != 2) {
+   if ((channels > dai->driver->playback.channels_max) ||
+   (channels < dai->driver->playback.channels_min)) {
dev_err(dai->dev, "Unsupported number of channels: %d\n",
channels);
return -EINVAL;
}
 
+   lines = (channels + 1) / 2;
+
+   /* Enable the required output lines */
+   regmap_update_bits(i2s->regmap, SUN4I_I2S_CTRL_REG,
+  SUN4I_I2S_CTRL_SDO_EN_MASK,
+  SUN4I_I2S_CTRL_SDO_EN(lines));
+
if (i2s->variant->has_chcfg) {
regmap_update_bits(i2s->regmap, SUN8I_I2S_CHAN_CFG_REG,
   SUN8I_I2S_CHAN_CFG_TX_SLOT_NUM_MASK,
@@ -412,8 +421,19 @@ static int sun4i_i2s_hw_params(struct snd_pcm_substream 
*substream,
}
 
/* Map the channels for playback and capture */
-   regmap_field_write(i2s->field_txchanmap, 0x76543210);
regmap_field_write(i2s->field_rxchanmap, 0x3210);
+   regmap_field_write(i2s->field_txchanmap, 0x10);
+   if (i2s->variant->has_chsel_tx_chen) {
+   if (channels > 2)
+   regmap_write(i2s->regmap,
+SUN8I_I2S_TX_CHAN_MAP_REG+4, 0x32);
+   if (channels > 4)
+   regmap_write(i2s->regmap,
+SUN8I_I2S_TX_CHAN_MAP_REG+8, 0x54);
+   if (channels > 6)
+   regmap_write(i2s->regmap,
+SUN8I_I2S_TX_CHAN_MAP_REG+12, 0x76);
+   }
 
/* Configure the channels */
regmap_field_write(i2s->field_txchansel,
@@ -692,12 +712,6 @@ static int sun4i_i2s_startup(struct snd_pcm_substream 
*substream,
regmap_update_bits(i2s->regmap, SUN4I_I2S_CTRL_REG,
   SUN4I_I2S_CTRL_GL_EN, SUN4I_I2S_CTRL_GL_EN);
 
-   /* Enable the first output line */
-   regmap_update_bits(i2s->regmap, SUN4I_I2S_CTRL_REG,
-  SUN4I_I2S_CTRL_SDO_EN_MASK,
-  SUN4I_I2S_CTRL_SDO_EN(0));
-
-
return clk_prepare_enable(i2s->mod_clk);
 }
 
@@ -1073,6 +1087,7 @@ static int sun4i_i2s_init_regmap_fields(struct device 
*dev,
 static int sun4i_i2s_probe(struct platform_device *pdev)
 {
struct sun4i_i2s *i2s;
+   struct snd_soc_dai_driver *soc_dai;
struct resource *res;
void __iomem *regs;
int irq, ret, val;
@@ -1148,6 +1163,19 @@ static int sun4i_i2s_probe(struct platform_device *pdev)
i2s->slot_width = val;
}
 
+   soc_dai = devm_kmemdup(>dev, _i2s_dai,
+  sizeof(*soc_dai), GFP_KERNEL);
+   if (!soc_dai) {
+   ret = -ENOMEM;
+   

[PATCH v2 5/6] ASoc: sun4i-i2s: Add 20, 24 and 32 bit support

2018-03-12 Thread codekipper
From: Marcus Cooper 

Extend the functionality of the driver to include support of 20 and
24 bits per sample for the earlier SoCs.

Newer SoCs can also handle 32bit samples.

Signed-off-by: Marcus Cooper 
---
 sound/soc/sunxi/sun4i-i2s.c | 34 +++---
 1 file changed, 31 insertions(+), 3 deletions(-)

diff --git a/sound/soc/sunxi/sun4i-i2s.c b/sound/soc/sunxi/sun4i-i2s.c
index 436480df1844..7cf4dfe440de 100644
--- a/sound/soc/sunxi/sun4i-i2s.c
+++ b/sound/soc/sunxi/sun4i-i2s.c
@@ -451,6 +451,11 @@ static int sun4i_i2s_hw_params(struct snd_pcm_substream 
*substream,
case 16:
width = DMA_SLAVE_BUSWIDTH_2_BYTES;
break;
+   case 20:
+   case 24:
+   case 32:
+   width = DMA_SLAVE_BUSWIDTH_4_BYTES;
+   break;
default:
dev_err(dai->dev, "Unsupported physical sample width: %d\n",
params_physical_width(params));
@@ -463,7 +468,18 @@ static int sun4i_i2s_hw_params(struct snd_pcm_substream 
*substream,
sr = 0;
wss = 0;
break;
-
+   case 20:
+   sr = 1;
+   wss = 1;
+   break;
+   case 24:
+   sr = 2;
+   wss = 2;
+   break;
+   case 32:
+   sr = 4;
+   wss = 4;
+   break;
default:
dev_err(dai->dev, "Unsupported sample width: %d\n",
params_width(params));
@@ -766,6 +782,13 @@ static int sun4i_i2s_dai_probe(struct snd_soc_dai *dai)
return 0;
 }
 
+#define SUN4I_FORMATS  (SNDRV_PCM_FMTBIT_S16_LE | \
+SNDRV_PCM_FMTBIT_S20_3LE | \
+SNDRV_PCM_FMTBIT_S24_LE)
+
+#define SUN8I_FORMATS  (SUN4I_FORMATS | \
+SNDRV_PCM_FMTBIT_S32_LE)
+
 static struct snd_soc_dai_driver sun4i_i2s_dai = {
.probe = sun4i_i2s_dai_probe,
.capture = {
@@ -773,14 +796,14 @@ static struct snd_soc_dai_driver sun4i_i2s_dai = {
.channels_min = 2,
.channels_max = 2,
.rates = SNDRV_PCM_RATE_8000_192000,
-   .formats = SNDRV_PCM_FMTBIT_S16_LE,
+   .formats = SUN4I_FORMATS,
},
.playback = {
.stream_name = "Playback",
.channels_min = 2,
.channels_max = 2,
.rates = SNDRV_PCM_RATE_8000_192000,
-   .formats = SNDRV_PCM_FMTBIT_S16_LE,
+   .formats = SUN4I_FORMATS,
},
.ops = _i2s_dai_ops,
.symmetric_rates = 1,
@@ -1170,6 +1193,11 @@ static int sun4i_i2s_probe(struct platform_device *pdev)
goto err_pm_disable;
}
 
+   if (i2s->variant->has_fmt_set_lrck_period) {
+   soc_dai->playback.formats = SUN8I_FORMATS;
+   soc_dai->capture.formats = SUN8I_FORMATS;
+   }
+
if (!of_property_read_u32(pdev->dev.of_node,
  "allwinner,playback-channels", )) {
if (val >= 2 && val <= 8)
-- 
2.16.2



[PATCH v2 2/6] ASoC: sun4i-i2s: Add regmap field to sign extend sample

2018-03-12 Thread codekipper
From: Marcus Cooper 

On the newer SoCs (H3, H5, A64 etc) this is set by default to
transfer a 0 after each sample in each slot whereas on the
earlier SoCs (A20, A31 etc) the default sign extension is to
pad the LSB.

Add the regmap field to configure this and set it so that it
pads the sample with 0s.

Signed-off-by: Marcus Cooper 
---
 sound/soc/sunxi/sun4i-i2s.c | 15 +++
 1 file changed, 15 insertions(+)

diff --git a/sound/soc/sunxi/sun4i-i2s.c b/sound/soc/sunxi/sun4i-i2s.c
index 873054a6c3be..396b11346361 100644
--- a/sound/soc/sunxi/sun4i-i2s.c
+++ b/sound/soc/sunxi/sun4i-i2s.c
@@ -138,6 +138,7 @@
  * @field_fmt_bclk: regmap field to set clk polarity.
  * @field_fmt_lrclk: regmap field to set frame polarity.
  * @field_fmt_mode: regmap field to set the operational mode.
+ * @field_fmt_sext: regmap field to set the sign extension.
  * @field_txchanmap: location of the tx channel mapping register.
  * @field_rxchanmap: location of the rx channel mapping register.
  * @field_txchansel: location of the tx channel select bit fields.
@@ -163,6 +164,7 @@ struct sun4i_i2s_quirks {
struct reg_fieldfield_fmt_bclk;
struct reg_fieldfield_fmt_lrclk;
struct reg_fieldfield_fmt_mode;
+   struct reg_fieldfield_fmt_sext;
struct reg_fieldfield_txchanmap;
struct reg_fieldfield_rxchanmap;
struct reg_fieldfield_txchansel;
@@ -187,6 +189,7 @@ struct sun4i_i2s {
struct regmap_field *field_fmt_bclk;
struct regmap_field *field_fmt_lrclk;
struct regmap_field *field_fmt_mode;
+   struct regmap_field *field_fmt_sext;
struct regmap_field *field_txchanmap;
struct regmap_field *field_rxchanmap;
struct regmap_field *field_txchansel;
@@ -348,6 +351,9 @@ static int sun4i_i2s_set_clk_rate(struct snd_soc_dai *dai,
   SUN8I_I2S_FMT0_LRCK_PERIOD_MASK,
   SUN8I_I2S_FMT0_LRCK_PERIOD(word_size));
 
+   /* Set sign extension to pad out LSB with 0 */
+   regmap_field_write(i2s->field_fmt_sext, 0);
+
return 0;
 }
 
@@ -901,6 +907,7 @@ static const struct sun4i_i2s_quirks sun4i_a10_i2s_quirks = 
{
.field_fmt_lrclk= REG_FIELD(SUN4I_I2S_FMT0_REG, 7, 7),
.has_slave_select_bit   = true,
.field_fmt_mode = REG_FIELD(SUN4I_I2S_FMT0_REG, 0, 1),
+   .field_fmt_sext = REG_FIELD(SUN4I_I2S_FMT1_REG, 8, 8),
.field_txchanmap= REG_FIELD(SUN4I_I2S_TX_CHAN_MAP_REG, 0, 31),
.field_rxchanmap= REG_FIELD(SUN4I_I2S_RX_CHAN_MAP_REG, 0, 31),
.field_txchansel= REG_FIELD(SUN4I_I2S_TX_CHAN_SEL_REG, 0, 2),
@@ -918,6 +925,7 @@ static const struct sun4i_i2s_quirks sun6i_a31_i2s_quirks = 
{
.field_fmt_lrclk= REG_FIELD(SUN4I_I2S_FMT0_REG, 7, 7),
.has_slave_select_bit   = true,
.field_fmt_mode = REG_FIELD(SUN4I_I2S_FMT0_REG, 0, 1),
+   .field_fmt_sext = REG_FIELD(SUN4I_I2S_FMT1_REG, 8, 8),
.field_txchanmap= REG_FIELD(SUN4I_I2S_TX_CHAN_MAP_REG, 0, 31),
.field_rxchanmap= REG_FIELD(SUN4I_I2S_RX_CHAN_MAP_REG, 0, 31),
.field_txchansel= REG_FIELD(SUN4I_I2S_TX_CHAN_SEL_REG, 0, 2),
@@ -958,6 +966,7 @@ static const struct sun4i_i2s_quirks sun8i_h3_i2s_quirks = {
.field_fmt_bclk = REG_FIELD(SUN4I_I2S_FMT0_REG, 7, 7),
.field_fmt_lrclk= REG_FIELD(SUN4I_I2S_FMT0_REG, 19, 19),
.field_fmt_mode = REG_FIELD(SUN4I_I2S_CTRL_REG, 4, 5),
+   .field_fmt_sext = REG_FIELD(SUN4I_I2S_FMT1_REG, 4, 5),
.field_txchanmap= REG_FIELD(SUN8I_I2S_TX_CHAN_MAP_REG, 0, 31),
.field_rxchanmap= REG_FIELD(SUN8I_I2S_RX_CHAN_MAP_REG, 0, 31),
.field_txchansel= REG_FIELD(SUN8I_I2S_TX_CHAN_SEL_REG, 0, 2),
@@ -1003,6 +1012,12 @@ static int sun4i_i2s_init_regmap_fields(struct device 
*dev,
if (IS_ERR(i2s->field_fmt_mode))
return PTR_ERR(i2s->field_fmt_mode);
 
+   i2s->field_fmt_sext =
+   devm_regmap_field_alloc(dev, i2s->regmap,
+   i2s->variant->field_fmt_sext);
+   if (IS_ERR(i2s->field_fmt_sext))
+   return PTR_ERR(i2s->field_fmt_sext);
+
i2s->field_txchanmap =
devm_regmap_field_alloc(dev, i2s->regmap,
i2s->variant->field_txchanmap);
-- 
2.16.2



[PATCH v2 0/6] ASoC: sun4i-i2s: Updates to the driver

2018-03-12 Thread codekipper
From: Marcus Cooper <codekip...@gmail.com>

Hi All,

here is a patch series to add some improvements to the sun4i-i2s driver
found whilst getting slave clocking and hdmi audio working on the newer
SoCs. The original attempt had some changes related to the slave work
but I've left them out for this release as I would still like to do some
more investigations.

The functionality included with the new patch set has been extended to
cover more sample resolutions, multi-lane data output for HDMI audio
and loopback so block testing can be made without an external codec.

I've also moved away from using tdm to set the slot width and now use
a dedicated property.

This has been tested on a Pine64 using the ES9023 audio POT board
(https://github.com/codekipper/linux-sunxi/commits/upstream)
and HDMI audio
(https://github.com/codekipper/linux-sunxi/commits/sunxi-wip-a64)

BR,
CK

---
v2 changes compared to v1 are:
 - removed slave mode changes which didn't set mclk and bclk div.
 - removed use of tdm and now use a dedicated property.
 - fix commit message to better explain reason for sign extending
 - add divider calculations for newer SoCs.
 - add support for multi-lane i2s data output.
 - add support for 20, 24 and 32 bit samples.
 - add loopback property so blocks can be tested without a codec.

---

Marcus Cooper (6):
  ASoC: sun4i-i2s: Add slot width override
  ASoC: sun4i-i2s: Add regmap field to sign extend sample
  ASoC: sun4i-i2s: Correct divider calculations
  ASoC: sun4i-i2s: Add multi-lane functionality
  ASoc: sun4i-i2s: Add 20, 24 and 32 bit support
  ASoC: sun4i-i2s: Add support for loopback

 .../devicetree/bindings/sound/sun4i-i2s.txt|  11 ++
 sound/soc/sunxi/sun4i-i2s.c| 199 -
 2 files changed, 170 insertions(+), 40 deletions(-)

-- 
2.16.2



[PATCH v2 3/6] ASoC: sun4i-i2s: Correct divider calculations

2018-03-12 Thread codekipper
From: Marcus Cooper 

The clock division circuitry is different on the H3 and later SoCs.
The division of bclk is now based on pll2.

Signed-off-by: Marcus Cooper 
---
 sound/soc/sunxi/sun4i-i2s.c | 76 +++--
 1 file changed, 52 insertions(+), 24 deletions(-)

diff --git a/sound/soc/sunxi/sun4i-i2s.c b/sound/soc/sunxi/sun4i-i2s.c
index 396b11346361..2bd0befa02a8 100644
--- a/sound/soc/sunxi/sun4i-i2s.c
+++ b/sound/soc/sunxi/sun4i-i2s.c
@@ -129,10 +129,10 @@
  * @has_chsel_offset: SoC uses offset for selecting dai operational mode.
  * @reg_offset_txdata: offset of the tx fifo.
  * @sun4i_i2s_regmap: regmap config to use.
- * @mclk_offset: Value by which mclkdiv needs to be adjusted.
- * @bclk_offset: Value by which bclkdiv needs to be adjusted.
  * @fmt_offset: Value by which wss and sr needs to be adjusted.
  * @field_clkdiv_mclk_en: regmap field to enable mclk output.
+ * @field_clkdiv_mclk: regmap field for mclkdiv.
+ * @field_clkdiv_bclk: regmap field for bclkdiv.
  * @field_fmt_wss: regmap field to set word select size.
  * @field_fmt_sr: regmap field to set sample resolution.
  * @field_fmt_bclk: regmap field to set clk polarity.
@@ -153,8 +153,6 @@ struct sun4i_i2s_quirks {
boolhas_chsel_offset;
unsigned intreg_offset_txdata;  /* TX FIFO */
const struct regmap_config  *sun4i_i2s_regmap;
-   unsigned intmclk_offset;
-   unsigned intbclk_offset;
unsigned intfmt_offset;
 
/* Register fields for i2s */
@@ -212,7 +210,25 @@ static const struct sun4i_i2s_clk_div sun4i_i2s_bclk_div[] 
= {
{ .div = 8, .val = 3 },
{ .div = 12, .val = 4 },
{ .div = 16, .val = 5 },
-   /* TODO - extend divide ratio supported by newer SoCs */
+};
+
+static const struct sun4i_i2s_clk_div sun8i_i2s_clk_div[] = {
+   { .div = 0, .val = 0 },
+   { .div = 1, .val = 1 },
+   { .div = 2, .val = 2 },
+   { .div = 4, .val = 3 },
+   { .div = 6, .val = 4 },
+   { .div = 8, .val = 5 },
+   { .div = 12, .val = 6 },
+   { .div = 16, .val = 7 },
+   { .div = 24, .val = 8 },
+   { .div = 32, .val = 9 },
+   { .div = 48, .val = 10 },
+   { .div = 64, .val = 11 },
+   { .div = 96, .val = 12 },
+   { .div = 128, .val = 13 },
+   { .div = 176, .val = 14 },
+   { .div = 192, .val = 15 },
 };
 
 static const struct sun4i_i2s_clk_div sun4i_i2s_mclk_div[] = {
@@ -224,21 +240,21 @@ static const struct sun4i_i2s_clk_div 
sun4i_i2s_mclk_div[] = {
{ .div = 12, .val = 5 },
{ .div = 16, .val = 6 },
{ .div = 24, .val = 7 },
-   /* TODO - extend divide ratio supported by newer SoCs */
 };
 
 static int sun4i_i2s_get_bclk_div(struct sun4i_i2s *i2s,
  unsigned int oversample_rate,
- unsigned int word_size)
+ unsigned int word_size,
+ const struct sun4i_i2s_clk_div *bdiv,
+ unsigned int size)
 {
int div = oversample_rate / word_size / 2;
int i;
 
-   for (i = 0; i < ARRAY_SIZE(sun4i_i2s_bclk_div); i++) {
-   const struct sun4i_i2s_clk_div *bdiv = _i2s_bclk_div[i];
-
+   for (i = 0; i < size; i++) {
if (bdiv->div == div)
return bdiv->val;
+   bdiv++;
}
 
return -EINVAL;
@@ -247,16 +263,17 @@ static int sun4i_i2s_get_bclk_div(struct sun4i_i2s *i2s,
 static int sun4i_i2s_get_mclk_div(struct sun4i_i2s *i2s,
  unsigned int oversample_rate,
  unsigned int module_rate,
- unsigned int sampling_rate)
+ unsigned int sampling_rate,
+ const struct sun4i_i2s_clk_div *mdiv,
+ unsigned int size)
 {
int div = module_rate / sampling_rate / oversample_rate;
int i;
 
-   for (i = 0; i < ARRAY_SIZE(sun4i_i2s_mclk_div); i++) {
-   const struct sun4i_i2s_clk_div *mdiv = _i2s_mclk_div[i];
-
+   for (i = 0; i < size; i++) {
if (mdiv->div == div)
return mdiv->val;
+   mdiv++;
}
 
return -EINVAL;
@@ -321,24 +338,37 @@ static int sun4i_i2s_set_clk_rate(struct snd_soc_dai *dai,
return -EINVAL;
}
 
-   bclk_div = sun4i_i2s_get_bclk_div(i2s, oversample_rate,
- word_size);
+   if (i2s->variant->has_fmt_set_lrck_period)
+   bclk_div = sun4i_i2s_get_bclk_div(i2s, clk_rate / rate,
+ word_size,
+ sun8i_i2s_clk_div,
+ 

[PATCH v2 6/6] ASoC: sun4i-i2s: Add support for loopback

2018-03-12 Thread codekipper
From: Marcus Cooper 

The DAI has a loopback register which can be set and therefore routes
the transmit fifo to receive fifo. This is useful for testing the block
without the need for any external hardware.

Signed-off-by: Marcus Cooper 
---
 Documentation/devicetree/bindings/sound/sun4i-i2s.txt |  3 +++
 sound/soc/sunxi/sun4i-i2s.c   | 11 +++
 2 files changed, 14 insertions(+)

diff --git a/Documentation/devicetree/bindings/sound/sun4i-i2s.txt 
b/Documentation/devicetree/bindings/sound/sun4i-i2s.txt
index 3f966ac61b9e..325e3d4571f1 100644
--- a/Documentation/devicetree/bindings/sound/sun4i-i2s.txt
+++ b/Documentation/devicetree/bindings/sound/sun4i-i2s.txt
@@ -32,6 +32,9 @@ Optional properties:
 - allwinner,slot-width-override:if this property is present then the dai is
configured to extend the slot width to the
value specified. Min 8, Max 32.
+- loopback:if this property is present then the dai is configured in
+   loopback mode where the output fifo is redirected to the input
+   fifo.
 
 - allwinner,playback-channels:  if this property is present then the number
of available channels is extended and the
diff --git a/sound/soc/sunxi/sun4i-i2s.c b/sound/soc/sunxi/sun4i-i2s.c
index 7cf4dfe440de..a3c33814d33e 100644
--- a/sound/soc/sunxi/sun4i-i2s.c
+++ b/sound/soc/sunxi/sun4i-i2s.c
@@ -31,6 +31,7 @@
 #define SUN4I_I2S_CTRL_MODE_MASK   BIT(5)
 #define SUN4I_I2S_CTRL_MODE_SLAVE  (1 << 5)
 #define SUN4I_I2S_CTRL_MODE_MASTER (0 << 5)
+#define SUN4I_I2S_CTRL_LOOPBIT(3)
 #define SUN4I_I2S_CTRL_TX_EN   BIT(2)
 #define SUN4I_I2S_CTRL_RX_EN   BIT(1)
 #define SUN4I_I2S_CTRL_GL_EN   BIT(0)
@@ -195,6 +196,8 @@ struct sun4i_i2s {
 
const struct sun4i_i2s_quirks   *variant;
 
+   bool loopback;
+
unsigned intslot_width;
 };
 
@@ -639,6 +642,11 @@ static void sun4i_i2s_start_capture(struct sun4i_i2s *i2s)
regmap_update_bits(i2s->regmap, SUN4I_I2S_DMA_INT_CTRL_REG,
   SUN4I_I2S_DMA_INT_CTRL_RX_DRQ_EN,
   SUN4I_I2S_DMA_INT_CTRL_RX_DRQ_EN);
+
+   /* Debugging without codec */
+   if (i2s->loopback)
+   regmap_update_bits(i2s->regmap, SUN4I_I2S_CTRL_REG,
+  SUN4I_I2S_CTRL_LOOP, SUN4I_I2S_CTRL_LOOP);
 }
 
 static void sun4i_i2s_start_playback(struct sun4i_i2s *i2s)
@@ -1204,6 +1212,9 @@ static int sun4i_i2s_probe(struct platform_device *pdev)
soc_dai->playback.channels_max = val;
}
 
+   if (of_property_read_bool(pdev->dev.of_node, "loopback"))
+   i2s->loopback = true;
+
pm_runtime_enable(>dev);
if (!pm_runtime_enabled(>dev)) {
ret = sun4i_i2s_runtime_resume(>dev);
-- 
2.16.2



[PATCH v2 1/6] ASoC: sun4i-i2s: Add slot width override

2018-03-12 Thread codekipper
From: Marcus Cooper 

Some codecs require a different amount of a bit clocks per frame
than what is calculated by using the sample width. Use a slot
width override property to provide this mechanism.

Signed-off-by: Marcus Cooper 
---
 Documentation/devicetree/bindings/sound/sun4i-i2s.txt |  5 +
 sound/soc/sunxi/sun4i-i2s.c   | 15 ---
 2 files changed, 17 insertions(+), 3 deletions(-)

diff --git a/Documentation/devicetree/bindings/sound/sun4i-i2s.txt 
b/Documentation/devicetree/bindings/sound/sun4i-i2s.txt
index b9d50d6cdef3..48addef65b8f 100644
--- a/Documentation/devicetree/bindings/sound/sun4i-i2s.txt
+++ b/Documentation/devicetree/bindings/sound/sun4i-i2s.txt
@@ -28,6 +28,11 @@ Required properties for the following compatibles:
- "allwinner,sun8i-h3-i2s"
 - resets: phandle to the reset line for this codec
 
+Optional properties:
+- allwinner,slot-width-override:if this property is present then the dai is
+   configured to extend the slot width to the
+   value specified. Min 8, Max 32.
+
 Example:
 
 i2s0: i2s@1c22400 {
diff --git a/sound/soc/sunxi/sun4i-i2s.c b/sound/soc/sunxi/sun4i-i2s.c
index a4aa931ebfae..873054a6c3be 100644
--- a/sound/soc/sunxi/sun4i-i2s.c
+++ b/sound/soc/sunxi/sun4i-i2s.c
@@ -193,6 +193,8 @@ struct sun4i_i2s {
struct regmap_field *field_rxchansel;
 
const struct sun4i_i2s_quirks   *variant;
+
+   unsigned intslot_width;
 };
 
 struct sun4i_i2s_clk_div {
@@ -344,7 +346,7 @@ static int sun4i_i2s_set_clk_rate(struct snd_soc_dai *dai,
if (i2s->variant->has_fmt_set_lrck_period)
regmap_update_bits(i2s->regmap, SUN4I_I2S_FMT0_REG,
   SUN8I_I2S_FMT0_LRCK_PERIOD_MASK,
-  SUN8I_I2S_FMT0_LRCK_PERIOD(32));
+  SUN8I_I2S_FMT0_LRCK_PERIOD(word_size));
 
return 0;
 }
@@ -418,7 +420,8 @@ static int sun4i_i2s_hw_params(struct snd_pcm_substream 
*substream,
   sr + i2s->variant->fmt_offset);
 
return sun4i_i2s_set_clk_rate(dai, params_rate(params),
- params_width(params));
+ i2s->slot_width ?
+ i2s->slot_width : params_width(params));
 }
 
 static int sun4i_i2s_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
@@ -1029,7 +1032,7 @@ static int sun4i_i2s_probe(struct platform_device *pdev)
struct sun4i_i2s *i2s;
struct resource *res;
void __iomem *regs;
-   int irq, ret;
+   int irq, ret, val;
 
i2s = devm_kzalloc(>dev, sizeof(*i2s), GFP_KERNEL);
if (!i2s)
@@ -1096,6 +1099,12 @@ static int sun4i_i2s_probe(struct platform_device *pdev)
i2s->capture_dma_data.addr = res->start + SUN4I_I2S_FIFO_RX_REG;
i2s->capture_dma_data.maxburst = 8;
 
+   if (!of_property_read_u32(pdev->dev.of_node,
+ "allwinner,slot-width-override", )) {
+   if (val >= 8 && val <= 32)
+   i2s->slot_width = val;
+   }
+
pm_runtime_enable(>dev);
if (!pm_runtime_enabled(>dev)) {
ret = sun4i_i2s_runtime_resume(>dev);
-- 
2.16.2



[PATCH v2 4/6] ASoC: sun4i-i2s: Add multi-lane functionality

2018-03-12 Thread codekipper
From: Marcus Cooper 

The i2s block supports multi-lane i2s output however this functionality
is only possible in earlier SoCs where the pins are exposed and for
the i2s block used for HDMI audio on the later SoCs.

To enable this functionality, an optional property has been added to
the bindings.

Signed-off-by: Marcus Cooper 
---
 .../devicetree/bindings/sound/sun4i-i2s.txt|  3 ++
 sound/soc/sunxi/sun4i-i2s.c| 48 +-
 2 files changed, 41 insertions(+), 10 deletions(-)

diff --git a/Documentation/devicetree/bindings/sound/sun4i-i2s.txt 
b/Documentation/devicetree/bindings/sound/sun4i-i2s.txt
index 48addef65b8f..3f966ac61b9e 100644
--- a/Documentation/devicetree/bindings/sound/sun4i-i2s.txt
+++ b/Documentation/devicetree/bindings/sound/sun4i-i2s.txt
@@ -33,6 +33,9 @@ Optional properties:
configured to extend the slot width to the
value specified. Min 8, Max 32.
 
+- allwinner,playback-channels:  if this property is present then the number
+   of available channels is extended and the
+   outputs enabled.
 Example:
 
 i2s0: i2s@1c22400 {
diff --git a/sound/soc/sunxi/sun4i-i2s.c b/sound/soc/sunxi/sun4i-i2s.c
index 2bd0befa02a8..436480df1844 100644
--- a/sound/soc/sunxi/sun4i-i2s.c
+++ b/sound/soc/sunxi/sun4i-i2s.c
@@ -27,7 +27,7 @@
 
 #define SUN4I_I2S_CTRL_REG 0x00
 #define SUN4I_I2S_CTRL_SDO_EN_MASK GENMASK(11, 8)
-#define SUN4I_I2S_CTRL_SDO_EN(sdo) BIT(8 + (sdo))
+#define SUN4I_I2S_CTRL_SDO_EN(lines)   (((1 << lines) - 1) << 8)
 #define SUN4I_I2S_CTRL_MODE_MASK   BIT(5)
 #define SUN4I_I2S_CTRL_MODE_SLAVE  (1 << 5)
 #define SUN4I_I2S_CTRL_MODE_MASTER (0 << 5)
@@ -394,14 +394,23 @@ static int sun4i_i2s_hw_params(struct snd_pcm_substream 
*substream,
struct sun4i_i2s *i2s = snd_soc_dai_get_drvdata(dai);
int sr, wss, channels;
u32 width;
+   int lines;
 
channels = params_channels(params);
-   if (channels != 2) {
+   if ((channels > dai->driver->playback.channels_max) ||
+   (channels < dai->driver->playback.channels_min)) {
dev_err(dai->dev, "Unsupported number of channels: %d\n",
channels);
return -EINVAL;
}
 
+   lines = (channels + 1) / 2;
+
+   /* Enable the required output lines */
+   regmap_update_bits(i2s->regmap, SUN4I_I2S_CTRL_REG,
+  SUN4I_I2S_CTRL_SDO_EN_MASK,
+  SUN4I_I2S_CTRL_SDO_EN(lines));
+
if (i2s->variant->has_chcfg) {
regmap_update_bits(i2s->regmap, SUN8I_I2S_CHAN_CFG_REG,
   SUN8I_I2S_CHAN_CFG_TX_SLOT_NUM_MASK,
@@ -412,8 +421,19 @@ static int sun4i_i2s_hw_params(struct snd_pcm_substream 
*substream,
}
 
/* Map the channels for playback and capture */
-   regmap_field_write(i2s->field_txchanmap, 0x76543210);
regmap_field_write(i2s->field_rxchanmap, 0x3210);
+   regmap_field_write(i2s->field_txchanmap, 0x10);
+   if (i2s->variant->has_chsel_tx_chen) {
+   if (channels > 2)
+   regmap_write(i2s->regmap,
+SUN8I_I2S_TX_CHAN_MAP_REG+4, 0x32);
+   if (channels > 4)
+   regmap_write(i2s->regmap,
+SUN8I_I2S_TX_CHAN_MAP_REG+8, 0x54);
+   if (channels > 6)
+   regmap_write(i2s->regmap,
+SUN8I_I2S_TX_CHAN_MAP_REG+12, 0x76);
+   }
 
/* Configure the channels */
regmap_field_write(i2s->field_txchansel,
@@ -692,12 +712,6 @@ static int sun4i_i2s_startup(struct snd_pcm_substream 
*substream,
regmap_update_bits(i2s->regmap, SUN4I_I2S_CTRL_REG,
   SUN4I_I2S_CTRL_GL_EN, SUN4I_I2S_CTRL_GL_EN);
 
-   /* Enable the first output line */
-   regmap_update_bits(i2s->regmap, SUN4I_I2S_CTRL_REG,
-  SUN4I_I2S_CTRL_SDO_EN_MASK,
-  SUN4I_I2S_CTRL_SDO_EN(0));
-
-
return clk_prepare_enable(i2s->mod_clk);
 }
 
@@ -1073,6 +1087,7 @@ static int sun4i_i2s_init_regmap_fields(struct device 
*dev,
 static int sun4i_i2s_probe(struct platform_device *pdev)
 {
struct sun4i_i2s *i2s;
+   struct snd_soc_dai_driver *soc_dai;
struct resource *res;
void __iomem *regs;
int irq, ret, val;
@@ -1148,6 +1163,19 @@ static int sun4i_i2s_probe(struct platform_device *pdev)
i2s->slot_width = val;
}
 
+   soc_dai = devm_kmemdup(>dev, _i2s_dai,
+  sizeof(*soc_dai), GFP_KERNEL);
+   if (!soc_dai) {
+   ret = -ENOMEM;
+   goto err_pm_disable;
+   }
+
+   if 

[PATCH v2 5/6] ASoc: sun4i-i2s: Add 20, 24 and 32 bit support

2018-03-12 Thread codekipper
From: Marcus Cooper 

Extend the functionality of the driver to include support of 20 and
24 bits per sample for the earlier SoCs.

Newer SoCs can also handle 32bit samples.

Signed-off-by: Marcus Cooper 
---
 sound/soc/sunxi/sun4i-i2s.c | 34 +++---
 1 file changed, 31 insertions(+), 3 deletions(-)

diff --git a/sound/soc/sunxi/sun4i-i2s.c b/sound/soc/sunxi/sun4i-i2s.c
index 436480df1844..7cf4dfe440de 100644
--- a/sound/soc/sunxi/sun4i-i2s.c
+++ b/sound/soc/sunxi/sun4i-i2s.c
@@ -451,6 +451,11 @@ static int sun4i_i2s_hw_params(struct snd_pcm_substream 
*substream,
case 16:
width = DMA_SLAVE_BUSWIDTH_2_BYTES;
break;
+   case 20:
+   case 24:
+   case 32:
+   width = DMA_SLAVE_BUSWIDTH_4_BYTES;
+   break;
default:
dev_err(dai->dev, "Unsupported physical sample width: %d\n",
params_physical_width(params));
@@ -463,7 +468,18 @@ static int sun4i_i2s_hw_params(struct snd_pcm_substream 
*substream,
sr = 0;
wss = 0;
break;
-
+   case 20:
+   sr = 1;
+   wss = 1;
+   break;
+   case 24:
+   sr = 2;
+   wss = 2;
+   break;
+   case 32:
+   sr = 4;
+   wss = 4;
+   break;
default:
dev_err(dai->dev, "Unsupported sample width: %d\n",
params_width(params));
@@ -766,6 +782,13 @@ static int sun4i_i2s_dai_probe(struct snd_soc_dai *dai)
return 0;
 }
 
+#define SUN4I_FORMATS  (SNDRV_PCM_FMTBIT_S16_LE | \
+SNDRV_PCM_FMTBIT_S20_3LE | \
+SNDRV_PCM_FMTBIT_S24_LE)
+
+#define SUN8I_FORMATS  (SUN4I_FORMATS | \
+SNDRV_PCM_FMTBIT_S32_LE)
+
 static struct snd_soc_dai_driver sun4i_i2s_dai = {
.probe = sun4i_i2s_dai_probe,
.capture = {
@@ -773,14 +796,14 @@ static struct snd_soc_dai_driver sun4i_i2s_dai = {
.channels_min = 2,
.channels_max = 2,
.rates = SNDRV_PCM_RATE_8000_192000,
-   .formats = SNDRV_PCM_FMTBIT_S16_LE,
+   .formats = SUN4I_FORMATS,
},
.playback = {
.stream_name = "Playback",
.channels_min = 2,
.channels_max = 2,
.rates = SNDRV_PCM_RATE_8000_192000,
-   .formats = SNDRV_PCM_FMTBIT_S16_LE,
+   .formats = SUN4I_FORMATS,
},
.ops = _i2s_dai_ops,
.symmetric_rates = 1,
@@ -1170,6 +1193,11 @@ static int sun4i_i2s_probe(struct platform_device *pdev)
goto err_pm_disable;
}
 
+   if (i2s->variant->has_fmt_set_lrck_period) {
+   soc_dai->playback.formats = SUN8I_FORMATS;
+   soc_dai->capture.formats = SUN8I_FORMATS;
+   }
+
if (!of_property_read_u32(pdev->dev.of_node,
  "allwinner,playback-channels", )) {
if (val >= 2 && val <= 8)
-- 
2.16.2



[PATCH v2 0/6] ASoC: sun4i-i2s: Updates to the driver

2018-03-12 Thread codekipper
From: Marcus Cooper 

Hi All,

here is a patch series to add some improvements to the sun4i-i2s driver
found whilst getting slave clocking and hdmi audio working on the newer
SoCs. The original attempt had some changes related to the slave work
but I've left them out for this release as I would still like to do some
more investigations.

The functionality included with the new patch set has been extended to
cover more sample resolutions, multi-lane data output for HDMI audio
and loopback so block testing can be made without an external codec.

I've also moved away from using tdm to set the slot width and now use
a dedicated property.

This has been tested on a Pine64 using the ES9023 audio POT board
(https://github.com/codekipper/linux-sunxi/commits/upstream)
and HDMI audio
(https://github.com/codekipper/linux-sunxi/commits/sunxi-wip-a64)

BR,
CK

---
v2 changes compared to v1 are:
 - removed slave mode changes which didn't set mclk and bclk div.
 - removed use of tdm and now use a dedicated property.
 - fix commit message to better explain reason for sign extending
 - add divider calculations for newer SoCs.
 - add support for multi-lane i2s data output.
 - add support for 20, 24 and 32 bit samples.
 - add loopback property so blocks can be tested without a codec.

---

Marcus Cooper (6):
  ASoC: sun4i-i2s: Add slot width override
  ASoC: sun4i-i2s: Add regmap field to sign extend sample
  ASoC: sun4i-i2s: Correct divider calculations
  ASoC: sun4i-i2s: Add multi-lane functionality
  ASoc: sun4i-i2s: Add 20, 24 and 32 bit support
  ASoC: sun4i-i2s: Add support for loopback

 .../devicetree/bindings/sound/sun4i-i2s.txt|  11 ++
 sound/soc/sunxi/sun4i-i2s.c| 199 -
 2 files changed, 170 insertions(+), 40 deletions(-)

-- 
2.16.2



[PATCH v2 2/6] ASoC: sun4i-i2s: Add regmap field to sign extend sample

2018-03-12 Thread codekipper
From: Marcus Cooper 

On the newer SoCs (H3, H5, A64 etc) this is set by default to
transfer a 0 after each sample in each slot whereas on the
earlier SoCs (A20, A31 etc) the default sign extension is to
pad the LSB.

Add the regmap field to configure this and set it so that it
pads the sample with 0s.

Signed-off-by: Marcus Cooper 
---
 sound/soc/sunxi/sun4i-i2s.c | 15 +++
 1 file changed, 15 insertions(+)

diff --git a/sound/soc/sunxi/sun4i-i2s.c b/sound/soc/sunxi/sun4i-i2s.c
index 873054a6c3be..396b11346361 100644
--- a/sound/soc/sunxi/sun4i-i2s.c
+++ b/sound/soc/sunxi/sun4i-i2s.c
@@ -138,6 +138,7 @@
  * @field_fmt_bclk: regmap field to set clk polarity.
  * @field_fmt_lrclk: regmap field to set frame polarity.
  * @field_fmt_mode: regmap field to set the operational mode.
+ * @field_fmt_sext: regmap field to set the sign extension.
  * @field_txchanmap: location of the tx channel mapping register.
  * @field_rxchanmap: location of the rx channel mapping register.
  * @field_txchansel: location of the tx channel select bit fields.
@@ -163,6 +164,7 @@ struct sun4i_i2s_quirks {
struct reg_fieldfield_fmt_bclk;
struct reg_fieldfield_fmt_lrclk;
struct reg_fieldfield_fmt_mode;
+   struct reg_fieldfield_fmt_sext;
struct reg_fieldfield_txchanmap;
struct reg_fieldfield_rxchanmap;
struct reg_fieldfield_txchansel;
@@ -187,6 +189,7 @@ struct sun4i_i2s {
struct regmap_field *field_fmt_bclk;
struct regmap_field *field_fmt_lrclk;
struct regmap_field *field_fmt_mode;
+   struct regmap_field *field_fmt_sext;
struct regmap_field *field_txchanmap;
struct regmap_field *field_rxchanmap;
struct regmap_field *field_txchansel;
@@ -348,6 +351,9 @@ static int sun4i_i2s_set_clk_rate(struct snd_soc_dai *dai,
   SUN8I_I2S_FMT0_LRCK_PERIOD_MASK,
   SUN8I_I2S_FMT0_LRCK_PERIOD(word_size));
 
+   /* Set sign extension to pad out LSB with 0 */
+   regmap_field_write(i2s->field_fmt_sext, 0);
+
return 0;
 }
 
@@ -901,6 +907,7 @@ static const struct sun4i_i2s_quirks sun4i_a10_i2s_quirks = 
{
.field_fmt_lrclk= REG_FIELD(SUN4I_I2S_FMT0_REG, 7, 7),
.has_slave_select_bit   = true,
.field_fmt_mode = REG_FIELD(SUN4I_I2S_FMT0_REG, 0, 1),
+   .field_fmt_sext = REG_FIELD(SUN4I_I2S_FMT1_REG, 8, 8),
.field_txchanmap= REG_FIELD(SUN4I_I2S_TX_CHAN_MAP_REG, 0, 31),
.field_rxchanmap= REG_FIELD(SUN4I_I2S_RX_CHAN_MAP_REG, 0, 31),
.field_txchansel= REG_FIELD(SUN4I_I2S_TX_CHAN_SEL_REG, 0, 2),
@@ -918,6 +925,7 @@ static const struct sun4i_i2s_quirks sun6i_a31_i2s_quirks = 
{
.field_fmt_lrclk= REG_FIELD(SUN4I_I2S_FMT0_REG, 7, 7),
.has_slave_select_bit   = true,
.field_fmt_mode = REG_FIELD(SUN4I_I2S_FMT0_REG, 0, 1),
+   .field_fmt_sext = REG_FIELD(SUN4I_I2S_FMT1_REG, 8, 8),
.field_txchanmap= REG_FIELD(SUN4I_I2S_TX_CHAN_MAP_REG, 0, 31),
.field_rxchanmap= REG_FIELD(SUN4I_I2S_RX_CHAN_MAP_REG, 0, 31),
.field_txchansel= REG_FIELD(SUN4I_I2S_TX_CHAN_SEL_REG, 0, 2),
@@ -958,6 +966,7 @@ static const struct sun4i_i2s_quirks sun8i_h3_i2s_quirks = {
.field_fmt_bclk = REG_FIELD(SUN4I_I2S_FMT0_REG, 7, 7),
.field_fmt_lrclk= REG_FIELD(SUN4I_I2S_FMT0_REG, 19, 19),
.field_fmt_mode = REG_FIELD(SUN4I_I2S_CTRL_REG, 4, 5),
+   .field_fmt_sext = REG_FIELD(SUN4I_I2S_FMT1_REG, 4, 5),
.field_txchanmap= REG_FIELD(SUN8I_I2S_TX_CHAN_MAP_REG, 0, 31),
.field_rxchanmap= REG_FIELD(SUN8I_I2S_RX_CHAN_MAP_REG, 0, 31),
.field_txchansel= REG_FIELD(SUN8I_I2S_TX_CHAN_SEL_REG, 0, 2),
@@ -1003,6 +1012,12 @@ static int sun4i_i2s_init_regmap_fields(struct device 
*dev,
if (IS_ERR(i2s->field_fmt_mode))
return PTR_ERR(i2s->field_fmt_mode);
 
+   i2s->field_fmt_sext =
+   devm_regmap_field_alloc(dev, i2s->regmap,
+   i2s->variant->field_fmt_sext);
+   if (IS_ERR(i2s->field_fmt_sext))
+   return PTR_ERR(i2s->field_fmt_sext);
+
i2s->field_txchanmap =
devm_regmap_field_alloc(dev, i2s->regmap,
i2s->variant->field_txchanmap);
-- 
2.16.2



  1   2   3   >