All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 0/4] Qualcomm IPQ4019 Audio driver addition
@ 2016-07-15  7:07 ` njaigane
  0 siblings, 0 replies; 24+ messages in thread
From: njaigane-sgV2jX0FEOL9JmXXK+q4OQ @ 2016-07-15  7:07 UTC (permalink / raw)
  To: linux-arm-msm-u79uwXL29TY76Z2rM5mHXA
  Cc: linux-A+ZNKFmMK5xy9aJCnZT0Uw, devicetree-u79uwXL29TY76Z2rM5mHXA,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	linux-soc-u79uwXL29TY76Z2rM5mHXA,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	twp-sgV2jX0FEOL9JmXXK+q4OQ, andy.gross-QSEj5FYQhm4dnm+yROfE0A,
	david.brown-QSEj5FYQhm4dnm+yROfE0A,
	robh+dt-DgEjT+Ai2ygdnm+yROfE0A, pawel.moll-5wv7dgnIgG8,
	mark.rutland-5wv7dgnIgG8, ijc+devicetree-KcIKpvwj1kUDXYZnReoRVg,
	galak-sgV2jX0FEOL9JmXXK+q4OQ, linux-I+IVW8TIWO2tmTQ+vhA3Yw,
	mturquette-rdvid1DuHRBWk0Htik3J/w, sboyd-sgV2jX0FEOL9JmXXK+q4OQ,
	linus.walleij-QSEj5FYQhm4dnm+yROfE0A,
	plai-sgV2jX0FEOL9JmXXK+q4OQ, bgoswami-sgV2jX0FEOL9JmXXK+q4OQ,
	lgirdwood-Re5JQEeQqe8AvxtiuMwx3w, broonie-DgEjT+Ai2ygdnm+yROfE0A,
	perex-/Fr2/VpizcU, tiwai-IBi9RG/b67k,
	bjorn.andersson-QSEj5FYQhm4dnm+yROfE0A,
	varada-sgV2jX0FEOL9JmXXK+q4OQ, pradeepb-sgV2jX0FEOL9JmXXK+q4OQ,
	snlakshm-sgV2jX0FEOL9JmXXK+q4OQ,
	linux-clk-u79uwXL29TY76Z2rM5mHXA,
	linux-gpio-u79uwXL29TY76Z2rM5mHXA,
	alsa-devel-K7yf7f+aM1XWsZ/bQMPhNw,
	bselvara-sgV2jX0FEOL9JmXXK+q4OQ, Jaiganesh Narayanan

From: Jaiganesh Narayanan <njaigane-sgV2jX0FEOL9JmXXK+q4OQ@public.gmane.org>

These patches add the support for Qualcomm IPQ4019 ASoC
with the ALSA based audio drivers. The patches are broken

1. Device Tree support
2. Audio clock driver support
3. TLMM / Pinctrl support
4. ALSA based audio drivers

Jaiganesh Narayanan (4):
  qcom: ipq4019: Add ipq4019 ASoC device tree changes
  qcom: ipq4019: ASoC clock driver support
  qcom: ipq4019: ASoC tlmm/pinctrl support
  qcom: ipq4019: Add ASoC driver modules

 .../bindings/sound/qca,ipq4019-audio-adss.txt      |  20 +
 .../bindings/sound/qca,ipq4019-audio.txt           |  13 +
 .../bindings/sound/qca,ipq4019-codec.txt           |  15 +
 .../devicetree/bindings/sound/qca,ipq4019-i2s.txt  |  33 +
 .../devicetree/bindings/sound/qca,ipq4019-i2s1.txt |  29 +
 .../devicetree/bindings/sound/qca,ipq4019-i2s2.txt |  29 +
 .../devicetree/bindings/sound/qca,ipq4019-mbox.txt |  23 +
 .../bindings/sound/qca,ipq4019-pcm-i2s.txt         |  15 +
 .../bindings/sound/qca,ipq4019-pcm-i2s1.txt        |  15 +
 .../bindings/sound/qca,ipq4019-pcm-i2s2.txt        |  15 +
 .../bindings/sound/qca,ipq4019-pcm-spdif.txt       |  15 +
 .../bindings/sound/qca,ipq4019-pcm-tdm.txt         |  15 +
 .../bindings/sound/qca,ipq4019-spdif.txt           |  35 +
 .../bindings/sound/qca,ipq4019-stereo.txt          |  17 +
 .../devicetree/bindings/sound/qca,ipq4019-tdm.txt  |  33 +
 arch/arm/boot/dts/qcom-ipq4019-ap.dk01.1.dtsi      | 195 ++++-
 arch/arm/boot/dts/qcom-ipq4019.dtsi                | 247 +++++-
 drivers/clk/qcom/Kconfig                           |   8 +
 drivers/clk/qcom/Makefile                          |   2 +
 drivers/clk/qcom/adcc-ipq4019.c                    | 700 +++++++++++++++++
 drivers/clk/qcom/clk-qcapll.c                      | 197 +++++
 drivers/clk/qcom/clk-qcapll.h                      |  60 ++
 drivers/clk/qcom/clk-rcg.h                         |  68 +-
 drivers/clk/qcom/clk-rcg2.c                        | 699 ++++++++++++++++-
 drivers/clk/qcom/common.c                          |   9 +-
 drivers/clk/qcom/common.h                          |   3 +-
 drivers/pinctrl/qcom/pinctrl-ipq4019.c             | 116 ++-
 include/dt-bindings/clock/qca,adcc-ipq4019.h       |  45 ++
 include/dt-bindings/clock/qcom,gcc-ipq4019.h       |   4 +-
 include/dt-bindings/sound/ipq4019-audio.h          |  37 +
 sound/soc/qcom/Kconfig                             |  47 ++
 sound/soc/qcom/Makefile                            |   1 +
 sound/soc/qcom/ipq4019/Makefile                    |  16 +
 sound/soc/qcom/ipq4019/ipq4019-adss.c              | 407 ++++++++++
 sound/soc/qcom/ipq4019/ipq4019-adss.h              | 432 +++++++++++
 sound/soc/qcom/ipq4019/ipq4019-codec.c             | 475 ++++++++++++
 sound/soc/qcom/ipq4019/ipq4019-codec.h             |  91 +++
 sound/soc/qcom/ipq4019/ipq4019-cpu-dai.c           | 687 +++++++++++++++++
 sound/soc/qcom/ipq4019/ipq4019-mbox.c              | 825 +++++++++++++++++++++
 sound/soc/qcom/ipq4019/ipq4019-mbox.h              | 146 ++++
 sound/soc/qcom/ipq4019/ipq4019-pcm-i2s.c           | 609 +++++++++++++++
 sound/soc/qcom/ipq4019/ipq4019-pcm-spdif.c         | 664 +++++++++++++++++
 sound/soc/qcom/ipq4019/ipq4019-pcm-tdm.c           | 609 +++++++++++++++
 sound/soc/qcom/ipq4019/ipq4019-pcm.h               |  37 +
 sound/soc/qcom/ipq4019/ipq4019-stereo.c            | 313 ++++++++
 sound/soc/qcom/ipq4019/ipq4019.c                   | 121 +++
 46 files changed, 8135 insertions(+), 57 deletions(-)
 create mode 100644 Documentation/devicetree/bindings/sound/qca,ipq4019-audio-adss.txt
 create mode 100644 Documentation/devicetree/bindings/sound/qca,ipq4019-audio.txt
 create mode 100644 Documentation/devicetree/bindings/sound/qca,ipq4019-codec.txt
 create mode 100644 Documentation/devicetree/bindings/sound/qca,ipq4019-i2s.txt
 create mode 100644 Documentation/devicetree/bindings/sound/qca,ipq4019-i2s1.txt
 create mode 100644 Documentation/devicetree/bindings/sound/qca,ipq4019-i2s2.txt
 create mode 100644 Documentation/devicetree/bindings/sound/qca,ipq4019-mbox.txt
 create mode 100644 Documentation/devicetree/bindings/sound/qca,ipq4019-pcm-i2s.txt
 create mode 100644 Documentation/devicetree/bindings/sound/qca,ipq4019-pcm-i2s1.txt
 create mode 100644 Documentation/devicetree/bindings/sound/qca,ipq4019-pcm-i2s2.txt
 create mode 100644 Documentation/devicetree/bindings/sound/qca,ipq4019-pcm-spdif.txt
 create mode 100644 Documentation/devicetree/bindings/sound/qca,ipq4019-pcm-tdm.txt
 create mode 100644 Documentation/devicetree/bindings/sound/qca,ipq4019-spdif.txt
 create mode 100644 Documentation/devicetree/bindings/sound/qca,ipq4019-stereo.txt
 create mode 100644 Documentation/devicetree/bindings/sound/qca,ipq4019-tdm.txt
 create mode 100644 drivers/clk/qcom/adcc-ipq4019.c
 create mode 100644 drivers/clk/qcom/clk-qcapll.c
 create mode 100644 drivers/clk/qcom/clk-qcapll.h
 create mode 100644 include/dt-bindings/clock/qca,adcc-ipq4019.h
 create mode 100644 include/dt-bindings/sound/ipq4019-audio.h
 create mode 100644 sound/soc/qcom/ipq4019/Makefile
 create mode 100644 sound/soc/qcom/ipq4019/ipq4019-adss.c
 create mode 100644 sound/soc/qcom/ipq4019/ipq4019-adss.h
 create mode 100644 sound/soc/qcom/ipq4019/ipq4019-codec.c
 create mode 100644 sound/soc/qcom/ipq4019/ipq4019-codec.h
 create mode 100644 sound/soc/qcom/ipq4019/ipq4019-cpu-dai.c
 create mode 100644 sound/soc/qcom/ipq4019/ipq4019-mbox.c
 create mode 100644 sound/soc/qcom/ipq4019/ipq4019-mbox.h
 create mode 100644 sound/soc/qcom/ipq4019/ipq4019-pcm-i2s.c
 create mode 100644 sound/soc/qcom/ipq4019/ipq4019-pcm-spdif.c
 create mode 100644 sound/soc/qcom/ipq4019/ipq4019-pcm-tdm.c
 create mode 100644 sound/soc/qcom/ipq4019/ipq4019-pcm.h
 create mode 100644 sound/soc/qcom/ipq4019/ipq4019-stereo.c
 create mode 100644 sound/soc/qcom/ipq4019/ipq4019.c

-- 
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
a Linux Foundation Collaborative Project

--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 24+ messages in thread

* [PATCH 0/4] Qualcomm IPQ4019 Audio driver addition
@ 2016-07-15  7:07 ` njaigane
  0 siblings, 0 replies; 24+ messages in thread
From: njaigane @ 2016-07-15  7:07 UTC (permalink / raw)
  To: linux-arm-msm
  Cc: linux, devicetree, linux-kernel, linux-soc, linux-arm-kernel,
	twp, andy.gross, david.brown, robh+dt, pawel.moll, mark.rutland,
	ijc+devicetree, galak, linux, mturquette, sboyd, linus.walleij,
	plai, bgoswami, lgirdwood, broonie, perex, tiwai,
	bjorn.andersson, varada, pradeepb, snlakshm, linux-clk,
	linux-gpio, alsa-devel, bselvara, Jaiganesh Narayanan

From: Jaiganesh Narayanan <njaigane@codeaurora.org>

These patches add the support for Qualcomm IPQ4019 ASoC
with the ALSA based audio drivers. The patches are broken

1. Device Tree support
2. Audio clock driver support
3. TLMM / Pinctrl support
4. ALSA based audio drivers

Jaiganesh Narayanan (4):
  qcom: ipq4019: Add ipq4019 ASoC device tree changes
  qcom: ipq4019: ASoC clock driver support
  qcom: ipq4019: ASoC tlmm/pinctrl support
  qcom: ipq4019: Add ASoC driver modules

 .../bindings/sound/qca,ipq4019-audio-adss.txt      |  20 +
 .../bindings/sound/qca,ipq4019-audio.txt           |  13 +
 .../bindings/sound/qca,ipq4019-codec.txt           |  15 +
 .../devicetree/bindings/sound/qca,ipq4019-i2s.txt  |  33 +
 .../devicetree/bindings/sound/qca,ipq4019-i2s1.txt |  29 +
 .../devicetree/bindings/sound/qca,ipq4019-i2s2.txt |  29 +
 .../devicetree/bindings/sound/qca,ipq4019-mbox.txt |  23 +
 .../bindings/sound/qca,ipq4019-pcm-i2s.txt         |  15 +
 .../bindings/sound/qca,ipq4019-pcm-i2s1.txt        |  15 +
 .../bindings/sound/qca,ipq4019-pcm-i2s2.txt        |  15 +
 .../bindings/sound/qca,ipq4019-pcm-spdif.txt       |  15 +
 .../bindings/sound/qca,ipq4019-pcm-tdm.txt         |  15 +
 .../bindings/sound/qca,ipq4019-spdif.txt           |  35 +
 .../bindings/sound/qca,ipq4019-stereo.txt          |  17 +
 .../devicetree/bindings/sound/qca,ipq4019-tdm.txt  |  33 +
 arch/arm/boot/dts/qcom-ipq4019-ap.dk01.1.dtsi      | 195 ++++-
 arch/arm/boot/dts/qcom-ipq4019.dtsi                | 247 +++++-
 drivers/clk/qcom/Kconfig                           |   8 +
 drivers/clk/qcom/Makefile                          |   2 +
 drivers/clk/qcom/adcc-ipq4019.c                    | 700 +++++++++++++++++
 drivers/clk/qcom/clk-qcapll.c                      | 197 +++++
 drivers/clk/qcom/clk-qcapll.h                      |  60 ++
 drivers/clk/qcom/clk-rcg.h                         |  68 +-
 drivers/clk/qcom/clk-rcg2.c                        | 699 ++++++++++++++++-
 drivers/clk/qcom/common.c                          |   9 +-
 drivers/clk/qcom/common.h                          |   3 +-
 drivers/pinctrl/qcom/pinctrl-ipq4019.c             | 116 ++-
 include/dt-bindings/clock/qca,adcc-ipq4019.h       |  45 ++
 include/dt-bindings/clock/qcom,gcc-ipq4019.h       |   4 +-
 include/dt-bindings/sound/ipq4019-audio.h          |  37 +
 sound/soc/qcom/Kconfig                             |  47 ++
 sound/soc/qcom/Makefile                            |   1 +
 sound/soc/qcom/ipq4019/Makefile                    |  16 +
 sound/soc/qcom/ipq4019/ipq4019-adss.c              | 407 ++++++++++
 sound/soc/qcom/ipq4019/ipq4019-adss.h              | 432 +++++++++++
 sound/soc/qcom/ipq4019/ipq4019-codec.c             | 475 ++++++++++++
 sound/soc/qcom/ipq4019/ipq4019-codec.h             |  91 +++
 sound/soc/qcom/ipq4019/ipq4019-cpu-dai.c           | 687 +++++++++++++++++
 sound/soc/qcom/ipq4019/ipq4019-mbox.c              | 825 +++++++++++++++++++++
 sound/soc/qcom/ipq4019/ipq4019-mbox.h              | 146 ++++
 sound/soc/qcom/ipq4019/ipq4019-pcm-i2s.c           | 609 +++++++++++++++
 sound/soc/qcom/ipq4019/ipq4019-pcm-spdif.c         | 664 +++++++++++++++++
 sound/soc/qcom/ipq4019/ipq4019-pcm-tdm.c           | 609 +++++++++++++++
 sound/soc/qcom/ipq4019/ipq4019-pcm.h               |  37 +
 sound/soc/qcom/ipq4019/ipq4019-stereo.c            | 313 ++++++++
 sound/soc/qcom/ipq4019/ipq4019.c                   | 121 +++
 46 files changed, 8135 insertions(+), 57 deletions(-)
 create mode 100644 Documentation/devicetree/bindings/sound/qca,ipq4019-audio-adss.txt
 create mode 100644 Documentation/devicetree/bindings/sound/qca,ipq4019-audio.txt
 create mode 100644 Documentation/devicetree/bindings/sound/qca,ipq4019-codec.txt
 create mode 100644 Documentation/devicetree/bindings/sound/qca,ipq4019-i2s.txt
 create mode 100644 Documentation/devicetree/bindings/sound/qca,ipq4019-i2s1.txt
 create mode 100644 Documentation/devicetree/bindings/sound/qca,ipq4019-i2s2.txt
 create mode 100644 Documentation/devicetree/bindings/sound/qca,ipq4019-mbox.txt
 create mode 100644 Documentation/devicetree/bindings/sound/qca,ipq4019-pcm-i2s.txt
 create mode 100644 Documentation/devicetree/bindings/sound/qca,ipq4019-pcm-i2s1.txt
 create mode 100644 Documentation/devicetree/bindings/sound/qca,ipq4019-pcm-i2s2.txt
 create mode 100644 Documentation/devicetree/bindings/sound/qca,ipq4019-pcm-spdif.txt
 create mode 100644 Documentation/devicetree/bindings/sound/qca,ipq4019-pcm-tdm.txt
 create mode 100644 Documentation/devicetree/bindings/sound/qca,ipq4019-spdif.txt
 create mode 100644 Documentation/devicetree/bindings/sound/qca,ipq4019-stereo.txt
 create mode 100644 Documentation/devicetree/bindings/sound/qca,ipq4019-tdm.txt
 create mode 100644 drivers/clk/qcom/adcc-ipq4019.c
 create mode 100644 drivers/clk/qcom/clk-qcapll.c
 create mode 100644 drivers/clk/qcom/clk-qcapll.h
 create mode 100644 include/dt-bindings/clock/qca,adcc-ipq4019.h
 create mode 100644 include/dt-bindings/sound/ipq4019-audio.h
 create mode 100644 sound/soc/qcom/ipq4019/Makefile
 create mode 100644 sound/soc/qcom/ipq4019/ipq4019-adss.c
 create mode 100644 sound/soc/qcom/ipq4019/ipq4019-adss.h
 create mode 100644 sound/soc/qcom/ipq4019/ipq4019-codec.c
 create mode 100644 sound/soc/qcom/ipq4019/ipq4019-codec.h
 create mode 100644 sound/soc/qcom/ipq4019/ipq4019-cpu-dai.c
 create mode 100644 sound/soc/qcom/ipq4019/ipq4019-mbox.c
 create mode 100644 sound/soc/qcom/ipq4019/ipq4019-mbox.h
 create mode 100644 sound/soc/qcom/ipq4019/ipq4019-pcm-i2s.c
 create mode 100644 sound/soc/qcom/ipq4019/ipq4019-pcm-spdif.c
 create mode 100644 sound/soc/qcom/ipq4019/ipq4019-pcm-tdm.c
 create mode 100644 sound/soc/qcom/ipq4019/ipq4019-pcm.h
 create mode 100644 sound/soc/qcom/ipq4019/ipq4019-stereo.c
 create mode 100644 sound/soc/qcom/ipq4019/ipq4019.c

-- 
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
a Linux Foundation Collaborative Project

^ permalink raw reply	[flat|nested] 24+ messages in thread

* [PATCH 0/4] Qualcomm IPQ4019 Audio driver addition
@ 2016-07-15  7:07 ` njaigane
  0 siblings, 0 replies; 24+ messages in thread
From: njaigane at codeaurora.org @ 2016-07-15  7:07 UTC (permalink / raw)
  To: linux-arm-kernel

From: Jaiganesh Narayanan <njaigane@codeaurora.org>

These patches add the support for Qualcomm IPQ4019 ASoC
with the ALSA based audio drivers. The patches are broken

1. Device Tree support
2. Audio clock driver support
3. TLMM / Pinctrl support
4. ALSA based audio drivers

Jaiganesh Narayanan (4):
  qcom: ipq4019: Add ipq4019 ASoC device tree changes
  qcom: ipq4019: ASoC clock driver support
  qcom: ipq4019: ASoC tlmm/pinctrl support
  qcom: ipq4019: Add ASoC driver modules

 .../bindings/sound/qca,ipq4019-audio-adss.txt      |  20 +
 .../bindings/sound/qca,ipq4019-audio.txt           |  13 +
 .../bindings/sound/qca,ipq4019-codec.txt           |  15 +
 .../devicetree/bindings/sound/qca,ipq4019-i2s.txt  |  33 +
 .../devicetree/bindings/sound/qca,ipq4019-i2s1.txt |  29 +
 .../devicetree/bindings/sound/qca,ipq4019-i2s2.txt |  29 +
 .../devicetree/bindings/sound/qca,ipq4019-mbox.txt |  23 +
 .../bindings/sound/qca,ipq4019-pcm-i2s.txt         |  15 +
 .../bindings/sound/qca,ipq4019-pcm-i2s1.txt        |  15 +
 .../bindings/sound/qca,ipq4019-pcm-i2s2.txt        |  15 +
 .../bindings/sound/qca,ipq4019-pcm-spdif.txt       |  15 +
 .../bindings/sound/qca,ipq4019-pcm-tdm.txt         |  15 +
 .../bindings/sound/qca,ipq4019-spdif.txt           |  35 +
 .../bindings/sound/qca,ipq4019-stereo.txt          |  17 +
 .../devicetree/bindings/sound/qca,ipq4019-tdm.txt  |  33 +
 arch/arm/boot/dts/qcom-ipq4019-ap.dk01.1.dtsi      | 195 ++++-
 arch/arm/boot/dts/qcom-ipq4019.dtsi                | 247 +++++-
 drivers/clk/qcom/Kconfig                           |   8 +
 drivers/clk/qcom/Makefile                          |   2 +
 drivers/clk/qcom/adcc-ipq4019.c                    | 700 +++++++++++++++++
 drivers/clk/qcom/clk-qcapll.c                      | 197 +++++
 drivers/clk/qcom/clk-qcapll.h                      |  60 ++
 drivers/clk/qcom/clk-rcg.h                         |  68 +-
 drivers/clk/qcom/clk-rcg2.c                        | 699 ++++++++++++++++-
 drivers/clk/qcom/common.c                          |   9 +-
 drivers/clk/qcom/common.h                          |   3 +-
 drivers/pinctrl/qcom/pinctrl-ipq4019.c             | 116 ++-
 include/dt-bindings/clock/qca,adcc-ipq4019.h       |  45 ++
 include/dt-bindings/clock/qcom,gcc-ipq4019.h       |   4 +-
 include/dt-bindings/sound/ipq4019-audio.h          |  37 +
 sound/soc/qcom/Kconfig                             |  47 ++
 sound/soc/qcom/Makefile                            |   1 +
 sound/soc/qcom/ipq4019/Makefile                    |  16 +
 sound/soc/qcom/ipq4019/ipq4019-adss.c              | 407 ++++++++++
 sound/soc/qcom/ipq4019/ipq4019-adss.h              | 432 +++++++++++
 sound/soc/qcom/ipq4019/ipq4019-codec.c             | 475 ++++++++++++
 sound/soc/qcom/ipq4019/ipq4019-codec.h             |  91 +++
 sound/soc/qcom/ipq4019/ipq4019-cpu-dai.c           | 687 +++++++++++++++++
 sound/soc/qcom/ipq4019/ipq4019-mbox.c              | 825 +++++++++++++++++++++
 sound/soc/qcom/ipq4019/ipq4019-mbox.h              | 146 ++++
 sound/soc/qcom/ipq4019/ipq4019-pcm-i2s.c           | 609 +++++++++++++++
 sound/soc/qcom/ipq4019/ipq4019-pcm-spdif.c         | 664 +++++++++++++++++
 sound/soc/qcom/ipq4019/ipq4019-pcm-tdm.c           | 609 +++++++++++++++
 sound/soc/qcom/ipq4019/ipq4019-pcm.h               |  37 +
 sound/soc/qcom/ipq4019/ipq4019-stereo.c            | 313 ++++++++
 sound/soc/qcom/ipq4019/ipq4019.c                   | 121 +++
 46 files changed, 8135 insertions(+), 57 deletions(-)
 create mode 100644 Documentation/devicetree/bindings/sound/qca,ipq4019-audio-adss.txt
 create mode 100644 Documentation/devicetree/bindings/sound/qca,ipq4019-audio.txt
 create mode 100644 Documentation/devicetree/bindings/sound/qca,ipq4019-codec.txt
 create mode 100644 Documentation/devicetree/bindings/sound/qca,ipq4019-i2s.txt
 create mode 100644 Documentation/devicetree/bindings/sound/qca,ipq4019-i2s1.txt
 create mode 100644 Documentation/devicetree/bindings/sound/qca,ipq4019-i2s2.txt
 create mode 100644 Documentation/devicetree/bindings/sound/qca,ipq4019-mbox.txt
 create mode 100644 Documentation/devicetree/bindings/sound/qca,ipq4019-pcm-i2s.txt
 create mode 100644 Documentation/devicetree/bindings/sound/qca,ipq4019-pcm-i2s1.txt
 create mode 100644 Documentation/devicetree/bindings/sound/qca,ipq4019-pcm-i2s2.txt
 create mode 100644 Documentation/devicetree/bindings/sound/qca,ipq4019-pcm-spdif.txt
 create mode 100644 Documentation/devicetree/bindings/sound/qca,ipq4019-pcm-tdm.txt
 create mode 100644 Documentation/devicetree/bindings/sound/qca,ipq4019-spdif.txt
 create mode 100644 Documentation/devicetree/bindings/sound/qca,ipq4019-stereo.txt
 create mode 100644 Documentation/devicetree/bindings/sound/qca,ipq4019-tdm.txt
 create mode 100644 drivers/clk/qcom/adcc-ipq4019.c
 create mode 100644 drivers/clk/qcom/clk-qcapll.c
 create mode 100644 drivers/clk/qcom/clk-qcapll.h
 create mode 100644 include/dt-bindings/clock/qca,adcc-ipq4019.h
 create mode 100644 include/dt-bindings/sound/ipq4019-audio.h
 create mode 100644 sound/soc/qcom/ipq4019/Makefile
 create mode 100644 sound/soc/qcom/ipq4019/ipq4019-adss.c
 create mode 100644 sound/soc/qcom/ipq4019/ipq4019-adss.h
 create mode 100644 sound/soc/qcom/ipq4019/ipq4019-codec.c
 create mode 100644 sound/soc/qcom/ipq4019/ipq4019-codec.h
 create mode 100644 sound/soc/qcom/ipq4019/ipq4019-cpu-dai.c
 create mode 100644 sound/soc/qcom/ipq4019/ipq4019-mbox.c
 create mode 100644 sound/soc/qcom/ipq4019/ipq4019-mbox.h
 create mode 100644 sound/soc/qcom/ipq4019/ipq4019-pcm-i2s.c
 create mode 100644 sound/soc/qcom/ipq4019/ipq4019-pcm-spdif.c
 create mode 100644 sound/soc/qcom/ipq4019/ipq4019-pcm-tdm.c
 create mode 100644 sound/soc/qcom/ipq4019/ipq4019-pcm.h
 create mode 100644 sound/soc/qcom/ipq4019/ipq4019-stereo.c
 create mode 100644 sound/soc/qcom/ipq4019/ipq4019.c

-- 
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
a Linux Foundation Collaborative Project

^ permalink raw reply	[flat|nested] 24+ messages in thread

* [PATCH 1/4] qcom: ipq4019: Add ipq4019 ASoC device tree changes
  2016-07-15  7:07 ` njaigane
@ 2016-07-15  7:07   ` njaigane at codeaurora.org
  -1 siblings, 0 replies; 24+ messages in thread
From: njaigane @ 2016-07-15  7:07 UTC (permalink / raw)
  To: linux-arm-msm
  Cc: linux, devicetree, linux-kernel, linux-soc, linux-arm-kernel,
	twp, andy.gross, david.brown, robh+dt, pawel.moll, mark.rutland,
	ijc+devicetree, galak, linux, mturquette, sboyd, linus.walleij,
	plai, bgoswami, lgirdwood, broonie, perex, tiwai,
	bjorn.andersson, varada, pradeepb, snlakshm, linux-clk,
	linux-gpio, alsa-devel, bselvara, Jaiganesh Narayanan

From: Jaiganesh Narayanan <njaigane@codeaurora.org>

This patch adds the ipq4019 ASoC device tree changes and the
binding documentation for pcm, spdif, tdm, stereo, codec, mbox,
adss modules

Signed-off-by: Jaiganesh Narayanan <njaigane@codeaurora.org>
---
 .../bindings/sound/qca,ipq4019-audio-adss.txt      |  20 ++
 .../bindings/sound/qca,ipq4019-audio.txt           |  13 ++
 .../bindings/sound/qca,ipq4019-codec.txt           |  15 ++
 .../devicetree/bindings/sound/qca,ipq4019-i2s.txt  |  33 +++
 .../devicetree/bindings/sound/qca,ipq4019-i2s1.txt |  29 +++
 .../devicetree/bindings/sound/qca,ipq4019-i2s2.txt |  29 +++
 .../devicetree/bindings/sound/qca,ipq4019-mbox.txt |  23 ++
 .../bindings/sound/qca,ipq4019-pcm-i2s.txt         |  15 ++
 .../bindings/sound/qca,ipq4019-pcm-i2s1.txt        |  15 ++
 .../bindings/sound/qca,ipq4019-pcm-i2s2.txt        |  15 ++
 .../bindings/sound/qca,ipq4019-pcm-spdif.txt       |  15 ++
 .../bindings/sound/qca,ipq4019-pcm-tdm.txt         |  15 ++
 .../bindings/sound/qca,ipq4019-spdif.txt           |  35 +++
 .../bindings/sound/qca,ipq4019-stereo.txt          |  17 ++
 .../devicetree/bindings/sound/qca,ipq4019-tdm.txt  |  33 +++
 arch/arm/boot/dts/qcom-ipq4019-ap.dk01.1.dtsi      | 195 ++++++++++++++--
 arch/arm/boot/dts/qcom-ipq4019.dtsi                | 247 ++++++++++++++++++++-
 17 files changed, 742 insertions(+), 22 deletions(-)
 create mode 100644 Documentation/devicetree/bindings/sound/qca,ipq4019-audio-adss.txt
 create mode 100644 Documentation/devicetree/bindings/sound/qca,ipq4019-audio.txt
 create mode 100644 Documentation/devicetree/bindings/sound/qca,ipq4019-codec.txt
 create mode 100644 Documentation/devicetree/bindings/sound/qca,ipq4019-i2s.txt
 create mode 100644 Documentation/devicetree/bindings/sound/qca,ipq4019-i2s1.txt
 create mode 100644 Documentation/devicetree/bindings/sound/qca,ipq4019-i2s2.txt
 create mode 100644 Documentation/devicetree/bindings/sound/qca,ipq4019-mbox.txt
 create mode 100644 Documentation/devicetree/bindings/sound/qca,ipq4019-pcm-i2s.txt
 create mode 100644 Documentation/devicetree/bindings/sound/qca,ipq4019-pcm-i2s1.txt
 create mode 100644 Documentation/devicetree/bindings/sound/qca,ipq4019-pcm-i2s2.txt
 create mode 100644 Documentation/devicetree/bindings/sound/qca,ipq4019-pcm-spdif.txt
 create mode 100644 Documentation/devicetree/bindings/sound/qca,ipq4019-pcm-tdm.txt
 create mode 100644 Documentation/devicetree/bindings/sound/qca,ipq4019-spdif.txt
 create mode 100644 Documentation/devicetree/bindings/sound/qca,ipq4019-stereo.txt
 create mode 100644 Documentation/devicetree/bindings/sound/qca,ipq4019-tdm.txt

diff --git a/Documentation/devicetree/bindings/sound/qca,ipq4019-audio-adss.txt b/Documentation/devicetree/bindings/sound/qca,ipq4019-audio-adss.txt
new file mode 100644
index 0000000..5ba2b9d
--- /dev/null
+++ b/Documentation/devicetree/bindings/sound/qca,ipq4019-audio-adss.txt
@@ -0,0 +1,20 @@
+* Qualcomm Technologies IPQ4019 ASoC audio subsystem driver
+
+This node models the Qualcomm Technologies IPQ4019 ASoC audio subsystem driver
+
+Required properties:
+
+- compatible	: "qca,ipq4019-audio-adss"
+- reg		: should have the stereo register address, length
+- resets	: references to the reset controllers
+- reset-names	: should be "blk_rst"
+
+
+Example:
+audio: audio@7700000 {
+	compatible = "qca,ipq4019-audio-adss";
+	reg = <0x7700000 0x34>;
+	resets = <&gcc AUDIO_BLK_ARES>;
+	reset-names = "blk_rst";
+	status = "disabled";
+};
diff --git a/Documentation/devicetree/bindings/sound/qca,ipq4019-audio.txt b/Documentation/devicetree/bindings/sound/qca,ipq4019-audio.txt
new file mode 100644
index 0000000..fde039f
--- /dev/null
+++ b/Documentation/devicetree/bindings/sound/qca,ipq4019-audio.txt
@@ -0,0 +1,13 @@
+* Qualcomm Technologies IPQ4019 ASoC machine driver
+
+This node models the Qualcomm Technologies IPQ4019 ASoC machine driver
+
+Required properties:
+
+- compatible		: "qca,ipq4019-audio"
+
+Example:
+
+sound: sound {
+	compatible = "qca,ipq4019-audio";
+};
diff --git a/Documentation/devicetree/bindings/sound/qca,ipq4019-codec.txt b/Documentation/devicetree/bindings/sound/qca,ipq4019-codec.txt
new file mode 100644
index 0000000..3df7742d
--- /dev/null
+++ b/Documentation/devicetree/bindings/sound/qca,ipq4019-codec.txt
@@ -0,0 +1,15 @@
+* Qualcomm Technologies IPQ4019 ASoC Codec driver
+
+This node models the Qualcomm Technologies IPQ4019 ASoC Codec driver
+
+Required properties:
+
+- compatible	: "qca,ipq4019-codec"
+- reg		: should have the stereo i2c register address
+
+Example:
+qca_codec: qca_codec@12 {
+	compatible = "qca,ipq4019-codec";
+	reg = <0x12>;
+	status = "disabled";
+};
diff --git a/Documentation/devicetree/bindings/sound/qca,ipq4019-i2s.txt b/Documentation/devicetree/bindings/sound/qca,ipq4019-i2s.txt
new file mode 100644
index 0000000..af9b63e
--- /dev/null
+++ b/Documentation/devicetree/bindings/sound/qca,ipq4019-i2s.txt
@@ -0,0 +1,33 @@
+* Qualcomm Technologies IPQ4019 ASoC PCM driver
+
+This node models the Qualcomm Technologies IPQ4019 ASoC I2S PCM driver
+
+Required properties:
+
+- compatible	 : "qca,ipq4019-i2s"
+- dma-tx-channel : should have the mbox tx channel id
+- dma-rx-channel : should have the mbox rx channel id
+- stereo-tx-port : should have the stereo tx id
+- stereo-rx-port : should have the stereo rx id
+- clocks	 : should have the audio tx bit clock, tx master clock,
+		   rx bit clock, rx master clock id
+- clock-names	 : should be "audio_tx_bclk", "audio_tx_mclk", "audio_rx_bclk",
+		   "audio_rx_mclk"
+
+Example:
+i2s: ipq4019-pcm-i2s@0 {
+	compatible = "qca,ipq4019-i2s";
+	dma-tx-channel = <MBOX0_TX_ID>;
+	dma-rx-channel = <MBOX3_RX_ID>;
+	stereo-tx-port = <STEREO0_ID>;
+	stereo-rx-port = <STEREO3_ID>;
+	clocks = <&adcc ADCC_TXB_CLK_SRC>,
+		<&adcc ADCC_TXM_CLK_SRC>,
+		<&adcc ADCC_RXB_CLK_SRC>,
+		<&adcc ADCC_RXM_CLK_SRC>;
+	clock-names = "audio_tx_bclk",
+		"audio_tx_mclk",
+		"audio_rx_bclk",
+		"audio_rx_mclk";
+	status = "disabled";
+};
diff --git a/Documentation/devicetree/bindings/sound/qca,ipq4019-i2s1.txt b/Documentation/devicetree/bindings/sound/qca,ipq4019-i2s1.txt
new file mode 100644
index 0000000..47333b3
--- /dev/null
+++ b/Documentation/devicetree/bindings/sound/qca,ipq4019-i2s1.txt
@@ -0,0 +1,29 @@
+* Qualcomm Technologies IPQ4019 ASoC I2S PCM driver
+
+This node models the Qualcomm Technologies IPQ4019 ASoC I2S PCM driver
+
+Required properties:
+
+- compatible	 : "qca,ipq4019-i2s1"
+- dma-tx-channel : should have the mbox tx channel id
+- stereo-tx-port : should have the stereo tx id
+- clocks	 : should have the audio tx bit clock, tx master clock,
+		   rx bit clock, rx master clock id
+- clock-names	 : should be "audio_tx_bclk", "audio_tx_mclk", "audio_rx_bclk",
+		   "audio_rx_mclk"
+
+Example:
+i2s1: ipq4019-pcm-i2s1@0 {
+	compatible = "qca,ipq4019-i2s1";
+	dma-tx-channel = <MBOX1_TX_ID>;
+	stereo-tx-port = <STEREO1_ID>;
+	clocks = <&adcc ADCC_TXB_CLK_SRC>,
+		<&adcc ADCC_TXM_CLK_SRC>,
+		<&adcc ADCC_RXB_CLK_SRC>,
+		<&adcc ADCC_RXM_CLK_SRC>;
+	clock-names = "audio_tx_bclk",
+		"audio_tx_mclk",
+		"audio_rx_bclk",
+		"audio_rx_mclk";
+	status = "disabled";
+};
diff --git a/Documentation/devicetree/bindings/sound/qca,ipq4019-i2s2.txt b/Documentation/devicetree/bindings/sound/qca,ipq4019-i2s2.txt
new file mode 100644
index 0000000..9af0113
--- /dev/null
+++ b/Documentation/devicetree/bindings/sound/qca,ipq4019-i2s2.txt
@@ -0,0 +1,29 @@
+* Qualcomm Technologies IPQ4019 ASoC I2S PCM driver
+
+This node models the Qualcomm Technologies IPQ4019 ASoC I2S PCM driver
+
+Required properties:
+
+- compatible	 : "qca,ipq4019-i2s2"
+- dma-tx-channel : should have the mbox tx channel id
+- stereo-tx-port : should have the stereo tx id
+- clocks	 : should have the audio tx bit clock, tx master clock,
+		   rx bit clock, rx master clock id
+- clock-names	 : should be "audio_tx_bclk", "audio_tx_mclk", "audio_rx_bclk",
+		   "audio_rx_mclk"
+
+Example:
+i2s1: ipq4019-pcm-i2s2@0 {
+	compatible = "qca,ipq4019-i2s2";
+	dma-tx-channel = <MBOX2_TX_ID>;
+	stereo-tx-port = <STEREO2_ID>;
+	clocks = <&adcc ADCC_TXB_CLK_SRC>,
+		<&adcc ADCC_TXM_CLK_SRC>,
+		<&adcc ADCC_RXB_CLK_SRC>,
+		<&adcc ADCC_RXM_CLK_SRC>;
+	clock-names = "audio_tx_bclk",
+		"audio_tx_mclk",
+		"audio_rx_bclk",
+		"audio_rx_mclk";
+	status = "disabled";
+};
diff --git a/Documentation/devicetree/bindings/sound/qca,ipq4019-mbox.txt b/Documentation/devicetree/bindings/sound/qca,ipq4019-mbox.txt
new file mode 100644
index 0000000..51d6c51
--- /dev/null
+++ b/Documentation/devicetree/bindings/sound/qca,ipq4019-mbox.txt
@@ -0,0 +1,23 @@
+* Qualcomm Technologies IPQ4019 ASoC MBOX driver
+
+This node models the Qualcomm Technologies IPQ4019 ASoC mbox driver
+
+Required properties:
+
+- compatible	 : "qca,ipq4019-mbox"
+- dma-index	 : should have the mbox dma index
+- reg		 : should have the stereo register address, length
+- interrupts	 : should have the mbox interrupt no
+- tx-channel	 : should have the mbox tx id
+- rx-channel	 : should have the mbox rx id
+
+Example:
+mbox0: mbox@7708000 {
+	compatible = "qca,ipq4019-mbox";
+	dma-index = <0>;
+	reg = <0x7708000 0x1000>;
+	interrupts = <0 156 0>;
+	tx-channel = <MBOX0_TX_ID>;
+	rx-channel = <MBOX0_RX_ID>;
+	status = "disabled";
+};
diff --git a/Documentation/devicetree/bindings/sound/qca,ipq4019-pcm-i2s.txt b/Documentation/devicetree/bindings/sound/qca,ipq4019-pcm-i2s.txt
new file mode 100644
index 0000000..a47c7fb
--- /dev/null
+++ b/Documentation/devicetree/bindings/sound/qca,ipq4019-pcm-i2s.txt
@@ -0,0 +1,15 @@
+* Qualcomm Technologies IPQ4019 ASoC platform driver
+
+This node models the Qualcomm Technologies IPQ4019 ASoC platform driver
+
+Required properties:
+
+- compatible	 : "qca,ipq4019-pcm-i2s"
+- reg		 : should have the stereo register address, length
+
+Example:
+i2splatform: qca-pcm-i2s@7709000 {
+	compatible = "qca,ipq4019-pcm-i2s";
+	reg = <0x7709000 0x1000>;
+	status = "disabled";
+};
diff --git a/Documentation/devicetree/bindings/sound/qca,ipq4019-pcm-i2s1.txt b/Documentation/devicetree/bindings/sound/qca,ipq4019-pcm-i2s1.txt
new file mode 100644
index 0000000..cf23ca0b
--- /dev/null
+++ b/Documentation/devicetree/bindings/sound/qca,ipq4019-pcm-i2s1.txt
@@ -0,0 +1,15 @@
+* Qualcomm Technologies IPQ4019 ASoC platform driver
+
+This node models the Qualcomm Technologies IPQ4019 ASoC platform driver
+
+Required properties:
+
+- compatible	 : "qca,ipq4019-pcm-i2s1"
+- reg		 : should have the stereo register address, length
+
+Example:
+i2s1platform: qca-pcm-i2s1@770b000 {
+	compatible = "qca,ipq4019-pcm-i2s1";
+	reg = <0x770b000 0x1000>;
+	status = "disabled";
+};
diff --git a/Documentation/devicetree/bindings/sound/qca,ipq4019-pcm-i2s2.txt b/Documentation/devicetree/bindings/sound/qca,ipq4019-pcm-i2s2.txt
new file mode 100644
index 0000000..ae04380
--- /dev/null
+++ b/Documentation/devicetree/bindings/sound/qca,ipq4019-pcm-i2s2.txt
@@ -0,0 +1,15 @@
+* Qualcomm Technologies IPQ4019 ASoC platform driver
+
+This node models the Qualcomm Technologies IPQ4019 ASoC platform driver
+
+Required properties:
+
+- compatible	 : "qca,ipq4019-pcm-i2s2"
+- reg		 : should have the stereo register address, length
+
+Example:
+i2s2platform: qca-pcm-i2s1@770d000 {
+	compatible = "qca,ipq4019-pcm-i2s2";
+	reg = <0x770d000 0x1000>;
+	status = "disabled";
+};
diff --git a/Documentation/devicetree/bindings/sound/qca,ipq4019-pcm-spdif.txt b/Documentation/devicetree/bindings/sound/qca,ipq4019-pcm-spdif.txt
new file mode 100644
index 0000000..b47c02c
--- /dev/null
+++ b/Documentation/devicetree/bindings/sound/qca,ipq4019-pcm-spdif.txt
@@ -0,0 +1,15 @@
+* Qualcomm Technologies IPQ4019 ASoC SPDIF platform driver
+
+This node models the Qualcomm Technologies IPQ4019 ASoC SPDIF platform driver
+
+Required properties:
+
+- compatible	 : "qca,ipq4019-pcm-spdif"
+- reg		 : should have the stereo register address, length
+
+Example:
+tdmplatform: qca-pcm-spdif@7707000 {
+	compatible = "qca,ipq4019-pcm-spdif";
+	reg = <0x7709000 0x1000>;
+	status = "disabled";
+};
diff --git a/Documentation/devicetree/bindings/sound/qca,ipq4019-pcm-tdm.txt b/Documentation/devicetree/bindings/sound/qca,ipq4019-pcm-tdm.txt
new file mode 100644
index 0000000..bd3aaa3
--- /dev/null
+++ b/Documentation/devicetree/bindings/sound/qca,ipq4019-pcm-tdm.txt
@@ -0,0 +1,15 @@
+* Qualcomm Technologies IPQ4019 ASoC TDM platform driver
+
+This node models the Qualcomm Technologies IPQ4019 ASoC TDM platform driver
+
+Required properties:
+
+- compatible	 : "qca,ipq4019-pcm-tdm"
+- reg		 : should have the stereo register address, length
+
+Example:
+tdmplatform: qca-pcm-tdm@7709000 {
+	compatible = "qca,ipq4019-pcm-tdm";
+	reg = <0x7709000 0x1000>;
+	status = "disabled";
+};
diff --git a/Documentation/devicetree/bindings/sound/qca,ipq4019-spdif.txt b/Documentation/devicetree/bindings/sound/qca,ipq4019-spdif.txt
new file mode 100644
index 0000000..5a80bbe
--- /dev/null
+++ b/Documentation/devicetree/bindings/sound/qca,ipq4019-spdif.txt
@@ -0,0 +1,35 @@
+* Qualcomm Technologies IPQ4019 ASoC SPDIF driver
+
+This node models the Qualcomm Technologies IPQ4019 ASoC SPDIF driver
+
+Required properties:
+
+- compatible	 : "qca,ipq4019-spdif"
+- dma-tx-channel : should have the mbox tx channel id
+- dma-rx-channel : should have the mbox rx channel id
+- stereo-tx-port : should have the stereo tx id
+- stereo-rx-port : should have the stereo tx id
+- clocks	 : should have the audio tx bit clock, tx master clock,
+		   spdif clock, spdif divider clock, spdif in fast clock
+- clock-names	 : should be "audio_tx_bclk", "audio_tx_mclk", "audio_spdif_src",
+		   "audio_spdif_div2", "audio_spdifinfast_src"
+
+Example:
+spdif: spdif@0 {
+	compatible = "qca,ipq4019-spdif";
+	dma-tx-channel = <MBOX0_TX_ID>;
+	dma-rx-channel = <MBOX3_RX_ID>;
+	stereo-tx-port = <STEREO0_ID>;
+	stereo-rx-port = <STEREO3_ID>;
+	clocks = <&adcc ADCC_TXB_CLK_SRC>,
+		<&adcc ADCC_TXM_CLK_SRC>,
+		<&adcc ADCC_SPDIF_SRC>,
+		<&adcc ADCC_SPDIFDIV2_SRC>,
+		<&adcc ADCC_AUDIO_SPDIFINFAST_SRC>;
+	clock-names = "audio_tx_bclk",
+		"audio_tx_mclk",
+		"audio_spdif_src",
+		"audio_spdif_div2",
+		"audio_spdifinfast_src";
+	status = "disabled";
+};
diff --git a/Documentation/devicetree/bindings/sound/qca,ipq4019-stereo.txt b/Documentation/devicetree/bindings/sound/qca,ipq4019-stereo.txt
new file mode 100644
index 0000000..35b4815
--- /dev/null
+++ b/Documentation/devicetree/bindings/sound/qca,ipq4019-stereo.txt
@@ -0,0 +1,17 @@
+* Qualcomm Technologies IPQ4019 ASoC stereo driver
+
+This node models the Qualcomm Technologies IPQ4019 ASoC stereo driver
+
+Required properties:
+
+- compatible	 : "qca,ipq4019-stereo"
+- reg		 : should have the stereo register address, length
+- stereo-index	 : should have the stereo port index
+
+Example:
+stereo0: stereo@7709000 {
+	compatible = "qca,ipq4019-stereo";
+	reg = <0x7709000 0x1000>;
+	stereo-index = <STEREO0_ID>;
+	status = "disabled";
+};
diff --git a/Documentation/devicetree/bindings/sound/qca,ipq4019-tdm.txt b/Documentation/devicetree/bindings/sound/qca,ipq4019-tdm.txt
new file mode 100644
index 0000000..c2bf38c
--- /dev/null
+++ b/Documentation/devicetree/bindings/sound/qca,ipq4019-tdm.txt
@@ -0,0 +1,33 @@
+* Qualcomm Technologies IPQ4019 ASoC TDM driver
+
+This node models the Qualcomm Technologies IPQ4019 ASoC TDM driver
+
+Required properties:
+
+- compatible	 : "qca,ipq4019-tdm"
+- dma-tx-channel : should have the mbox tx channel id
+- dma-rx-channel : should have the mbox rx channel id
+- stereo-tx-port : should have the stereo tx id
+- stereo-rx-port : should have the stereo tx id
+- clocks	 : should have the audio tx bit clock, tx master clock,
+		   rx bit clock, rx master clock id
+- clock-names	 : should be "audio_tx_bclk", "audio_tx_mclk", "audio_rx_bclk",
+		   "audio_rx_mclk"
+
+Example:
+tdm: tdm@0 {
+	compatible = "qca,ipq4019-tdm";
+	dma-tx-channel = <MBOX0_TX_ID>;
+	dma-rx-channel = <MBOX3_RX_ID>;
+	stereo-tx-port = <STEREO0_ID>;
+	stereo-rx-port = <STEREO3_ID>;
+	clocks = <&adcc ADCC_TXB_CLK_SRC>,
+		<&adcc ADCC_TXM_CLK_SRC>,
+		<&adcc ADCC_RXB_CLK_SRC>,
+		<&adcc ADCC_RXM_CLK_SRC>;
+	clock-names = "audio_tx_bclk",
+		"audio_tx_mclk",
+		"audio_rx_bclk",
+		"audio_rx_mclk";
+	status = "disabled";
+};
diff --git a/arch/arm/boot/dts/qcom-ipq4019-ap.dk01.1.dtsi b/arch/arm/boot/dts/qcom-ipq4019-ap.dk01.1.dtsi
index b9457dd2..e2ab95a 100644
--- a/arch/arm/boot/dts/qcom-ipq4019-ap.dk01.1.dtsi
+++ b/arch/arm/boot/dts/qcom-ipq4019-ap.dk01.1.dtsi
@@ -1,4 +1,4 @@
-/* Copyright (c) 2015, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2015-2016, The Linux Foundation. All rights reserved.
  *
  * Permission to use, copy, modify, and/or distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
@@ -20,26 +20,7 @@
 	model = "Qualcomm Technologies, Inc. IPQ4019/AP-DK01.1";
 	compatible = "qcom,ipq4019";
 
-	clocks {
-                xo: xo {
-                        compatible = "fixed-clock";
-                        clock-frequency = <48000000>;
-                        #clock-cells = <0>;
-                };
-	};
-
 	soc {
-
-
-		timer {
-			compatible = "arm,armv7-timer";
-			interrupts = <1 2 0xf08>,
-				     <1 3 0xf08>,
-				     <1 4 0xf08>,
-				     <1 1 0xf08>;
-			clock-frequency = <48000000>;
-		};
-
 		pinctrl@0x01000000 {
 			serial_pins: serial_pinmux {
 				mux {
@@ -69,6 +50,81 @@
 					bias-disable;
 					output-high;
 				};
+
+			};
+
+			audio_pins: audio_pinmux {
+				mux_1 {
+					pins = "gpio25", "gpio53", "gpio60";
+					function = "i2s_tx_bclk";
+					bias-pull,up;
+				};
+
+				mux_2 {
+					pins = "gpio27", "gpio54", "gpio63";
+					function = "i2s_txd1";
+					bias-pull,up;
+				};
+
+				mux_3 {
+					pins = "gpio28", "gpio55";
+					function = "i2s_txd2";
+					bias-pull,up;
+				};
+
+				mux_4 {
+					pins = "gpio29", "gpio56";
+					function = "i2s_txd3";
+					bias-pull,up;
+				};
+
+				mux_5 {
+					pins = "gpio24", "gpio52";
+					function = "i2s_tx_mclk";
+					bias-pull,up;
+				};
+
+				mux_6 {
+					pins = "gpio26", "gpio57", "gpio61";
+					function = "i2s_tx_fsync";
+					bias-pull,up;
+				};
+
+				mux_7 {
+					pins = "gpio2", "gpio23", "gpio63";
+					function = "i2s_rxd";
+					bias-pull,up;
+				};
+
+				mux_8 {
+					pins = "gpio20", "gpio58";
+					function = "i2s_rx_mclk";
+					bias-pull,up;
+				};
+
+				mux_9 {
+					pins = "gpio0", "gpio21", "gpio60";
+					function = "i2s_rx_bclk";
+					bias-pull,up;
+				};
+
+				mux_10 {
+					pins = "gpio1", "gpio22", "gpio61";
+					function = "i2s_rx_fsync";
+					bias-pull,up;
+				};
+
+				mux_11 {
+					pins = "gpio34", "gpio59", "gpio63";
+					function = "i2s_spdif_in";
+					bias-pull,up;
+				};
+
+				mux_12 {
+					pins = "gpio35", "gpio62", "gpio63";
+					function = "i2s_spdif_out";
+					bias-pull,up;
+				};
 			};
 		};
 
@@ -108,5 +164,104 @@
 		watchdog@b017000 {
 			status = "ok";
 		};
+
+		adcc: clock-controller@7700038 {
+			status = "ok";
+		};
+
+		audio: audio@7700000 {
+			status = "ok";
+		};
+
+		mbox0: mbox@7708000 {
+			status = "ok";
+		};
+
+		mbox1: mbox@770a000 {
+			status = "ok";
+		};
+
+		mbox2: mbox@770c000 {
+			status = "ok";
+		};
+
+		mbox3: mbox@770e000 {
+			status = "ok";
+		};
+
+		mbox4: mbox@7706000 {
+			status = "ok";
+		};
+
+		stereo0: stereo@7709000 {
+			status = "ok";
+		};
+
+		stereo1: stereo@770b000 {
+			status = "ok";
+		};
+
+		stereo2: stereo@770d000 {
+			status = "ok";
+		};
+
+		stereo3: stereo@770f000 {
+			status = "ok";
+		};
+
+		/* Enable Audio Interfaces */
+		i2s: ipq4019-pcm-i2s@0 {
+			status = "ok";
+		};
+
+		i2splatform: qca-pcm-i2s@7709000 {
+			status = "ok";
+		};
+
+		i2s1platform: qca-pcm-i2s1@770b000 {
+			status = "ok";
+		};
+
+		i2s1: ipq4019-pcm-i2s1@0 {
+			status = "ok";
+		};
+
+		i2s2platform: qca-pcm-i2s2@770d000 {
+			status = "ok";
+		};
+
+		i2s2: ipq4019-pcm-i2s2@0 {
+			status = "ok";
+		};
+
+		tdmplatform: qca-pcm-tdm@7709000 {
+			status = "ok";
+		};
+
+		tdm: tdm@0 {
+			status = "ok";
+		};
+
+		spdifplatform: qca-pcm-spdif@7707000 {
+			status = "ok";
+		};
+
+		spdif: spdif@0 {
+			status = "ok";
+		};
+
+		sound: sound@0 {
+			pinctrl-0 = <&audio_pins>;
+			pinctrl-names = "default";
+			status = "ok";
+		};
+
+		i2c_0: i2c@78b7000 { /* BLSP1 QUP2 */
+			status = "ok";
+
+			qca_codec: qca_codec@12 {
+				status = "ok";
+			};
+		};
 	};
 };
diff --git a/arch/arm/boot/dts/qcom-ipq4019.dtsi b/arch/arm/boot/dts/qcom-ipq4019.dtsi
index 5c08d19..e2b4810 100644
--- a/arch/arm/boot/dts/qcom-ipq4019.dtsi
+++ b/arch/arm/boot/dts/qcom-ipq4019.dtsi
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2015-2016, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -15,6 +15,8 @@
 
 #include "skeleton.dtsi"
 #include <dt-bindings/clock/qcom,gcc-ipq4019.h>
+#include <dt-bindings/clock/qca,adcc-ipq4019.h>
+#include <dt-bindings/sound/ipq4019-audio.h>
 #include <dt-bindings/interrupt-controller/arm-gic.h>
 #include <dt-bindings/interrupt-controller/irq.h>
 
@@ -90,6 +92,21 @@
 			clock-frequency = <32768>;
 			#clock-cells = <0>;
 		};
+
+		xo: xo {
+			compatible = "fixed-clock";
+			clock-frequency = <48000000>;
+			#clock-cells = <0>;
+		};
+	};
+
+	timer {
+		compatible = "arm,armv7-timer";
+		interrupts = <1 2 0xf08>,
+			     <1 3 0xf08>,
+			     <1 4 0xf08>,
+			     <1 1 0xf08>;
+		clock-frequency = <48000000>;
 	};
 
 	soc {
@@ -156,8 +173,13 @@
 			#address-cells = <1>;
 			#size-cells = <0>;
 			status = "disabled";
-		};
 
+			qca_codec: qca_codec@12 {
+				compatible = "qca,ipq4019-codec";
+				reg = <0x12>;
+				status = "disabled";
+			};
+		};
 
 		cryptobam: dma@8e04000 {
 			compatible = "qcom,bam-v1.7.0";
@@ -263,5 +285,226 @@
 			compatible = "qcom,pshold";
 			reg = <0x4ab000 0x4>;
 		};
+
+		adcc: clock-controller@7700038 {
+			compatible = "qcom,adcc-ipq4019";
+			#clock-cells = <1>;
+			#reset-cells = <1>;
+			reg = <0x7700038 0x1DC>;
+			status = "disabled";
+		};
+
+		audio: audio@7700000 {
+			compatible = "qca,ipq4019-audio-adss";
+			reg = <0x7700000 0x34>,
+				<0x7707000 0x20>;
+			resets = <&gcc AUDIO_BLK_ARES>;
+			reset-names = "blk_rst";
+			status = "disabled";
+		};
+
+		pcm: pcm@7704000 {
+			compatible = "qca,ipq4019-pcm";
+			reg = <0x7704000 0x2000>;
+			dma-tx-channel = <MBOX3_TX_ID>;
+			dma-rx-channel = <MBOX0_RX_ID>;
+			stereo-tx-port = <STEREO3_ID>;
+			stereo-rx-port = <STEREO0_ID>;
+			clocks = <&adcc ADCC_PCM_CLK_SRC>;
+			clock-names = "audio_pcm_clk";
+			status = "disabled";
+		};
+
+		mbox0: mbox@7708000 {
+			dma-index = <0>;
+			compatible = "qca,ipq4019-mbox";
+			reg = <0x7708000 0x1000>;
+			interrupts = <0 156 0>;
+			tx-channel = <MBOX0_TX_ID>;
+			rx-channel = <MBOX0_RX_ID>;
+			status = "disabled";
+		};
+
+		mbox1: mbox@770a000 {
+			dma-index = <1>;
+			compatible = "qca,ipq4019-mbox";
+			reg = <0x770A000 0x1000>;
+			interrupts = <0 157 0>;
+			tx-channel = <MBOX1_TX_ID>;
+			status = "disabled";
+		};
+
+		mbox2: mbox@770c000 {
+			dma-index = <2>;
+			compatible = "qca,ipq4019-mbox";
+			reg = <0x770C000 0x1000>;
+			interrupts = <0 158 0>;
+			tx-channel = <MBOX2_TX_ID>;
+			status = "disabled";
+		};
+
+		mbox3: mbox@770e000 {
+			dma-index = <3>;
+			compatible = "qca,ipq4019-mbox";
+			reg = <0x770E000 0x1000>;
+			interrupts = <0 159 0>;
+			tx-channel = <MBOX3_TX_ID>;
+			rx-channel = <MBOX3_RX_ID>;
+			status = "disabled";
+		};
+
+		mbox4: mbox@7706000 {
+			dma-index = <4>;
+			compatible = "qca,ipq4019-mbox";
+			reg = <0x7706000 0x1000>;
+			interrupts = <0 163 0>;
+			rx-channel = <MBOX_SPDIF_RX_ID>;
+			status = "disabled";
+		};
+
+		stereo0: stereo@7709000 {
+			stereo-index = <STEREO0_ID>;
+			compatible = "qca,ipq4019-stereo";
+			reg = <0x7709000 0x1000>;
+			status = "disabled";
+		};
+
+		stereo1: stereo@770b000 {
+			stereo-index = <STEREO1_ID>;
+			compatible = "qca,ipq4019-stereo";
+			reg = <0x770B000 0x1000>;
+			status = "disabled";
+		};
+
+		stereo2: stereo@770d000 {
+			stereo-index = <STEREO2_ID>;
+			compatible = "qca,ipq4019-stereo";
+			reg = <0x770D000 0x1000>;
+			status = "disabled";
+		};
+
+		stereo3: stereo@770f000 {
+			stereo-index = <STEREO3_ID>;
+			compatible = "qca,ipq4019-stereo";
+			reg = <0x770F000 0x1000>;
+			status = "disabled";
+		};
+
+		i2splatform: qca-pcm-i2s@7709000 {
+			compatible = "qca,ipq4019-pcm-i2s";
+			reg = <0x7709000 0x1000>;
+			status = "disabled";
+		};
+
+		i2s: ipq4019-pcm-i2s@0 {
+			compatible = "qca,ipq4019-i2s";
+			dma-tx-channel = <MBOX0_TX_ID>;
+			stereo-tx-port = <STEREO0_ID>;
+			dma-rx-channel = <MBOX3_RX_ID>;
+			stereo-rx-port = <STEREO3_ID>;
+			clocks = <&adcc ADCC_TXB_CLK_SRC>,
+				<&adcc ADCC_TXM_CLK_SRC>,
+				<&adcc ADCC_RXB_CLK_SRC>,
+				<&adcc ADCC_RXM_CLK_SRC>;
+			clock-names = "audio_tx_bclk",
+				"audio_tx_mclk",
+				"audio_rx_bclk",
+				"audio_rx_mclk";
+			status = "disabled";
+		};
+
+		i2s1platform: qca-pcm-i2s1@770b000 {
+			compatible = "qca,ipq4019-pcm-i2s1";
+			reg = <0x770b000 0x1000>;
+			status = "disabled";
+		};
+
+		i2s1: ipq4019-pcm-i2s1@0 {
+			compatible = "qca,ipq4019-i2s1";
+			dma-tx-channel = <MBOX1_TX_ID>;
+			stereo-tx-port = <STEREO1_ID>;
+			clocks = <&adcc ADCC_TXB_CLK_SRC>,
+				<&adcc ADCC_TXM_CLK_SRC>,
+				<&adcc ADCC_RXB_CLK_SRC>,
+				<&adcc ADCC_RXM_CLK_SRC>;
+			clock-names = "audio_tx_bclk",
+				"audio_tx_mclk",
+				"audio_rx_bclk",
+				"audio_rx_mclk";
+			status = "disabled";
+		};
+
+		i2s2platform: qca-pcm-i2s2@770d000 {
+			compatible = "qca,ipq4019-pcm-i2s2";
+			reg = <0x770d000 0x1000>;
+			status = "disabled";
+		};
+
+		i2s2: ipq4019-pcm-i2s2@0 {
+			compatible = "qca,ipq4019-i2s2";
+			dma-tx-channel = <MBOX2_TX_ID>;
+			stereo-tx-port = <STEREO2_ID>;
+			clocks = <&adcc ADCC_TXB_CLK_SRC>,
+				<&adcc ADCC_TXM_CLK_SRC>,
+				<&adcc ADCC_RXB_CLK_SRC>,
+				<&adcc ADCC_RXM_CLK_SRC>;
+			clock-names = "audio_tx_bclk",
+				"audio_tx_mclk",
+				"audio_rx_bclk",
+				"audio_rx_mclk";
+			status = "disabled";
+		};
+
+		tdmplatform: qca-pcm-tdm@7709000 {
+			compatible = "qca,ipq4019-pcm-tdm";
+			reg = <0x7709000 0x1000>;
+			status = "disabled";
+		};
+
+		tdm: tdm@0 {
+			compatible = "qca,ipq4019-tdm";
+			dma-tx-channel = <MBOX0_TX_ID>;
+			dma-rx-channel = <MBOX3_RX_ID>;
+			stereo-tx-port = <STEREO0_ID>;
+			stereo-rx-port = <STEREO3_ID>;
+			clocks = <&adcc ADCC_TXB_CLK_SRC>,
+				<&adcc ADCC_TXM_CLK_SRC>,
+				<&adcc ADCC_RXB_CLK_SRC>,
+				<&adcc ADCC_RXM_CLK_SRC>;
+			clock-names = "audio_tx_bclk",
+				"audio_tx_mclk",
+				"audio_rx_bclk",
+				"audio_rx_mclk";
+			status = "disabled";
+		};
+
+		spdifplatform: qca-pcm-spdif@7707000 {
+			compatible = "qca,ipq4019-pcm-spdif";
+			reg = <0x7707000 0x1000>;
+			status = "disabled";
+		};
+
+		spdif: spdif@0 {
+			compatible = "qca,ipq4019-spdif";
+			dma-tx-channel = <MBOX0_TX_ID>;
+			dma-rx-channel = <MBOX_SPDIF_RX_ID>;
+			stereo-tx-port = <STEREO0_ID>;
+			clocks = <&adcc ADCC_TXB_CLK_SRC>,
+				<&adcc ADCC_TXM_CLK_SRC>,
+				<&adcc ADCC_SPDIF_SRC>,
+				<&adcc ADCC_SPDIFDIV2_SRC >,
+				<&adcc ADCC_AUDIO_SPDIFINFAST_SRC>;
+			clock-names = "audio_tx_bclk",
+				"audio_tx_mclk",
+				"audio_spdif_src",
+				"audio_spdif_div2",
+				"audio_spdifinfast_src";
+			status = "disabled";
+		};
+
+		sound: sound@0 {
+			compatible = "qca,ipq4019-audio";
+			status = "disabled";
+		};
 	};
 };
-- 
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
a Linux Foundation Collaborative Project

^ permalink raw reply related	[flat|nested] 24+ messages in thread

* [PATCH 1/4] qcom: ipq4019: Add ipq4019 ASoC device tree changes
@ 2016-07-15  7:07   ` njaigane at codeaurora.org
  0 siblings, 0 replies; 24+ messages in thread
From: njaigane at codeaurora.org @ 2016-07-15  7:07 UTC (permalink / raw)
  To: linux-arm-kernel

From: Jaiganesh Narayanan <njaigane@codeaurora.org>

This patch adds the ipq4019 ASoC device tree changes and the
binding documentation for pcm, spdif, tdm, stereo, codec, mbox,
adss modules

Signed-off-by: Jaiganesh Narayanan <njaigane@codeaurora.org>
---
 .../bindings/sound/qca,ipq4019-audio-adss.txt      |  20 ++
 .../bindings/sound/qca,ipq4019-audio.txt           |  13 ++
 .../bindings/sound/qca,ipq4019-codec.txt           |  15 ++
 .../devicetree/bindings/sound/qca,ipq4019-i2s.txt  |  33 +++
 .../devicetree/bindings/sound/qca,ipq4019-i2s1.txt |  29 +++
 .../devicetree/bindings/sound/qca,ipq4019-i2s2.txt |  29 +++
 .../devicetree/bindings/sound/qca,ipq4019-mbox.txt |  23 ++
 .../bindings/sound/qca,ipq4019-pcm-i2s.txt         |  15 ++
 .../bindings/sound/qca,ipq4019-pcm-i2s1.txt        |  15 ++
 .../bindings/sound/qca,ipq4019-pcm-i2s2.txt        |  15 ++
 .../bindings/sound/qca,ipq4019-pcm-spdif.txt       |  15 ++
 .../bindings/sound/qca,ipq4019-pcm-tdm.txt         |  15 ++
 .../bindings/sound/qca,ipq4019-spdif.txt           |  35 +++
 .../bindings/sound/qca,ipq4019-stereo.txt          |  17 ++
 .../devicetree/bindings/sound/qca,ipq4019-tdm.txt  |  33 +++
 arch/arm/boot/dts/qcom-ipq4019-ap.dk01.1.dtsi      | 195 ++++++++++++++--
 arch/arm/boot/dts/qcom-ipq4019.dtsi                | 247 ++++++++++++++++++++-
 17 files changed, 742 insertions(+), 22 deletions(-)
 create mode 100644 Documentation/devicetree/bindings/sound/qca,ipq4019-audio-adss.txt
 create mode 100644 Documentation/devicetree/bindings/sound/qca,ipq4019-audio.txt
 create mode 100644 Documentation/devicetree/bindings/sound/qca,ipq4019-codec.txt
 create mode 100644 Documentation/devicetree/bindings/sound/qca,ipq4019-i2s.txt
 create mode 100644 Documentation/devicetree/bindings/sound/qca,ipq4019-i2s1.txt
 create mode 100644 Documentation/devicetree/bindings/sound/qca,ipq4019-i2s2.txt
 create mode 100644 Documentation/devicetree/bindings/sound/qca,ipq4019-mbox.txt
 create mode 100644 Documentation/devicetree/bindings/sound/qca,ipq4019-pcm-i2s.txt
 create mode 100644 Documentation/devicetree/bindings/sound/qca,ipq4019-pcm-i2s1.txt
 create mode 100644 Documentation/devicetree/bindings/sound/qca,ipq4019-pcm-i2s2.txt
 create mode 100644 Documentation/devicetree/bindings/sound/qca,ipq4019-pcm-spdif.txt
 create mode 100644 Documentation/devicetree/bindings/sound/qca,ipq4019-pcm-tdm.txt
 create mode 100644 Documentation/devicetree/bindings/sound/qca,ipq4019-spdif.txt
 create mode 100644 Documentation/devicetree/bindings/sound/qca,ipq4019-stereo.txt
 create mode 100644 Documentation/devicetree/bindings/sound/qca,ipq4019-tdm.txt

diff --git a/Documentation/devicetree/bindings/sound/qca,ipq4019-audio-adss.txt b/Documentation/devicetree/bindings/sound/qca,ipq4019-audio-adss.txt
new file mode 100644
index 0000000..5ba2b9d
--- /dev/null
+++ b/Documentation/devicetree/bindings/sound/qca,ipq4019-audio-adss.txt
@@ -0,0 +1,20 @@
+* Qualcomm Technologies IPQ4019 ASoC audio subsystem driver
+
+This node models the Qualcomm Technologies IPQ4019 ASoC audio subsystem driver
+
+Required properties:
+
+- compatible	: "qca,ipq4019-audio-adss"
+- reg		: should have the stereo register address, length
+- resets	: references to the reset controllers
+- reset-names	: should be "blk_rst"
+
+
+Example:
+audio: audio at 7700000 {
+	compatible = "qca,ipq4019-audio-adss";
+	reg = <0x7700000 0x34>;
+	resets = <&gcc AUDIO_BLK_ARES>;
+	reset-names = "blk_rst";
+	status = "disabled";
+};
diff --git a/Documentation/devicetree/bindings/sound/qca,ipq4019-audio.txt b/Documentation/devicetree/bindings/sound/qca,ipq4019-audio.txt
new file mode 100644
index 0000000..fde039f
--- /dev/null
+++ b/Documentation/devicetree/bindings/sound/qca,ipq4019-audio.txt
@@ -0,0 +1,13 @@
+* Qualcomm Technologies IPQ4019 ASoC machine driver
+
+This node models the Qualcomm Technologies IPQ4019 ASoC machine driver
+
+Required properties:
+
+- compatible		: "qca,ipq4019-audio"
+
+Example:
+
+sound: sound {
+	compatible = "qca,ipq4019-audio";
+};
diff --git a/Documentation/devicetree/bindings/sound/qca,ipq4019-codec.txt b/Documentation/devicetree/bindings/sound/qca,ipq4019-codec.txt
new file mode 100644
index 0000000..3df7742d
--- /dev/null
+++ b/Documentation/devicetree/bindings/sound/qca,ipq4019-codec.txt
@@ -0,0 +1,15 @@
+* Qualcomm Technologies IPQ4019 ASoC Codec driver
+
+This node models the Qualcomm Technologies IPQ4019 ASoC Codec driver
+
+Required properties:
+
+- compatible	: "qca,ipq4019-codec"
+- reg		: should have the stereo i2c register address
+
+Example:
+qca_codec: qca_codec at 12 {
+	compatible = "qca,ipq4019-codec";
+	reg = <0x12>;
+	status = "disabled";
+};
diff --git a/Documentation/devicetree/bindings/sound/qca,ipq4019-i2s.txt b/Documentation/devicetree/bindings/sound/qca,ipq4019-i2s.txt
new file mode 100644
index 0000000..af9b63e
--- /dev/null
+++ b/Documentation/devicetree/bindings/sound/qca,ipq4019-i2s.txt
@@ -0,0 +1,33 @@
+* Qualcomm Technologies IPQ4019 ASoC PCM driver
+
+This node models the Qualcomm Technologies IPQ4019 ASoC I2S PCM driver
+
+Required properties:
+
+- compatible	 : "qca,ipq4019-i2s"
+- dma-tx-channel : should have the mbox tx channel id
+- dma-rx-channel : should have the mbox rx channel id
+- stereo-tx-port : should have the stereo tx id
+- stereo-rx-port : should have the stereo rx id
+- clocks	 : should have the audio tx bit clock, tx master clock,
+		   rx bit clock, rx master clock id
+- clock-names	 : should be "audio_tx_bclk", "audio_tx_mclk", "audio_rx_bclk",
+		   "audio_rx_mclk"
+
+Example:
+i2s: ipq4019-pcm-i2s at 0 {
+	compatible = "qca,ipq4019-i2s";
+	dma-tx-channel = <MBOX0_TX_ID>;
+	dma-rx-channel = <MBOX3_RX_ID>;
+	stereo-tx-port = <STEREO0_ID>;
+	stereo-rx-port = <STEREO3_ID>;
+	clocks = <&adcc ADCC_TXB_CLK_SRC>,
+		<&adcc ADCC_TXM_CLK_SRC>,
+		<&adcc ADCC_RXB_CLK_SRC>,
+		<&adcc ADCC_RXM_CLK_SRC>;
+	clock-names = "audio_tx_bclk",
+		"audio_tx_mclk",
+		"audio_rx_bclk",
+		"audio_rx_mclk";
+	status = "disabled";
+};
diff --git a/Documentation/devicetree/bindings/sound/qca,ipq4019-i2s1.txt b/Documentation/devicetree/bindings/sound/qca,ipq4019-i2s1.txt
new file mode 100644
index 0000000..47333b3
--- /dev/null
+++ b/Documentation/devicetree/bindings/sound/qca,ipq4019-i2s1.txt
@@ -0,0 +1,29 @@
+* Qualcomm Technologies IPQ4019 ASoC I2S PCM driver
+
+This node models the Qualcomm Technologies IPQ4019 ASoC I2S PCM driver
+
+Required properties:
+
+- compatible	 : "qca,ipq4019-i2s1"
+- dma-tx-channel : should have the mbox tx channel id
+- stereo-tx-port : should have the stereo tx id
+- clocks	 : should have the audio tx bit clock, tx master clock,
+		   rx bit clock, rx master clock id
+- clock-names	 : should be "audio_tx_bclk", "audio_tx_mclk", "audio_rx_bclk",
+		   "audio_rx_mclk"
+
+Example:
+i2s1: ipq4019-pcm-i2s1 at 0 {
+	compatible = "qca,ipq4019-i2s1";
+	dma-tx-channel = <MBOX1_TX_ID>;
+	stereo-tx-port = <STEREO1_ID>;
+	clocks = <&adcc ADCC_TXB_CLK_SRC>,
+		<&adcc ADCC_TXM_CLK_SRC>,
+		<&adcc ADCC_RXB_CLK_SRC>,
+		<&adcc ADCC_RXM_CLK_SRC>;
+	clock-names = "audio_tx_bclk",
+		"audio_tx_mclk",
+		"audio_rx_bclk",
+		"audio_rx_mclk";
+	status = "disabled";
+};
diff --git a/Documentation/devicetree/bindings/sound/qca,ipq4019-i2s2.txt b/Documentation/devicetree/bindings/sound/qca,ipq4019-i2s2.txt
new file mode 100644
index 0000000..9af0113
--- /dev/null
+++ b/Documentation/devicetree/bindings/sound/qca,ipq4019-i2s2.txt
@@ -0,0 +1,29 @@
+* Qualcomm Technologies IPQ4019 ASoC I2S PCM driver
+
+This node models the Qualcomm Technologies IPQ4019 ASoC I2S PCM driver
+
+Required properties:
+
+- compatible	 : "qca,ipq4019-i2s2"
+- dma-tx-channel : should have the mbox tx channel id
+- stereo-tx-port : should have the stereo tx id
+- clocks	 : should have the audio tx bit clock, tx master clock,
+		   rx bit clock, rx master clock id
+- clock-names	 : should be "audio_tx_bclk", "audio_tx_mclk", "audio_rx_bclk",
+		   "audio_rx_mclk"
+
+Example:
+i2s1: ipq4019-pcm-i2s2 at 0 {
+	compatible = "qca,ipq4019-i2s2";
+	dma-tx-channel = <MBOX2_TX_ID>;
+	stereo-tx-port = <STEREO2_ID>;
+	clocks = <&adcc ADCC_TXB_CLK_SRC>,
+		<&adcc ADCC_TXM_CLK_SRC>,
+		<&adcc ADCC_RXB_CLK_SRC>,
+		<&adcc ADCC_RXM_CLK_SRC>;
+	clock-names = "audio_tx_bclk",
+		"audio_tx_mclk",
+		"audio_rx_bclk",
+		"audio_rx_mclk";
+	status = "disabled";
+};
diff --git a/Documentation/devicetree/bindings/sound/qca,ipq4019-mbox.txt b/Documentation/devicetree/bindings/sound/qca,ipq4019-mbox.txt
new file mode 100644
index 0000000..51d6c51
--- /dev/null
+++ b/Documentation/devicetree/bindings/sound/qca,ipq4019-mbox.txt
@@ -0,0 +1,23 @@
+* Qualcomm Technologies IPQ4019 ASoC MBOX driver
+
+This node models the Qualcomm Technologies IPQ4019 ASoC mbox driver
+
+Required properties:
+
+- compatible	 : "qca,ipq4019-mbox"
+- dma-index	 : should have the mbox dma index
+- reg		 : should have the stereo register address, length
+- interrupts	 : should have the mbox interrupt no
+- tx-channel	 : should have the mbox tx id
+- rx-channel	 : should have the mbox rx id
+
+Example:
+mbox0: mbox at 7708000 {
+	compatible = "qca,ipq4019-mbox";
+	dma-index = <0>;
+	reg = <0x7708000 0x1000>;
+	interrupts = <0 156 0>;
+	tx-channel = <MBOX0_TX_ID>;
+	rx-channel = <MBOX0_RX_ID>;
+	status = "disabled";
+};
diff --git a/Documentation/devicetree/bindings/sound/qca,ipq4019-pcm-i2s.txt b/Documentation/devicetree/bindings/sound/qca,ipq4019-pcm-i2s.txt
new file mode 100644
index 0000000..a47c7fb
--- /dev/null
+++ b/Documentation/devicetree/bindings/sound/qca,ipq4019-pcm-i2s.txt
@@ -0,0 +1,15 @@
+* Qualcomm Technologies IPQ4019 ASoC platform driver
+
+This node models the Qualcomm Technologies IPQ4019 ASoC platform driver
+
+Required properties:
+
+- compatible	 : "qca,ipq4019-pcm-i2s"
+- reg		 : should have the stereo register address, length
+
+Example:
+i2splatform: qca-pcm-i2s at 7709000 {
+	compatible = "qca,ipq4019-pcm-i2s";
+	reg = <0x7709000 0x1000>;
+	status = "disabled";
+};
diff --git a/Documentation/devicetree/bindings/sound/qca,ipq4019-pcm-i2s1.txt b/Documentation/devicetree/bindings/sound/qca,ipq4019-pcm-i2s1.txt
new file mode 100644
index 0000000..cf23ca0b
--- /dev/null
+++ b/Documentation/devicetree/bindings/sound/qca,ipq4019-pcm-i2s1.txt
@@ -0,0 +1,15 @@
+* Qualcomm Technologies IPQ4019 ASoC platform driver
+
+This node models the Qualcomm Technologies IPQ4019 ASoC platform driver
+
+Required properties:
+
+- compatible	 : "qca,ipq4019-pcm-i2s1"
+- reg		 : should have the stereo register address, length
+
+Example:
+i2s1platform: qca-pcm-i2s1 at 770b000 {
+	compatible = "qca,ipq4019-pcm-i2s1";
+	reg = <0x770b000 0x1000>;
+	status = "disabled";
+};
diff --git a/Documentation/devicetree/bindings/sound/qca,ipq4019-pcm-i2s2.txt b/Documentation/devicetree/bindings/sound/qca,ipq4019-pcm-i2s2.txt
new file mode 100644
index 0000000..ae04380
--- /dev/null
+++ b/Documentation/devicetree/bindings/sound/qca,ipq4019-pcm-i2s2.txt
@@ -0,0 +1,15 @@
+* Qualcomm Technologies IPQ4019 ASoC platform driver
+
+This node models the Qualcomm Technologies IPQ4019 ASoC platform driver
+
+Required properties:
+
+- compatible	 : "qca,ipq4019-pcm-i2s2"
+- reg		 : should have the stereo register address, length
+
+Example:
+i2s2platform: qca-pcm-i2s1 at 770d000 {
+	compatible = "qca,ipq4019-pcm-i2s2";
+	reg = <0x770d000 0x1000>;
+	status = "disabled";
+};
diff --git a/Documentation/devicetree/bindings/sound/qca,ipq4019-pcm-spdif.txt b/Documentation/devicetree/bindings/sound/qca,ipq4019-pcm-spdif.txt
new file mode 100644
index 0000000..b47c02c
--- /dev/null
+++ b/Documentation/devicetree/bindings/sound/qca,ipq4019-pcm-spdif.txt
@@ -0,0 +1,15 @@
+* Qualcomm Technologies IPQ4019 ASoC SPDIF platform driver
+
+This node models the Qualcomm Technologies IPQ4019 ASoC SPDIF platform driver
+
+Required properties:
+
+- compatible	 : "qca,ipq4019-pcm-spdif"
+- reg		 : should have the stereo register address, length
+
+Example:
+tdmplatform: qca-pcm-spdif at 7707000 {
+	compatible = "qca,ipq4019-pcm-spdif";
+	reg = <0x7709000 0x1000>;
+	status = "disabled";
+};
diff --git a/Documentation/devicetree/bindings/sound/qca,ipq4019-pcm-tdm.txt b/Documentation/devicetree/bindings/sound/qca,ipq4019-pcm-tdm.txt
new file mode 100644
index 0000000..bd3aaa3
--- /dev/null
+++ b/Documentation/devicetree/bindings/sound/qca,ipq4019-pcm-tdm.txt
@@ -0,0 +1,15 @@
+* Qualcomm Technologies IPQ4019 ASoC TDM platform driver
+
+This node models the Qualcomm Technologies IPQ4019 ASoC TDM platform driver
+
+Required properties:
+
+- compatible	 : "qca,ipq4019-pcm-tdm"
+- reg		 : should have the stereo register address, length
+
+Example:
+tdmplatform: qca-pcm-tdm at 7709000 {
+	compatible = "qca,ipq4019-pcm-tdm";
+	reg = <0x7709000 0x1000>;
+	status = "disabled";
+};
diff --git a/Documentation/devicetree/bindings/sound/qca,ipq4019-spdif.txt b/Documentation/devicetree/bindings/sound/qca,ipq4019-spdif.txt
new file mode 100644
index 0000000..5a80bbe
--- /dev/null
+++ b/Documentation/devicetree/bindings/sound/qca,ipq4019-spdif.txt
@@ -0,0 +1,35 @@
+* Qualcomm Technologies IPQ4019 ASoC SPDIF driver
+
+This node models the Qualcomm Technologies IPQ4019 ASoC SPDIF driver
+
+Required properties:
+
+- compatible	 : "qca,ipq4019-spdif"
+- dma-tx-channel : should have the mbox tx channel id
+- dma-rx-channel : should have the mbox rx channel id
+- stereo-tx-port : should have the stereo tx id
+- stereo-rx-port : should have the stereo tx id
+- clocks	 : should have the audio tx bit clock, tx master clock,
+		   spdif clock, spdif divider clock, spdif in fast clock
+- clock-names	 : should be "audio_tx_bclk", "audio_tx_mclk", "audio_spdif_src",
+		   "audio_spdif_div2", "audio_spdifinfast_src"
+
+Example:
+spdif: spdif at 0 {
+	compatible = "qca,ipq4019-spdif";
+	dma-tx-channel = <MBOX0_TX_ID>;
+	dma-rx-channel = <MBOX3_RX_ID>;
+	stereo-tx-port = <STEREO0_ID>;
+	stereo-rx-port = <STEREO3_ID>;
+	clocks = <&adcc ADCC_TXB_CLK_SRC>,
+		<&adcc ADCC_TXM_CLK_SRC>,
+		<&adcc ADCC_SPDIF_SRC>,
+		<&adcc ADCC_SPDIFDIV2_SRC>,
+		<&adcc ADCC_AUDIO_SPDIFINFAST_SRC>;
+	clock-names = "audio_tx_bclk",
+		"audio_tx_mclk",
+		"audio_spdif_src",
+		"audio_spdif_div2",
+		"audio_spdifinfast_src";
+	status = "disabled";
+};
diff --git a/Documentation/devicetree/bindings/sound/qca,ipq4019-stereo.txt b/Documentation/devicetree/bindings/sound/qca,ipq4019-stereo.txt
new file mode 100644
index 0000000..35b4815
--- /dev/null
+++ b/Documentation/devicetree/bindings/sound/qca,ipq4019-stereo.txt
@@ -0,0 +1,17 @@
+* Qualcomm Technologies IPQ4019 ASoC stereo driver
+
+This node models the Qualcomm Technologies IPQ4019 ASoC stereo driver
+
+Required properties:
+
+- compatible	 : "qca,ipq4019-stereo"
+- reg		 : should have the stereo register address, length
+- stereo-index	 : should have the stereo port index
+
+Example:
+stereo0: stereo at 7709000 {
+	compatible = "qca,ipq4019-stereo";
+	reg = <0x7709000 0x1000>;
+	stereo-index = <STEREO0_ID>;
+	status = "disabled";
+};
diff --git a/Documentation/devicetree/bindings/sound/qca,ipq4019-tdm.txt b/Documentation/devicetree/bindings/sound/qca,ipq4019-tdm.txt
new file mode 100644
index 0000000..c2bf38c
--- /dev/null
+++ b/Documentation/devicetree/bindings/sound/qca,ipq4019-tdm.txt
@@ -0,0 +1,33 @@
+* Qualcomm Technologies IPQ4019 ASoC TDM driver
+
+This node models the Qualcomm Technologies IPQ4019 ASoC TDM driver
+
+Required properties:
+
+- compatible	 : "qca,ipq4019-tdm"
+- dma-tx-channel : should have the mbox tx channel id
+- dma-rx-channel : should have the mbox rx channel id
+- stereo-tx-port : should have the stereo tx id
+- stereo-rx-port : should have the stereo tx id
+- clocks	 : should have the audio tx bit clock, tx master clock,
+		   rx bit clock, rx master clock id
+- clock-names	 : should be "audio_tx_bclk", "audio_tx_mclk", "audio_rx_bclk",
+		   "audio_rx_mclk"
+
+Example:
+tdm: tdm at 0 {
+	compatible = "qca,ipq4019-tdm";
+	dma-tx-channel = <MBOX0_TX_ID>;
+	dma-rx-channel = <MBOX3_RX_ID>;
+	stereo-tx-port = <STEREO0_ID>;
+	stereo-rx-port = <STEREO3_ID>;
+	clocks = <&adcc ADCC_TXB_CLK_SRC>,
+		<&adcc ADCC_TXM_CLK_SRC>,
+		<&adcc ADCC_RXB_CLK_SRC>,
+		<&adcc ADCC_RXM_CLK_SRC>;
+	clock-names = "audio_tx_bclk",
+		"audio_tx_mclk",
+		"audio_rx_bclk",
+		"audio_rx_mclk";
+	status = "disabled";
+};
diff --git a/arch/arm/boot/dts/qcom-ipq4019-ap.dk01.1.dtsi b/arch/arm/boot/dts/qcom-ipq4019-ap.dk01.1.dtsi
index b9457dd2..e2ab95a 100644
--- a/arch/arm/boot/dts/qcom-ipq4019-ap.dk01.1.dtsi
+++ b/arch/arm/boot/dts/qcom-ipq4019-ap.dk01.1.dtsi
@@ -1,4 +1,4 @@
-/* Copyright (c) 2015, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2015-2016, The Linux Foundation. All rights reserved.
  *
  * Permission to use, copy, modify, and/or distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
@@ -20,26 +20,7 @@
 	model = "Qualcomm Technologies, Inc. IPQ4019/AP-DK01.1";
 	compatible = "qcom,ipq4019";
 
-	clocks {
-                xo: xo {
-                        compatible = "fixed-clock";
-                        clock-frequency = <48000000>;
-                        #clock-cells = <0>;
-                };
-	};
-
 	soc {
-
-
-		timer {
-			compatible = "arm,armv7-timer";
-			interrupts = <1 2 0xf08>,
-				     <1 3 0xf08>,
-				     <1 4 0xf08>,
-				     <1 1 0xf08>;
-			clock-frequency = <48000000>;
-		};
-
 		pinctrl at 0x01000000 {
 			serial_pins: serial_pinmux {
 				mux {
@@ -69,6 +50,81 @@
 					bias-disable;
 					output-high;
 				};
+
+			};
+
+			audio_pins: audio_pinmux {
+				mux_1 {
+					pins = "gpio25", "gpio53", "gpio60";
+					function = "i2s_tx_bclk";
+					bias-pull,up;
+				};
+
+				mux_2 {
+					pins = "gpio27", "gpio54", "gpio63";
+					function = "i2s_txd1";
+					bias-pull,up;
+				};
+
+				mux_3 {
+					pins = "gpio28", "gpio55";
+					function = "i2s_txd2";
+					bias-pull,up;
+				};
+
+				mux_4 {
+					pins = "gpio29", "gpio56";
+					function = "i2s_txd3";
+					bias-pull,up;
+				};
+
+				mux_5 {
+					pins = "gpio24", "gpio52";
+					function = "i2s_tx_mclk";
+					bias-pull,up;
+				};
+
+				mux_6 {
+					pins = "gpio26", "gpio57", "gpio61";
+					function = "i2s_tx_fsync";
+					bias-pull,up;
+				};
+
+				mux_7 {
+					pins = "gpio2", "gpio23", "gpio63";
+					function = "i2s_rxd";
+					bias-pull,up;
+				};
+
+				mux_8 {
+					pins = "gpio20", "gpio58";
+					function = "i2s_rx_mclk";
+					bias-pull,up;
+				};
+
+				mux_9 {
+					pins = "gpio0", "gpio21", "gpio60";
+					function = "i2s_rx_bclk";
+					bias-pull,up;
+				};
+
+				mux_10 {
+					pins = "gpio1", "gpio22", "gpio61";
+					function = "i2s_rx_fsync";
+					bias-pull,up;
+				};
+
+				mux_11 {
+					pins = "gpio34", "gpio59", "gpio63";
+					function = "i2s_spdif_in";
+					bias-pull,up;
+				};
+
+				mux_12 {
+					pins = "gpio35", "gpio62", "gpio63";
+					function = "i2s_spdif_out";
+					bias-pull,up;
+				};
 			};
 		};
 
@@ -108,5 +164,104 @@
 		watchdog at b017000 {
 			status = "ok";
 		};
+
+		adcc: clock-controller at 7700038 {
+			status = "ok";
+		};
+
+		audio: audio at 7700000 {
+			status = "ok";
+		};
+
+		mbox0: mbox at 7708000 {
+			status = "ok";
+		};
+
+		mbox1: mbox at 770a000 {
+			status = "ok";
+		};
+
+		mbox2: mbox at 770c000 {
+			status = "ok";
+		};
+
+		mbox3: mbox at 770e000 {
+			status = "ok";
+		};
+
+		mbox4: mbox at 7706000 {
+			status = "ok";
+		};
+
+		stereo0: stereo at 7709000 {
+			status = "ok";
+		};
+
+		stereo1: stereo at 770b000 {
+			status = "ok";
+		};
+
+		stereo2: stereo at 770d000 {
+			status = "ok";
+		};
+
+		stereo3: stereo at 770f000 {
+			status = "ok";
+		};
+
+		/* Enable Audio Interfaces */
+		i2s: ipq4019-pcm-i2s at 0 {
+			status = "ok";
+		};
+
+		i2splatform: qca-pcm-i2s at 7709000 {
+			status = "ok";
+		};
+
+		i2s1platform: qca-pcm-i2s1 at 770b000 {
+			status = "ok";
+		};
+
+		i2s1: ipq4019-pcm-i2s1 at 0 {
+			status = "ok";
+		};
+
+		i2s2platform: qca-pcm-i2s2 at 770d000 {
+			status = "ok";
+		};
+
+		i2s2: ipq4019-pcm-i2s2 at 0 {
+			status = "ok";
+		};
+
+		tdmplatform: qca-pcm-tdm at 7709000 {
+			status = "ok";
+		};
+
+		tdm: tdm at 0 {
+			status = "ok";
+		};
+
+		spdifplatform: qca-pcm-spdif at 7707000 {
+			status = "ok";
+		};
+
+		spdif: spdif at 0 {
+			status = "ok";
+		};
+
+		sound: sound at 0 {
+			pinctrl-0 = <&audio_pins>;
+			pinctrl-names = "default";
+			status = "ok";
+		};
+
+		i2c_0: i2c at 78b7000 { /* BLSP1 QUP2 */
+			status = "ok";
+
+			qca_codec: qca_codec at 12 {
+				status = "ok";
+			};
+		};
 	};
 };
diff --git a/arch/arm/boot/dts/qcom-ipq4019.dtsi b/arch/arm/boot/dts/qcom-ipq4019.dtsi
index 5c08d19..e2b4810 100644
--- a/arch/arm/boot/dts/qcom-ipq4019.dtsi
+++ b/arch/arm/boot/dts/qcom-ipq4019.dtsi
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2015-2016, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -15,6 +15,8 @@
 
 #include "skeleton.dtsi"
 #include <dt-bindings/clock/qcom,gcc-ipq4019.h>
+#include <dt-bindings/clock/qca,adcc-ipq4019.h>
+#include <dt-bindings/sound/ipq4019-audio.h>
 #include <dt-bindings/interrupt-controller/arm-gic.h>
 #include <dt-bindings/interrupt-controller/irq.h>
 
@@ -90,6 +92,21 @@
 			clock-frequency = <32768>;
 			#clock-cells = <0>;
 		};
+
+		xo: xo {
+			compatible = "fixed-clock";
+			clock-frequency = <48000000>;
+			#clock-cells = <0>;
+		};
+	};
+
+	timer {
+		compatible = "arm,armv7-timer";
+		interrupts = <1 2 0xf08>,
+			     <1 3 0xf08>,
+			     <1 4 0xf08>,
+			     <1 1 0xf08>;
+		clock-frequency = <48000000>;
 	};
 
 	soc {
@@ -156,8 +173,13 @@
 			#address-cells = <1>;
 			#size-cells = <0>;
 			status = "disabled";
-		};
 
+			qca_codec: qca_codec at 12 {
+				compatible = "qca,ipq4019-codec";
+				reg = <0x12>;
+				status = "disabled";
+			};
+		};
 
 		cryptobam: dma at 8e04000 {
 			compatible = "qcom,bam-v1.7.0";
@@ -263,5 +285,226 @@
 			compatible = "qcom,pshold";
 			reg = <0x4ab000 0x4>;
 		};
+
+		adcc: clock-controller at 7700038 {
+			compatible = "qcom,adcc-ipq4019";
+			#clock-cells = <1>;
+			#reset-cells = <1>;
+			reg = <0x7700038 0x1DC>;
+			status = "disabled";
+		};
+
+		audio: audio at 7700000 {
+			compatible = "qca,ipq4019-audio-adss";
+			reg = <0x7700000 0x34>,
+				<0x7707000 0x20>;
+			resets = <&gcc AUDIO_BLK_ARES>;
+			reset-names = "blk_rst";
+			status = "disabled";
+		};
+
+		pcm: pcm at 7704000 {
+			compatible = "qca,ipq4019-pcm";
+			reg = <0x7704000 0x2000>;
+			dma-tx-channel = <MBOX3_TX_ID>;
+			dma-rx-channel = <MBOX0_RX_ID>;
+			stereo-tx-port = <STEREO3_ID>;
+			stereo-rx-port = <STEREO0_ID>;
+			clocks = <&adcc ADCC_PCM_CLK_SRC>;
+			clock-names = "audio_pcm_clk";
+			status = "disabled";
+		};
+
+		mbox0: mbox at 7708000 {
+			dma-index = <0>;
+			compatible = "qca,ipq4019-mbox";
+			reg = <0x7708000 0x1000>;
+			interrupts = <0 156 0>;
+			tx-channel = <MBOX0_TX_ID>;
+			rx-channel = <MBOX0_RX_ID>;
+			status = "disabled";
+		};
+
+		mbox1: mbox at 770a000 {
+			dma-index = <1>;
+			compatible = "qca,ipq4019-mbox";
+			reg = <0x770A000 0x1000>;
+			interrupts = <0 157 0>;
+			tx-channel = <MBOX1_TX_ID>;
+			status = "disabled";
+		};
+
+		mbox2: mbox at 770c000 {
+			dma-index = <2>;
+			compatible = "qca,ipq4019-mbox";
+			reg = <0x770C000 0x1000>;
+			interrupts = <0 158 0>;
+			tx-channel = <MBOX2_TX_ID>;
+			status = "disabled";
+		};
+
+		mbox3: mbox at 770e000 {
+			dma-index = <3>;
+			compatible = "qca,ipq4019-mbox";
+			reg = <0x770E000 0x1000>;
+			interrupts = <0 159 0>;
+			tx-channel = <MBOX3_TX_ID>;
+			rx-channel = <MBOX3_RX_ID>;
+			status = "disabled";
+		};
+
+		mbox4: mbox at 7706000 {
+			dma-index = <4>;
+			compatible = "qca,ipq4019-mbox";
+			reg = <0x7706000 0x1000>;
+			interrupts = <0 163 0>;
+			rx-channel = <MBOX_SPDIF_RX_ID>;
+			status = "disabled";
+		};
+
+		stereo0: stereo at 7709000 {
+			stereo-index = <STEREO0_ID>;
+			compatible = "qca,ipq4019-stereo";
+			reg = <0x7709000 0x1000>;
+			status = "disabled";
+		};
+
+		stereo1: stereo at 770b000 {
+			stereo-index = <STEREO1_ID>;
+			compatible = "qca,ipq4019-stereo";
+			reg = <0x770B000 0x1000>;
+			status = "disabled";
+		};
+
+		stereo2: stereo at 770d000 {
+			stereo-index = <STEREO2_ID>;
+			compatible = "qca,ipq4019-stereo";
+			reg = <0x770D000 0x1000>;
+			status = "disabled";
+		};
+
+		stereo3: stereo at 770f000 {
+			stereo-index = <STEREO3_ID>;
+			compatible = "qca,ipq4019-stereo";
+			reg = <0x770F000 0x1000>;
+			status = "disabled";
+		};
+
+		i2splatform: qca-pcm-i2s at 7709000 {
+			compatible = "qca,ipq4019-pcm-i2s";
+			reg = <0x7709000 0x1000>;
+			status = "disabled";
+		};
+
+		i2s: ipq4019-pcm-i2s at 0 {
+			compatible = "qca,ipq4019-i2s";
+			dma-tx-channel = <MBOX0_TX_ID>;
+			stereo-tx-port = <STEREO0_ID>;
+			dma-rx-channel = <MBOX3_RX_ID>;
+			stereo-rx-port = <STEREO3_ID>;
+			clocks = <&adcc ADCC_TXB_CLK_SRC>,
+				<&adcc ADCC_TXM_CLK_SRC>,
+				<&adcc ADCC_RXB_CLK_SRC>,
+				<&adcc ADCC_RXM_CLK_SRC>;
+			clock-names = "audio_tx_bclk",
+				"audio_tx_mclk",
+				"audio_rx_bclk",
+				"audio_rx_mclk";
+			status = "disabled";
+		};
+
+		i2s1platform: qca-pcm-i2s1 at 770b000 {
+			compatible = "qca,ipq4019-pcm-i2s1";
+			reg = <0x770b000 0x1000>;
+			status = "disabled";
+		};
+
+		i2s1: ipq4019-pcm-i2s1 at 0 {
+			compatible = "qca,ipq4019-i2s1";
+			dma-tx-channel = <MBOX1_TX_ID>;
+			stereo-tx-port = <STEREO1_ID>;
+			clocks = <&adcc ADCC_TXB_CLK_SRC>,
+				<&adcc ADCC_TXM_CLK_SRC>,
+				<&adcc ADCC_RXB_CLK_SRC>,
+				<&adcc ADCC_RXM_CLK_SRC>;
+			clock-names = "audio_tx_bclk",
+				"audio_tx_mclk",
+				"audio_rx_bclk",
+				"audio_rx_mclk";
+			status = "disabled";
+		};
+
+		i2s2platform: qca-pcm-i2s2 at 770d000 {
+			compatible = "qca,ipq4019-pcm-i2s2";
+			reg = <0x770d000 0x1000>;
+			status = "disabled";
+		};
+
+		i2s2: ipq4019-pcm-i2s2 at 0 {
+			compatible = "qca,ipq4019-i2s2";
+			dma-tx-channel = <MBOX2_TX_ID>;
+			stereo-tx-port = <STEREO2_ID>;
+			clocks = <&adcc ADCC_TXB_CLK_SRC>,
+				<&adcc ADCC_TXM_CLK_SRC>,
+				<&adcc ADCC_RXB_CLK_SRC>,
+				<&adcc ADCC_RXM_CLK_SRC>;
+			clock-names = "audio_tx_bclk",
+				"audio_tx_mclk",
+				"audio_rx_bclk",
+				"audio_rx_mclk";
+			status = "disabled";
+		};
+
+		tdmplatform: qca-pcm-tdm at 7709000 {
+			compatible = "qca,ipq4019-pcm-tdm";
+			reg = <0x7709000 0x1000>;
+			status = "disabled";
+		};
+
+		tdm: tdm at 0 {
+			compatible = "qca,ipq4019-tdm";
+			dma-tx-channel = <MBOX0_TX_ID>;
+			dma-rx-channel = <MBOX3_RX_ID>;
+			stereo-tx-port = <STEREO0_ID>;
+			stereo-rx-port = <STEREO3_ID>;
+			clocks = <&adcc ADCC_TXB_CLK_SRC>,
+				<&adcc ADCC_TXM_CLK_SRC>,
+				<&adcc ADCC_RXB_CLK_SRC>,
+				<&adcc ADCC_RXM_CLK_SRC>;
+			clock-names = "audio_tx_bclk",
+				"audio_tx_mclk",
+				"audio_rx_bclk",
+				"audio_rx_mclk";
+			status = "disabled";
+		};
+
+		spdifplatform: qca-pcm-spdif at 7707000 {
+			compatible = "qca,ipq4019-pcm-spdif";
+			reg = <0x7707000 0x1000>;
+			status = "disabled";
+		};
+
+		spdif: spdif at 0 {
+			compatible = "qca,ipq4019-spdif";
+			dma-tx-channel = <MBOX0_TX_ID>;
+			dma-rx-channel = <MBOX_SPDIF_RX_ID>;
+			stereo-tx-port = <STEREO0_ID>;
+			clocks = <&adcc ADCC_TXB_CLK_SRC>,
+				<&adcc ADCC_TXM_CLK_SRC>,
+				<&adcc ADCC_SPDIF_SRC>,
+				<&adcc ADCC_SPDIFDIV2_SRC >,
+				<&adcc ADCC_AUDIO_SPDIFINFAST_SRC>;
+			clock-names = "audio_tx_bclk",
+				"audio_tx_mclk",
+				"audio_spdif_src",
+				"audio_spdif_div2",
+				"audio_spdifinfast_src";
+			status = "disabled";
+		};
+
+		sound: sound at 0 {
+			compatible = "qca,ipq4019-audio";
+			status = "disabled";
+		};
 	};
 };
-- 
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
a Linux Foundation Collaborative Project

^ permalink raw reply related	[flat|nested] 24+ messages in thread

* [PATCH 2/4] qcom: ipq4019: ASoC clock driver support
  2016-07-15  7:07 ` njaigane
@ 2016-07-15  7:07   ` njaigane at codeaurora.org
  -1 siblings, 0 replies; 24+ messages in thread
From: njaigane @ 2016-07-15  7:07 UTC (permalink / raw)
  To: linux-arm-msm
  Cc: linux, devicetree, linux-kernel, linux-soc, linux-arm-kernel,
	twp, andy.gross, david.brown, robh+dt, pawel.moll, mark.rutland,
	ijc+devicetree, galak, linux, mturquette, sboyd, linus.walleij,
	plai, bgoswami, lgirdwood, broonie, perex, tiwai,
	bjorn.andersson, varada, pradeepb, snlakshm, linux-clk,
	linux-gpio, alsa-devel, bselvara, Jaiganesh Narayanan

From: Jaiganesh Narayanan <njaigane@codeaurora.org>

This patch adds the support for IPQ4019 ASoC clock driver

Signed-off-by: Jaiganesh Narayanan <njaigane@codeaurora.org>
---
 drivers/clk/qcom/Kconfig                     |   8 +
 drivers/clk/qcom/Makefile                    |   2 +
 drivers/clk/qcom/adcc-ipq4019.c              | 700 +++++++++++++++++++++++++++
 drivers/clk/qcom/clk-qcapll.c                | 197 ++++++++
 drivers/clk/qcom/clk-qcapll.h                |  60 +++
 drivers/clk/qcom/clk-rcg.h                   |  68 ++-
 drivers/clk/qcom/clk-rcg2.c                  | 699 +++++++++++++++++++++++++-
 drivers/clk/qcom/common.c                    |   9 +-
 drivers/clk/qcom/common.h                    |   3 +-
 include/dt-bindings/clock/qca,adcc-ipq4019.h |  45 ++
 include/dt-bindings/clock/qcom,gcc-ipq4019.h |   4 +-
 include/dt-bindings/sound/ipq4019-audio.h    |  37 ++
 12 files changed, 1825 insertions(+), 7 deletions(-)
 create mode 100644 drivers/clk/qcom/adcc-ipq4019.c
 create mode 100644 drivers/clk/qcom/clk-qcapll.c
 create mode 100644 drivers/clk/qcom/clk-qcapll.h
 create mode 100644 include/dt-bindings/clock/qca,adcc-ipq4019.h
 create mode 100644 include/dt-bindings/sound/ipq4019-audio.h

diff --git a/drivers/clk/qcom/Kconfig b/drivers/clk/qcom/Kconfig
index 95e3b3e..e21417a 100644
--- a/drivers/clk/qcom/Kconfig
+++ b/drivers/clk/qcom/Kconfig
@@ -36,6 +36,14 @@ config IPQ_GCC_4019
 	  Say Y if you want to use peripheral devices such as UART, SPI,
 	  i2c, USB, SD/eMMC, etc.
 
+config IPQ_ADCC_4019
+	tristate "IPQ4019 Audio Clock Controller"
+	depends on COMMON_CLK_QCOM
+	help
+	  Say Y if you need support for audio clock controller on IPQ4019 devices.
+	  Audio clocks TXM, RXM, TXB and RXB depend on ADCC. ADCC also is used for
+	  selecting the pad's as the source for the ADSS [audio subsystem] clocks.
+
 config IPQ_GCC_806X
 	tristate "IPQ806x Global Clock Controller"
 	depends on COMMON_CLK_QCOM
diff --git a/drivers/clk/qcom/Makefile b/drivers/clk/qcom/Makefile
index 2a25f4e..aec6ab4 100644
--- a/drivers/clk/qcom/Makefile
+++ b/drivers/clk/qcom/Makefile
@@ -4,6 +4,7 @@ clk-qcom-y += common.o
 clk-qcom-y += clk-regmap.o
 clk-qcom-y += clk-alpha-pll.o
 clk-qcom-y += clk-pll.o
+clk-qcom-y += clk-qcapll.o
 clk-qcom-y += clk-rcg.o
 clk-qcom-y += clk-rcg2.o
 clk-qcom-y += clk-branch.o
@@ -15,6 +16,7 @@ clk-qcom-$(CONFIG_QCOM_GDSC) += gdsc.o
 obj-$(CONFIG_APQ_GCC_8084) += gcc-apq8084.o
 obj-$(CONFIG_APQ_MMCC_8084) += mmcc-apq8084.o
 obj-$(CONFIG_IPQ_GCC_4019) += gcc-ipq4019.o
+obj-$(CONFIG_IPQ_ADCC_4019) += adcc-ipq4019.o
 obj-$(CONFIG_IPQ_GCC_806X) += gcc-ipq806x.o
 obj-$(CONFIG_IPQ_LCC_806X) += lcc-ipq806x.o
 obj-$(CONFIG_MSM_GCC_8660) += gcc-msm8660.o
diff --git a/drivers/clk/qcom/adcc-ipq4019.c b/drivers/clk/qcom/adcc-ipq4019.c
new file mode 100644
index 0000000..0ed90e1
--- /dev/null
+++ b/drivers/clk/qcom/adcc-ipq4019.c
@@ -0,0 +1,700 @@
+/*
+ * Copyright (c) 2014 - 2016 The Linux Foundation. All rights reserved.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * 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 <linux/kernel.h>
+#include <linux/err.h>
+#include <linux/platform_device.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/clk-provider.h>
+#include <linux/delay.h>
+#include <linux/regmap.h>
+#include <linux/reset-controller.h>
+
+#include <dt-bindings/clock/qca,adcc-ipq4019.h>
+
+#include "common.h"
+#include "clk-regmap.h"
+#include "clk-rcg.h"
+#include "clk-qcapll.h"
+#include "clk-branch.h"
+#include "reset.h"
+
+#define AUDIO_PLL_CONFIG_REG				0x00000
+#define AUDIO_PLL_MODULATION_REG			0x00004
+#define AUDIO_PLL_MOD_STEP_REG				0x00008
+#define CURRENT_AUDIO_PLL_MODULATION_REG		0x0000c
+#define AUDIO_PLL_CONFIG1_REG				0x00010
+#define AUDIO_ATB_SETTING_REG				0x00014
+#define AUDIO_RXB_CFG_MUXR_REG				0x000cc
+#define AUDIO_RXB_MISC_REG				0x000d0
+#define AUDIO_RXB_CBCR_REG				0x000D4
+#define AUDIO_RXM_CMD_RCGR_REG				0x000e8
+#define AUDIO_RXM_CFG_RCGR_REG				0x000ec
+#define AUDIO_RXM_MISC_REG				0x000f0
+#define AUDIO_RXM_CBCR_REG				0x000F4
+#define AUDIO_TXB_CFG_MUXR_REG				0x0010c
+#define AUDIO_TXB_MISC_REG				0x00110
+#define AUDIO_TXB_CBCR_REG				0x00114
+#define AUDIO_SPDIF_MISC_REG				0x00118
+#define AUDIO_SPDIF_CBCR_REG				0x0011c
+#define AUDIO_SPDIFDIV2_MISC_REG			0x00120
+#define AUDIO_SPDIFDIV2_CBCR_REG			0x00124
+#define AUDIO_TXM_CMD_RCGR_REG				0x00128
+#define AUDIO_TXM_CFG_RCGR_REG				0x0012c
+#define AUDIO_TXM_MISC_REG				0x00130
+#define AUDIO_TXM_CBCR_REG				0x00134
+#define AUDIO_SAMPLE_CBCR_REG				0x00154
+#define AUDIO_PCM_CMD_RCGR_REG				0x00168
+#define AUDIO_PCM_CFG_RCGR_REG				0x0016C
+#define AUDIO_PCM_MISC_REG				0x00170
+#define AUDIO_PCM_CBCR_REG				0x00174
+#define AUDIO_XO_CBCR_REG				0x00194
+#define AUDIO_SPDIFINFAST_CMD_RCGR_REG			0x001A8
+#define AUDIO_SPDIFINFAST_CFG_RCGR_REG			0x001AC
+#define AUDIO_SPDIFINFAST_CBCR_REG			0x001B4
+#define AUDIO_AHB_CBCR_REG				0x001c8
+#define AUDIO_AHB_I2S0_CBCR_REG				0x001cc
+#define AUDIO_AHB_I2S3_CBCR_REG				0x001d0
+#define AUDIO_AHB_MBOX0_CBCR_REG			0x001D4
+#define AUDIO_AHB_MBOX3_CBCR_REG			0x001d8
+
+#define F(f, s, h, m, n) { (f), (s), (2 * (h) - 1), (m), (n) }
+#define P_XO 0
+#define ADSS_PLL 1
+#define MCLK_MCLK_IN 2
+#define BCLK_BCLK_IN 2
+#define BCLK_MCLK_IN 3
+
+static struct parent_map adcc_xo_adpll_padmclk_map[] = {
+	{  P_XO, 0 },
+	{  ADSS_PLL, 1 },
+	{  MCLK_MCLK_IN, 2 },
+};
+
+static const char * const adcc_xo_adpll_padmclk[] = {
+	"xo",
+	"adss_pll",
+	"padmclk",
+};
+
+static struct parent_map adcc_xo_adpll_padbclk_padmclk_map[] = {
+	{  P_XO, 0 },
+	{  ADSS_PLL, 1 },
+	{  MCLK_MCLK_IN, 2 },
+	{  BCLK_MCLK_IN, 3 },
+};
+
+static const char * const adcc_xo_adpll_padbclk_padmclk[] = {
+	"xo",
+	"adss_pll",
+	"padbclk",
+	"padmclk",
+};
+
+static struct parent_map adcc_xo_adpll_map[] = {
+	{  P_XO, 0 },
+	{  ADSS_PLL, 1 },
+};
+
+static const char * const adcc_xo_adpll[] = {
+	"xo",
+	"adss_pll",
+};
+
+static const struct pll_freq_tbl adss_freq_tbl[] = {
+	{163840000, 1, 5, 40, 0x3D708},
+	{180633600, 1, 5, 45, 0xA234},
+	{184320000, 1, 5, 46, 0x51E9},
+	{196608000, 1, 5, 49, 0x9bA6},
+	{197568000, 1, 5, 49, 0x19168},
+	{}
+};
+
+static struct clk_qcapll adss_pll_src = {
+	.config_reg		= AUDIO_PLL_CONFIG_REG,
+	.mod_reg		= AUDIO_PLL_MODULATION_REG,
+	.modstep_reg		= AUDIO_PLL_MOD_STEP_REG,
+	.current_mod_pll_reg	= CURRENT_AUDIO_PLL_MODULATION_REG,
+	.config1_reg		= AUDIO_PLL_CONFIG1_REG,
+	.freq_tbl = adss_freq_tbl,
+	.clkr.hw.init = &(struct clk_init_data){
+		.name = "adss_pll",
+		.parent_names = (const char *[]){ "xo" },
+		.num_parents = 1,
+		.ops = &clk_qcapll_ops,
+		.flags = CLK_IGNORE_UNUSED,
+	},
+};
+
+static const struct freq_tbl ftbl_m_clk[] = {
+	{255, MCLK_MCLK_IN, 1, 0, 0},
+	{2048000, ADSS_PLL, 96, 0, 0},
+	{2822400, ADSS_PLL, 64, 0, 0},
+	{4096000, ADSS_PLL, 48, 0, 0},
+	{5644800, ADSS_PLL, 32, 0, 0},
+	{6144000, ADSS_PLL, 32, 0, 0},
+	{8192000, ADSS_PLL, 24, 0, 0},
+	{11289600, ADSS_PLL, 16, 0, 0},
+	{12288000, ADSS_PLL, 16, 0, 0},
+	{14112000, ADSS_PLL, 14, 0, 0},
+	{15360000, ADSS_PLL, 12, 0, 0},
+	{16384000, ADSS_PLL, 12, 0, 0},
+	{20480000, ADSS_PLL, 8, 0, 0},
+	{22579200, ADSS_PLL, 8, 0, 0},
+	{24576000, ADSS_PLL, 8, 0, 0},
+	{30720000, ADSS_PLL, 6, 0, 0},
+	{ }
+};
+
+static struct clk_cdiv_rcg2 rxm_clk_src = {
+	.cdiv.offset = AUDIO_RXM_MISC_REG,
+	.cdiv.shift = 4,
+	.cdiv.mask = 0xf,
+	.cmd_rcgr = AUDIO_RXM_CMD_RCGR_REG,
+	.hid_width = 5,
+	.parent_map = adcc_xo_adpll_padmclk_map,
+	.freq_tbl = ftbl_m_clk,
+	.clkr.hw.init = &(struct clk_init_data){
+		.name = "rxm_clk_src",
+		.parent_names = adcc_xo_adpll_padmclk,
+		.num_parents = 3,
+		.ops = &clk_cdiv_rcg2_ops,
+		.flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED,
+	},
+};
+
+static struct clk_branch adcc_rxm_clk_src = {
+	.halt_reg = AUDIO_RXM_CBCR_REG,
+	.clkr = {
+		.enable_reg = AUDIO_RXM_CBCR_REG,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "adcc_rxm_clk_src",
+			.parent_names = (const char *[]){"rxm_clk_src"},
+			.num_parents = 1,
+			.ops = &clk_branch2_ops,
+			.flags = CLK_SET_RATE_PARENT,
+		},
+	},
+};
+
+static struct clk_cdiv_rcg2 txm_clk_src = {
+	.cdiv.offset = AUDIO_TXM_MISC_REG,
+	.cdiv.shift = 4,
+	.cdiv.mask = 0xf,
+	.cmd_rcgr = AUDIO_TXM_CMD_RCGR_REG,
+	.hid_width = 5,
+	.parent_map = adcc_xo_adpll_padmclk_map,
+	.freq_tbl = ftbl_m_clk,
+	.clkr.hw.init = &(struct clk_init_data){
+		.name = "txm_clk_src",
+		.parent_names = adcc_xo_adpll_padmclk,
+		.num_parents = 3,
+		.ops = &clk_cdiv_rcg2_ops,
+		.flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED,
+	},
+};
+
+static struct clk_branch adcc_txm_clk_src = {
+	.halt_reg = AUDIO_TXM_CBCR_REG,
+	.clkr = {
+		.enable_reg = AUDIO_TXM_CBCR_REG,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "adcc_txm_clk_src",
+			.parent_names = (const char *[]){
+				"txm_clk_src",
+			},
+			.num_parents = 1,
+			.ops = &clk_branch2_ops,
+			.flags = CLK_SET_RATE_PARENT,
+		},
+	},
+};
+
+static const struct freq_tbl ftbl_bclk_clk[] = {
+	{254, BCLK_BCLK_IN, 1, 0, 0},
+	{255, BCLK_MCLK_IN, 1, 0, 0},
+	{512000, ADSS_PLL, 384, 0, 0},
+	{705600, ADSS_PLL, 256, 0, 0},
+	{1024000, ADSS_PLL, 192, 0, 0},
+	{1411200, ADSS_PLL, 128, 0, 0},
+	{1536000, ADSS_PLL, 128, 0, 0},
+	{2048000, ADSS_PLL, 96, 0, 0},
+	{2822400, ADSS_PLL, 64, 0, 0},
+	{3072000, ADSS_PLL, 64, 0, 0},
+	{4096000, ADSS_PLL, 48, 0, 0},
+	{5120000, ADSS_PLL, 32, 0, 0},
+	{5644800, ADSS_PLL, 32, 0, 0},
+	{6144000, ADSS_PLL, 32, 0, 0},
+	{7056000, ADSS_PLL, 24, 0, 0},
+	{7680000, ADSS_PLL, 24, 0, 0},
+	{8192000, ADSS_PLL, 24, 0, 0},
+	{10240000, ADSS_PLL, 16, 0, 0},
+	{11289600, ADSS_PLL, 16, 0, 0},
+	{12288000, ADSS_PLL, 16, 0, 0},
+	{14112000, ADSS_PLL, 16, 0, 0},
+	{15360000, ADSS_PLL, 12, 0, 0},
+	{16384000, ADSS_PLL, 12, 0, 0},
+	{22579200, ADSS_PLL, 8, 0, 0},
+	{24576000, ADSS_PLL,  8, 0, 0},
+	{30720000, ADSS_PLL,  6, 0, 0},
+	{ }
+};
+
+static struct clk_muxr_misc txb_clk_src = {
+	.misc.offset = AUDIO_TXB_MISC_REG,
+	.misc.shift = 1,
+	.misc.mask = 0x1FF,
+	.muxr.offset = AUDIO_TXB_CFG_MUXR_REG,
+	.muxr.shift = 8,
+	.muxr.mask = 0x7,
+	.parent_map = adcc_xo_adpll_padbclk_padmclk_map,
+	.freq_tbl = ftbl_bclk_clk,
+	.clkr.hw.init = &(struct clk_init_data){
+		.name = "txb_clk_src",
+		.parent_names = adcc_xo_adpll_padbclk_padmclk,
+		.num_parents = 4,
+		.ops = &clk_muxr_misc_ops,
+		.flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED,
+	},
+};
+
+static struct clk_branch adcc_txb_clk_src = {
+	.halt_reg = AUDIO_TXB_CBCR_REG,
+	.clkr = {
+		.enable_reg = AUDIO_TXB_CBCR_REG,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "adcc_txb_clk_src",
+			.parent_names = (const char *[]){
+				"txb_clk_src",
+			},
+			.num_parents = 1,
+			.ops = &clk_branch2_ops,
+			.flags = CLK_SET_RATE_PARENT,
+		},
+	},
+};
+
+static struct clk_muxr_misc rxb_clk_src = {
+	.misc.offset = AUDIO_RXB_MISC_REG,
+	.misc.shift = 1,
+	.misc.mask = 0x1FF,
+	.muxr.offset = AUDIO_RXB_CFG_MUXR_REG,
+	.muxr.shift = 8,
+	.muxr.mask = 0x7,
+	.parent_map = adcc_xo_adpll_padbclk_padmclk_map,
+	.freq_tbl = ftbl_bclk_clk,
+	.clkr.hw.init = &(struct clk_init_data){
+		.name = "rxb_clk_src",
+		.parent_names = adcc_xo_adpll_padbclk_padmclk,
+		.num_parents = 4,
+		.ops = &clk_muxr_misc_ops,
+		.flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED,
+	},
+};
+
+
+static struct clk_branch adcc_rxb_clk_src = {
+	.halt_reg = AUDIO_RXB_CBCR_REG,
+	.clkr = {
+		.enable_reg = AUDIO_RXB_CBCR_REG,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "adcc_rxb_clk_src",
+			.parent_names = (const char *[]){
+				"rxb_clk_src",
+			},
+			.num_parents = 1,
+			.ops = &clk_branch2_ops,
+			.flags = CLK_SET_RATE_PARENT,
+		},
+	},
+};
+
+
+
+static const struct freq_tbl ftbl_adcc_pcm_clk[] = {
+	{8192000, ADSS_PLL, 24, 0, 0},
+	{16384000, ADSS_PLL, 12, 0, 0},
+	{ }
+};
+
+static struct clk_cdiv_rcg2 pcm_clk_src = {
+	.cdiv.offset = AUDIO_PCM_MISC_REG,
+	.cdiv.shift = 4,
+	.cdiv.mask = 0xf,
+	.cmd_rcgr = AUDIO_PCM_CMD_RCGR_REG,
+	.hid_width = 5,
+	.parent_map = adcc_xo_adpll_map,
+	.freq_tbl = ftbl_adcc_pcm_clk,
+	.clkr.hw.init = &(struct clk_init_data){
+		.name = "pcm_clk_src",
+		.parent_names = adcc_xo_adpll,
+		.num_parents = 2,
+		.ops = &clk_cdiv_rcg2_ops,
+		.flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED,
+	},
+};
+
+
+
+static struct clk_branch adcc_pcm_clk_src = {
+	.halt_reg = AUDIO_PCM_CBCR_REG,
+	.clkr = {
+		.enable_reg = AUDIO_PCM_CBCR_REG,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "adcc_pcm_clk_src",
+			.parent_names = (const char *[]){
+				"pcm_clk_src",
+			},
+			.num_parents = 1,
+			.ops = &clk_branch2_ops,
+			.flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED,
+		},
+	},
+};
+
+
+
+static const struct freq_tbl ftbl_adcc_spdifinfast_clk[] = {
+	F(49152000, ADSS_PLL, 0x04, 0, 0),
+	{ }
+};
+
+static struct clk_rcg2 spdifinfast_src = {
+	.cmd_rcgr = AUDIO_SPDIFINFAST_CMD_RCGR_REG,
+	.hid_width = 5,
+	.parent_map = adcc_xo_adpll_map,
+	.freq_tbl = ftbl_adcc_spdifinfast_clk,
+	.clkr.hw.init = &(struct clk_init_data){
+		.name = "spdifinfast_src",
+		.parent_names = adcc_xo_adpll,
+		.num_parents = 2,
+		.ops = &clk_rcg2_ops,
+		.flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED,
+	},
+};
+
+static struct clk_branch adcc_spdifinfast_src = {
+	.halt_reg = AUDIO_SPDIFINFAST_CBCR_REG,
+	.clkr = {
+		.enable_reg = AUDIO_SPDIFINFAST_CBCR_REG,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "adcc_spdifinfast_src",
+			.parent_names = (const char *[]){
+				"spdifinfast_src",
+			},
+			.num_parents = 1,
+			.ops = &clk_branch2_ops,
+			.flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED,
+		},
+	},
+};
+
+static struct clk_muxr_misc spdif_src = {
+	.misc.offset = AUDIO_SPDIF_MISC_REG,
+	.misc.shift = 1,
+	.misc.mask = 0x1FF,
+	.muxr.offset = AUDIO_TXB_CFG_MUXR_REG,
+	.muxr.shift = 8,
+	.muxr.mask = 0x7,
+	.parent_map = adcc_xo_adpll_padbclk_padmclk_map,
+	.freq_tbl = ftbl_m_clk,
+	.clkr.hw.init = &(struct clk_init_data){
+		.name = "spdif_src",
+		.parent_names = adcc_xo_adpll_padbclk_padmclk,
+		.num_parents = 4,
+		.ops = &clk_muxr_misc_ops,
+		.flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED,
+	},
+};
+
+static struct clk_branch adcc_spdif_src = {
+	.halt_reg = AUDIO_SPDIF_CBCR_REG,
+	.clkr = {
+		.enable_reg = AUDIO_SPDIF_CBCR_REG,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "adcc_spdif_src",
+			.parent_names = (const char *[]){
+				"spdif_src",
+			},
+			.num_parents = 1,
+			.ops = &clk_branch2_ops,
+			.flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED,
+		},
+	},
+};
+
+static struct clk_muxr_misc spdifdiv2_src = {
+	.misc.offset = AUDIO_SPDIFDIV2_MISC_REG,
+	.misc.shift = 1,
+	.misc.mask = 0x1FF,
+	.parent_map = adcc_xo_adpll_padbclk_padmclk_map,
+	.muxr.offset = AUDIO_TXB_CFG_MUXR_REG,
+	.muxr.shift = 8,
+	.muxr.mask = 0x7,
+	.freq_tbl = ftbl_bclk_clk,
+	.clkr.hw.init = &(struct clk_init_data){
+		.name = "spdifdiv2_src",
+		.parent_names = adcc_xo_adpll_padbclk_padmclk,
+		.num_parents = 4,
+		.ops = &clk_muxr_misc_ops,
+		.flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED,
+	},
+};
+
+static struct clk_branch adcc_spdifdiv2_src = {
+	.halt_reg = AUDIO_SPDIFDIV2_CBCR_REG,
+	.clkr = {
+		.enable_reg = AUDIO_SPDIFDIV2_CBCR_REG,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "adcc_spdifdiv2_src",
+			.parent_names = (const char *[]){
+				"spdifdiv2_src",
+			},
+			.num_parents = 1,
+			.ops = &clk_branch2_ops,
+			.flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED,
+		},
+	},
+};
+
+static struct clk_branch adcc_sample_src = {
+	.halt_reg = AUDIO_SAMPLE_CBCR_REG,
+	.clkr = {
+		.enable_reg = AUDIO_SAMPLE_CBCR_REG,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "adcc_sample_src",
+			.parent_names = (const char *[]){
+				"pcnoc_clk_src",
+			},
+			.num_parents = 1,
+			.ops = &clk_branch2_ops,
+			.flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED,
+		},
+	},
+};
+
+static struct clk_branch adcc_xo_src = {
+	.halt_reg = AUDIO_XO_CBCR_REG,
+	.clkr = {
+		.enable_reg = AUDIO_XO_CBCR_REG,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "adcc_xo_src",
+			.parent_names = (const char *[]){
+				"XO",
+			},
+			.num_parents = 1,
+			.ops = &clk_branch2_ops,
+			.flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED,
+		},
+	},
+};
+
+
+static struct clk_branch adcc_ahb_src = {
+	.halt_reg = AUDIO_AHB_CBCR_REG,
+	.clkr = {
+		.enable_reg = AUDIO_AHB_CBCR_REG,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "adcc_audio_ahb_src",
+			.parent_names = (const char *[]){
+				"pcnoc_clk_src",
+			},
+			.num_parents = 1,
+			.ops = &clk_branch2_ops,
+			.flags = CLK_IGNORE_UNUSED,
+		},
+	},
+};
+
+static struct clk_branch adcc_ahb_i2s0_src = {
+	.halt_reg = AUDIO_AHB_I2S0_CBCR_REG,
+	.clkr = {
+		.enable_reg = AUDIO_AHB_I2S0_CBCR_REG,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "adcc_audio_ahb_i2s0",
+			.parent_names = (const char *[]){
+				"pcnoc_clk_src",
+			},
+			.num_parents = 1,
+			.ops = &clk_branch2_ops,
+			.flags = CLK_IGNORE_UNUSED,
+		},
+	},
+};
+
+static struct clk_branch adcc_ahb_i2s3_src = {
+	.halt_reg = AUDIO_AHB_I2S3_CBCR_REG,
+	.clkr = {
+		.enable_reg = AUDIO_AHB_I2S3_CBCR_REG,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "adcc_audio_ahb_i2s3",
+			.parent_names = (const char *[]){
+				"pcnoc_clk_src",
+			},
+			.num_parents = 1,
+			.ops = &clk_branch2_ops,
+			.flags = CLK_IGNORE_UNUSED,
+		},
+	},
+};
+
+static struct clk_branch adcc_ahb_mbox0_src = {
+	.halt_reg = AUDIO_AHB_MBOX0_CBCR_REG,
+	.clkr = {
+		.enable_reg = AUDIO_AHB_MBOX0_CBCR_REG,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "adcc_audio_mbox0_src",
+			.parent_names = (const char *[]){
+				"pcnoc_clk_src",
+			},
+			.num_parents = 1,
+			.ops = &clk_branch2_ops,
+			.flags = CLK_IGNORE_UNUSED,
+		},
+	},
+};
+
+static struct clk_branch adcc_ahb_mbox3_src = {
+	.halt_reg = AUDIO_AHB_MBOX3_CBCR_REG,
+	.clkr = {
+		.enable_reg = AUDIO_AHB_MBOX3_CBCR_REG,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "adcc_ahb_mbox3_src",
+			.parent_names = (const char *[]){
+				"pcnoc_clk_src",
+			},
+			.num_parents = 1,
+			.ops = &clk_branch2_ops,
+			.flags = CLK_IGNORE_UNUSED,
+		},
+	},
+};
+
+static struct clk_regmap *adcc_ipq4019_clocks[] = {
+	[ADSS_PLL_SRC]				= &adss_pll_src.clkr,
+	[RXM_CLK_SRC]				= &rxm_clk_src.clkr,
+	[ADCC_RXM_CLK_SRC]			= &adcc_rxm_clk_src.clkr,
+	[TXM_CLK_SRC]				= &txm_clk_src.clkr,
+	[ADCC_TXM_CLK_SRC]			= &adcc_txm_clk_src.clkr,
+	[TXB_CLK_SRC]				= &txb_clk_src.clkr,
+	[ADCC_TXB_CLK_SRC]			= &adcc_txb_clk_src.clkr,
+	[RXB_CLK_SRC]				= &rxb_clk_src.clkr,
+	[ADCC_RXB_CLK_SRC]			= &adcc_rxb_clk_src.clkr,
+	[PCM_CLK_SRC]				= &pcm_clk_src.clkr,
+	[ADCC_PCM_CLK_SRC]			= &adcc_pcm_clk_src.clkr,
+	[AUDIO_SPDIFINFAST_SRC]			= &spdifinfast_src.clkr,
+	[ADCC_AUDIO_SPDIFINFAST_SRC]		= &adcc_spdifinfast_src.clkr,
+	[ADCC_AUDIO_AHB_SRC]			= &adcc_ahb_src.clkr,
+	[ADCC_AHB_I2S0]				= &adcc_ahb_i2s0_src.clkr,
+	[ADCC_AHB_I2S3]				= &adcc_ahb_i2s3_src.clkr,
+	[ADCC_AHB_MBOX0_SRC]			= &adcc_ahb_mbox0_src.clkr,
+	[ADCC_AHB_MBOX3_SRC]			= &adcc_ahb_mbox3_src.clkr,
+	[SPDIF_SRC]				= &spdif_src.clkr,
+	[ADCC_SPDIF_SRC]			= &adcc_spdif_src.clkr,
+	[SPDIFDIV2_SRC]				= &spdifdiv2_src.clkr,
+	[ADCC_SPDIFDIV2_SRC]			= &adcc_spdifdiv2_src.clkr,
+	[ADCC_SAMPLE_SRC]			= &adcc_sample_src.clkr,
+	[ADCC_XO_SRC]				= &adcc_xo_src.clkr,
+};
+
+static const struct qcom_reset_map adcc_ipq4019_resets[] = {
+};
+
+struct cdiv_fixed {
+	char	*name;
+	char	*pname;
+	u32	flags;
+	u32	mult;
+	u32	div;
+};
+
+static const struct regmap_config adcc_ipq4019_regmap_config = {
+	.reg_bits	= 32,
+	.reg_stride	= 4,
+	.val_bits	= 32,
+	.max_register	= 0x2ff,
+	.fast_io	= true,
+};
+
+static const struct qcom_cc_desc adcc_ipq4019_desc = {
+	.config = &adcc_ipq4019_regmap_config,
+	.clks = adcc_ipq4019_clocks,
+	.num_clks = ARRAY_SIZE(adcc_ipq4019_clocks),
+	.resets = adcc_ipq4019_resets,
+	.num_resets = ARRAY_SIZE(adcc_ipq4019_resets),
+};
+
+static const struct of_device_id adcc_ipq4019_match_table[] = {
+	{ .compatible = "qcom,adcc-ipq4019" },
+	{ }
+};
+MODULE_DEVICE_TABLE(of, gcc_ipq4019_match_table);
+
+static int adcc_ipq4019_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct regmap *regmap;
+
+	/* High speed external clock */
+	clk_register_fixed_rate(dev, "xo", NULL, CLK_IS_ROOT, 48000000);
+
+	/* External padbclk & padmclk clock.These [254 & 255] frequencies are
+	 * taken as tokens only to support the INPUTS from PADS.
+	 * Reference: ADSS_HPG/HDD document for IPQ4019
+	 */
+	clk_register_fixed_rate(dev, "padbclk", NULL, CLK_IS_ROOT, 254);
+	clk_register_fixed_rate(dev, "padmclk", NULL, CLK_IS_ROOT, 255);
+
+	regmap = qcom_cc_map(pdev, &adcc_ipq4019_desc);
+	if (IS_ERR(regmap))
+		return PTR_ERR(regmap);
+
+	return qcom_cc_really_probe(pdev, &adcc_ipq4019_desc, regmap);
+}
+
+static int adcc_ipq4019_remove(struct platform_device *pdev)
+{
+	qcom_cc_remove(pdev);
+	return 0;
+}
+
+static struct platform_driver adcc_ipq4019_driver = {
+	.probe		= adcc_ipq4019_probe,
+	.remove		= adcc_ipq4019_remove,
+	.driver		= {
+		.name	= "adcc-ipq4019",
+		.of_match_table = adcc_ipq4019_match_table,
+	},
+};
+module_platform_driver(adcc_ipq4019_driver);
+
+MODULE_DESCRIPTION("Audio Digital Clock controller Driver for IPQ4019");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:adcc-ipq4019");
diff --git a/drivers/clk/qcom/clk-qcapll.c b/drivers/clk/qcom/clk-qcapll.c
new file mode 100644
index 0000000..fac45c8
--- /dev/null
+++ b/drivers/clk/qcom/clk-qcapll.c
@@ -0,0 +1,197 @@
+/*
+ * Copyright (c) 2013, 2015-2016 The Linux Foundation. All rights reserved.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * 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 <linux/kernel.h>
+#include <linux/bitops.h>
+#include <linux/err.h>
+#include <linux/delay.h>
+#include <linux/export.h>
+#include <linux/clk-provider.h>
+#include <linux/regmap.h>
+
+#include <asm/div64.h>
+
+#include "clk-qcapll.h"
+
+#define PLL_CONFIG1_SRESET_L		BIT(0)
+#define PLL_MODULATION_START		BIT(0)
+#define PLL_CONFIG_PLLPWD		BIT(5)
+
+#define PLL_POSTDIV_MASK	0x380
+#define PLL_POSTDIV_SHFT	7
+#define PLL_PLLPWD_MASK         0x20
+#define PLL_PLLPWD_SHFT         5
+#define PLL_REFDIV_MASK		0x7
+#define PLL_REFDIV_SHFT		0
+#define PLL_TGT_INT_SHFT	1
+#define PLL_TGT_INT_MASK	0x3FE
+#define PLL_TGT_FRAC_MASK	0x1FFFF800
+#define PLL_TGT_FRAC_SHFT	11
+
+
+static int clk_qcapll_enable(struct clk_hw *hw)
+{
+	struct clk_qcapll *pll = to_clk_qcapll(hw);
+	int ret;
+
+	/* Enable PLL bypass mode. */
+	ret = regmap_update_bits(pll->clkr.regmap, pll->config_reg,
+				 PLL_CONFIG_PLLPWD, 0);
+	if (ret)
+		return ret;
+
+	return 0;
+}
+
+static void clk_qcapll_disable(struct clk_hw *hw)
+{
+	struct clk_qcapll *pll = to_clk_qcapll(hw);
+
+	/* Disable PLL bypass mode. */
+	regmap_update_bits(pll->clkr.regmap, pll->config_reg, PLL_CONFIG_PLLPWD,
+			   0x1);
+}
+
+static int clk_qcapll_is_enabled(struct clk_hw *hw)
+{
+	u32 config;
+	struct clk_qcapll *pll = to_clk_qcapll(hw);
+
+	regmap_read(pll->clkr.regmap, pll->config_reg, &config);
+	return config & PLL_PLLPWD_MASK;
+}
+
+static unsigned long
+clk_qcapll_recalc_rate(struct clk_hw *hw, unsigned long parent_rate)
+{
+	struct clk_qcapll *pll = to_clk_qcapll(hw);
+	u32 ref_div, post_plldiv, tgt_div_frac, tgt_div_int;
+	u32 config, mod_reg;
+
+	regmap_read(pll->clkr.regmap, pll->config_reg, &config);
+	regmap_read(pll->clkr.regmap, pll->mod_reg, &mod_reg);
+
+	ref_div = (config & PLL_REFDIV_MASK) >> PLL_REFDIV_SHFT;
+	post_plldiv = (config & PLL_POSTDIV_SHFT) >> PLL_POSTDIV_SHFT;
+	tgt_div_frac = (mod_reg & PLL_TGT_FRAC_MASK) >>  PLL_TGT_FRAC_SHFT;
+	tgt_div_int = (mod_reg & PLL_TGT_INT_MASK) >> PLL_TGT_INT_SHFT;
+
+	/*
+	 * FICO = (Fref / (refdiv+1)) * (Ninv + Nfrac[17:5]/2^13
+	 *	   + Nfrac[4:0]/(25*2^13)).
+	 *
+	 * we use this Lookups to get the precise frequencies as we need
+	 * the calculation would need use of some math functions to get
+	 * precise values which will add to the complexity. Hence, a simple
+	 * lookup table based on the Fract values
+	 */
+
+	if (tgt_div_frac == 0x3D708)
+		return 163840000;
+	else if (tgt_div_frac == 0xA234)
+		return 180633600;
+	else if (tgt_div_frac == 0x51E9)
+		return 184320000;
+	else if (tgt_div_frac == 0x9bA6)
+		return 196608000;
+	else if (tgt_div_frac == 0x19168)
+		return 197568000;
+
+	return 0;
+}
+
+static const
+struct pll_freq_tbl *find_freq(const struct pll_freq_tbl *f, unsigned long rate)
+{
+	if (!f)
+		return NULL;
+
+	for (; f->freq; f++)
+		if (rate <= f->freq)
+			return f;
+
+	return NULL;
+}
+
+static int
+clk_qcapll_determine_rate(struct clk_hw *hw, struct clk_rate_request *req)
+{
+	struct clk_qcapll *pll = to_clk_qcapll(hw);
+	const struct pll_freq_tbl *f;
+	unsigned long rate;
+
+	f = find_freq(pll->freq_tbl, req->rate);
+	if (!f)
+		rate = clk_qcapll_recalc_rate(hw, req->best_parent_rate);
+	else
+		rate = f->freq;
+
+	req->best_parent_rate = req->rate = rate;
+
+	return 0;
+}
+
+static int
+clk_qcapll_set_rate(struct clk_hw *hw, unsigned long rate, unsigned long p_rate)
+{
+	struct clk_qcapll *pll = to_clk_qcapll(hw);
+	const struct pll_freq_tbl *f;
+	u32 val, mask;
+
+	f = find_freq(pll->freq_tbl, rate);
+	if (!f)
+		return -EINVAL;
+
+	if (clk_qcapll_is_enabled(hw))
+		clk_qcapll_disable(hw);
+
+	regmap_write(pll->clkr.regmap, pll->config1_reg, 0xc);
+	udelay(2);
+	regmap_write(pll->clkr.regmap, pll->config1_reg, 0xd);
+
+	val = f->postplldiv << PLL_POSTDIV_SHFT;
+	val |= f->refdiv << PLL_REFDIV_SHFT;
+
+	mask = PLL_POSTDIV_MASK | PLL_REFDIV_MASK;
+	regmap_update_bits(pll->clkr.regmap, pll->config_reg, mask, val);
+
+	clk_qcapll_enable(hw);
+
+	val = f->tgt_div_int << PLL_TGT_INT_SHFT;
+	val |= f->tgt_div_frac << PLL_TGT_FRAC_SHFT;
+
+	mask = PLL_TGT_FRAC_MASK | PLL_TGT_INT_MASK;
+	regmap_update_bits(pll->clkr.regmap, pll->mod_reg, mask, val);
+
+	/* Start the PLL to initiate the Modulation. */
+	regmap_update_bits(pll->clkr.regmap, pll->mod_reg,
+						PLL_MODULATION_START, 0);
+
+	/*
+	 * Wait until PLL is locked. Refer DPLL document for IPQ4019.
+	 * This is recommended settling time for the PLL.
+	 */
+	udelay(50);
+
+	return 0;
+}
+
+const struct clk_ops clk_qcapll_ops = {
+	.enable = clk_qcapll_enable,
+	.disable = clk_qcapll_disable,
+	.is_enabled = clk_qcapll_is_enabled,
+	.recalc_rate = clk_qcapll_recalc_rate,
+	.determine_rate = clk_qcapll_determine_rate,
+	.set_rate = clk_qcapll_set_rate,
+};
+EXPORT_SYMBOL_GPL(clk_qcapll_ops);
diff --git a/drivers/clk/qcom/clk-qcapll.h b/drivers/clk/qcom/clk-qcapll.h
new file mode 100644
index 0000000..c0304ac
--- /dev/null
+++ b/drivers/clk/qcom/clk-qcapll.h
@@ -0,0 +1,60 @@
+/*
+ * Copyright (c) 2013, 2015-2016 The Linux Foundation. All rights reserved.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * 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.
+ */
+
+#ifndef __QCOM_CLK_QCA_PLL_H__
+#define __QCOM_CLK_QCA_PLL_H__
+
+#include <linux/clk-provider.h>
+#include "clk-regmap.h"
+
+/**
+ * struct pll_freq_tbl - PLL frequency table
+ * @postplldiv: postplldiv value
+ * @refdiv: refdiv value
+ * @tgt_div_int: tgt_div_int value
+ * @tgt_div_frac: tgt_div_frac values
+ */
+struct pll_freq_tbl {
+	unsigned long freq;
+	u8 postplldiv;
+	u8 refdiv;
+	u8 tgt_div_int;
+	u32 tgt_div_frac;
+};
+
+/**
+ * struct clk_pll - phase locked loop (PLL)
+ * @config_reg: config register
+ * @mode_reg: mode register
+ * @status_reg: status register
+ * @status_bit: ANDed with @status_reg to determine if PLL is enabled
+ * @freq_tbl: PLL frequency table
+ * @hw: handle between common and hardware-specific interfaces
+ */
+struct clk_qcapll {
+	u32 config_reg;
+	u32 mod_reg;
+	u32 modstep_reg;
+	u32 current_mod_pll_reg;
+	u32 config1_reg;
+
+	const struct pll_freq_tbl *freq_tbl;
+	struct clk_regmap clkr;
+};
+
+extern const struct clk_ops clk_qcapll_ops;
+
+#define to_clk_qcapll(_hw) container_of(to_clk_regmap(_hw), \
+						struct clk_qcapll, clkr)
+
+#endif
diff --git a/drivers/clk/qcom/clk-rcg.h b/drivers/clk/qcom/clk-rcg.h
index b904c33..562207c 100644
--- a/drivers/clk/qcom/clk-rcg.h
+++ b/drivers/clk/qcom/clk-rcg.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2013-2016 The Linux Foundation. All rights reserved.
  *
  * This software is licensed under the terms of the GNU General Public
  * License version 2, as published by the Free Software Foundation, and
@@ -20,7 +20,7 @@
 struct freq_tbl {
 	unsigned long freq;
 	u8 src;
-	u8 pre_div;
+	u16 pre_div;
 	u16 m;
 	u16 n;
 };
@@ -68,6 +68,18 @@ struct pre_div {
 };
 
 /**
+ * struct c_div - custom-divider used with Different Offsets
+ * @c_div_offset: offset of the CDIV in the ADDRESS Space
+ * @c_div_shift: lowest bit of pre divider field
+ * @c_div_width: number of bits in pre divider
+ */
+struct c_div {
+	u32	offset;
+	u8	shift;
+	u32	mask;
+};
+
+/**
  * struct src_sel - source selector
  * @src_sel_shift: lowest bit of source selection field
  * @parent_map: map from software's parent index to hardware's src_sel field
@@ -172,6 +184,55 @@ struct clk_rcg2 {
 
 #define to_clk_rcg2(_hw) container_of(to_clk_regmap(_hw), struct clk_rcg2, clkr)
 
+/**
+ * struct clk_cdiv_rcg2 - cdiv with root clock generator
+ *
+ * @cmd_rcgr: corresponds to *_CMD_RCGR
+ * @mnd_width: number of bits in m/n/d values
+ * @hid_width: number of bits in half integer divider
+ * @parent_map: map from software's parent index to hardware's src_sel field
+ * @freq_tbl: frequency table
+ * @clkr: regmap clock handle
+ * @lock: register lock
+ *
+ */
+struct clk_cdiv_rcg2 {
+	u32		cmd_rcgr;
+	u8		mnd_width;
+	u8		hid_width;
+	struct c_div	cdiv;
+	const struct parent_map	*parent_map;
+	const struct freq_tbl	*freq_tbl;
+	struct clk_regmap	clkr;
+};
+
+#define to_clk_cdiv_rcg2(_hw) container_of(to_clk_regmap(_hw), \
+						struct clk_cdiv_rcg2, clkr)
+
+
+/**
+ * struct clk_muxr_misc - mux and misc register
+ *
+ * @cmd_rcgr: corresponds to *_CMD_RCGR
+ * @mnd_width: number of bits in m/n/d values
+ * @hid_width: number of bits in half integer divider
+ * @parent_map: map from software's parent index to hardware's src_sel field
+ * @freq_tbl: frequency table
+ * @clkr: regmap clock handle
+ * @lock: register lock
+ *
+ */
+struct clk_muxr_misc {
+	struct c_div			muxr;
+	struct c_div			misc;
+	const struct parent_map		*parent_map;
+	const struct freq_tbl	*freq_tbl;
+	struct clk_regmap		clkr;
+};
+
+#define to_clk_muxr_misc(_hw) container_of(to_clk_regmap(_hw), \
+						struct clk_muxr_misc, clkr)
+
 extern const struct clk_ops clk_rcg2_ops;
 extern const struct clk_ops clk_rcg2_shared_ops;
 extern const struct clk_ops clk_edp_pixel_ops;
@@ -179,5 +240,8 @@ extern const struct clk_ops clk_byte_ops;
 extern const struct clk_ops clk_byte2_ops;
 extern const struct clk_ops clk_pixel_ops;
 extern const struct clk_ops clk_gfx3d_ops;
+extern const struct clk_ops clk_cdiv_rcg2_ops;
+extern const struct clk_ops clk_cpu_rcg2_ops;
+extern const struct clk_ops clk_muxr_misc_ops;
 
 #endif
diff --git a/drivers/clk/qcom/clk-rcg2.c b/drivers/clk/qcom/clk-rcg2.c
index a071bba..000c423 100644
--- a/drivers/clk/qcom/clk-rcg2.c
+++ b/drivers/clk/qcom/clk-rcg2.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2013-2016, The Linux Foundation. All rights reserved.
  *
  * This software is licensed under the terms of the GNU General Public
  * License version 2, as published by the Free Software Foundation, and
@@ -20,7 +20,6 @@
 #include <linux/delay.h>
 #include <linux/regmap.h>
 #include <linux/math64.h>
-
 #include <asm/div64.h>
 
 #include "clk-rcg.h"
@@ -46,6 +45,7 @@
 #define M_REG			0x8
 #define N_REG			0xc
 #define D_REG			0x10
+#define FEPLL_500_SRC		0x2
 
 static int clk_rcg2_is_enabled(struct clk_hw *hw)
 {
@@ -209,6 +209,7 @@ static int _freq_tbl_determine_rate(struct clk_hw *hw,
 	} else {
 		rate =  clk_hw_get_rate(p);
 	}
+
 	req->best_parent_hw = p;
 	req->best_parent_rate = rate;
 	req->rate = f->freq;
@@ -810,3 +811,697 @@ const struct clk_ops clk_gfx3d_ops = {
 	.determine_rate = clk_gfx3d_determine_rate,
 };
 EXPORT_SYMBOL_GPL(clk_gfx3d_ops);
+
+static int clk_cdiv_rcg2_is_enabled(struct clk_hw *hw)
+{
+	struct clk_cdiv_rcg2 *rcg = to_clk_cdiv_rcg2(hw);
+	u32 cmd = 0;
+	int ret;
+
+	ret = regmap_read(rcg->clkr.regmap, rcg->cmd_rcgr + CMD_REG, &cmd);
+	if (ret < 0)
+		return false;
+
+	return (cmd & CMD_ROOT_OFF) == 0;
+}
+
+static u8 clk_cdiv_rcg2_get_parent(struct clk_hw *hw)
+{
+	struct clk_cdiv_rcg2 *rcg = to_clk_cdiv_rcg2(hw);
+	int num_parents = clk_hw_get_num_parents(hw);
+	u32 cfg;
+	int i, ret;
+
+	ret = regmap_read(rcg->clkr.regmap, rcg->cmd_rcgr + CFG_REG, &cfg);
+	if (ret)
+		goto err;
+
+	cfg &= CFG_SRC_SEL_MASK;
+	cfg >>= CFG_SRC_SEL_SHIFT;
+
+	for (i = 0; i < num_parents; i++)
+		if (cfg == rcg->parent_map[i].cfg)
+			return i;
+err:
+	pr_debug("%s: Cannot find parent of %s clock, using default.\n",
+			__func__, __clk_get_name(hw->clk));
+	return 0;
+}
+
+static int cdiv_update_config(struct clk_cdiv_rcg2 *rcg)
+{
+	int count, ret;
+	struct clk_hw *hw = &rcg->clkr.hw;
+	const char *name = __clk_get_name(hw->clk);
+
+	ret = regmap_update_bits(rcg->clkr.regmap, rcg->cmd_rcgr + CMD_REG,
+				 CMD_UPDATE, CMD_UPDATE);
+	if (ret)
+		return ret;
+
+	/* Wait for update to take effect */
+	for (count = 500; count > 0; count--) {
+		u32 cmd = ~0U;
+
+		/* ignore regmap errors - until we exhaust retry count. */
+		ret = regmap_read(rcg->clkr.regmap, rcg->cmd_rcgr + CMD_REG,
+									&cmd);
+
+		if (ret >= 0 && !(cmd & CMD_UPDATE))
+			return 0;
+
+		udelay(1);
+	}
+
+	WARN(ret, "%s: rcg didn't update its configuration.", name);
+	return ret ? ret : -ETIMEDOUT;
+}
+
+static int clk_cdiv_rcg2_set_parent(struct clk_hw *hw, u8 index)
+{
+	struct clk_cdiv_rcg2 *rcg = to_clk_cdiv_rcg2(hw);
+	int ret;
+
+	ret = regmap_update_bits(rcg->clkr.regmap, rcg->cmd_rcgr + CFG_REG,
+				 CFG_SRC_SEL_MASK,
+				 rcg->parent_map[index].cfg <<
+				 CFG_SRC_SEL_SHIFT);
+	if (ret)
+		return ret;
+
+	return cdiv_update_config(rcg);
+}
+
+static unsigned long
+clk_cdiv_rcg2_recalc_rate(struct clk_hw *hw, unsigned long parent_rate)
+{
+	struct clk_cdiv_rcg2 *rcg = to_clk_cdiv_rcg2(hw);
+	u32 cfg, hid_div, m = 0, n = 0, mode = 0, mask, rate, cdiv;
+	int ret;
+
+	ret = regmap_read(rcg->clkr.regmap, rcg->cmd_rcgr + CFG_REG, &cfg);
+	if (ret)
+		return 0UL;
+
+	if (rcg->mnd_width) {
+		mask = BIT(rcg->mnd_width) - 1;
+		ret = regmap_read(rcg->clkr.regmap, rcg->cmd_rcgr + M_REG, &m);
+		if (ret)
+			return 0UL;
+
+		m &= mask;
+		ret = regmap_read(rcg->clkr.regmap, rcg->cmd_rcgr + N_REG, &n);
+		if (ret)
+			return 0UL;
+
+		n =  ~n;
+		n &= mask;
+
+		n += m;
+		mode = cfg & CFG_MODE_MASK;
+		mode >>= CFG_MODE_SHIFT;
+	}
+
+	mask = BIT(rcg->hid_width) - 1;
+	hid_div = cfg >> CFG_SRC_DIV_SHIFT;
+	hid_div &= mask;
+	rate = calc_rate(parent_rate, m, n, mode, hid_div);
+
+	ret = regmap_read(rcg->clkr.regmap, rcg->cdiv.offset, &cdiv);
+	if (ret)
+		return 0UL;
+
+	cdiv &= (rcg->cdiv.mask << rcg->cdiv.shift);
+	cdiv =  (cdiv >> rcg->cdiv.shift);
+	if (cdiv)
+		rate *= cdiv + 1;
+	return rate;
+}
+
+static int _cdiv_rcg2_freq_tbl_determine_rate(struct clk_hw *hw,
+		const struct freq_tbl *f,
+		struct clk_rate_request *req)
+{
+	unsigned long clk_flags;
+	struct clk_hw *p_hw;
+	unsigned long rate = req->rate;
+
+	f = qcom_find_freq(f, rate);
+	if (!f)
+		return 0L;
+
+	clk_flags = __clk_get_flags(hw->clk);
+	p_hw = clk_hw_get_parent_by_index(hw, f->src);
+	if (clk_flags & CLK_SET_RATE_PARENT) {
+		if (f->pre_div)
+			rate *= f->pre_div;
+		if (f->n) {
+			u64 tmp = rate;
+
+			tmp = tmp * f->n;
+			do_div(tmp, f->m);
+			rate = tmp;
+		}
+	} else {
+		rate =	clk_hw_get_rate(p_hw);
+	}
+
+	req->best_parent_rate = rate;
+	req->best_parent_hw = p_hw;
+	req->rate = f->freq;
+
+	return 0;
+}
+
+
+static int clk_cdiv_rcg2_determine_rate(struct clk_hw *hw,
+					struct clk_rate_request *req)
+{
+	struct clk_cdiv_rcg2 *rcg = to_clk_cdiv_rcg2(hw);
+
+	return _cdiv_rcg2_freq_tbl_determine_rate(hw, rcg->freq_tbl, req);
+}
+
+static int clk_cdiv_rcg2_configure(struct clk_cdiv_rcg2 *rcg,
+				const struct freq_tbl *f)
+{
+	u32 cfg = 0, mask;
+	u32 i;
+	int ret;
+
+	if (rcg->mnd_width && f->n) {
+		mask = BIT(rcg->mnd_width) - 1;
+		ret = regmap_update_bits(rcg->clkr.regmap,
+				rcg->cmd_rcgr + M_REG, mask, f->m);
+		if (ret)
+			return ret;
+
+		ret = regmap_update_bits(rcg->clkr.regmap,
+				rcg->cmd_rcgr + N_REG, mask, ~(f->n - f->m));
+		if (ret)
+			return ret;
+
+		ret = regmap_update_bits(rcg->clkr.regmap,
+				rcg->cmd_rcgr + D_REG, mask, ~f->n);
+		if (ret)
+			return ret;
+	}
+
+
+	if (rcg->cdiv.mask && f->pre_div > 16) {
+
+		/* The division is handled by two dividers. Both of which can
+		 * divide by a maximum value of 16. To achieve a division of
+		 * 256 = 16 * 16, we use a divider of 16 in the RCGR and the
+		 * other divider of 16 in the MISC Register.
+		 */
+		for (i = 2; i <= 16; i++) {
+			if (f->pre_div % i == 0)
+				cfg = i;
+		}
+
+		if (f->pre_div/cfg > 16)
+			return -EINVAL;
+		mask = (rcg->cdiv.mask)<<rcg->cdiv.shift;
+		ret = regmap_update_bits(rcg->clkr.regmap,
+					rcg->cdiv.offset, mask,
+				((cfg - 1) << rcg->cdiv.shift) & mask);
+		if (ret)
+			return ret;
+		cfg = (2 * (f->pre_div / cfg)) - 1;
+	} else {
+		ret = regmap_write(rcg->clkr.regmap, rcg->cdiv.offset, 0x0);
+		if (ret)
+			return ret;
+		cfg = ((2 * f->pre_div) - 1) << CFG_SRC_DIV_SHIFT;
+	}
+
+	mask = BIT(rcg->hid_width) - 1;
+	mask |= CFG_SRC_SEL_MASK | CFG_MODE_MASK;
+	cfg |= rcg->parent_map[f->src].cfg << CFG_SRC_SEL_SHIFT;
+	if (rcg->mnd_width && f->n)
+		cfg |= CFG_MODE_DUAL_EDGE;
+	ret = regmap_update_bits(rcg->clkr.regmap,
+			rcg->cmd_rcgr + CFG_REG, mask, cfg);
+	if (ret)
+		return ret;
+
+	return cdiv_update_config(rcg);
+}
+
+static int __clk_cdiv_rcg2_set_rate(struct clk_hw *hw, unsigned long rate)
+{
+	struct clk_cdiv_rcg2 *rcg = to_clk_cdiv_rcg2(hw);
+	const struct freq_tbl *f;
+
+	f = qcom_find_freq(rcg->freq_tbl, rate);
+	if (!f)
+		return -EINVAL;
+
+	return clk_cdiv_rcg2_configure(rcg, f);
+}
+
+static int clk_cdiv_rcg2_set_rate(struct clk_hw *hw, unsigned long rate,
+			    unsigned long parent_rate)
+{
+	return __clk_cdiv_rcg2_set_rate(hw, rate);
+}
+
+static int clk_cdiv_rcg2_set_rate_and_parent(struct clk_hw *hw,
+		unsigned long rate, unsigned long parent_rate, u8 index)
+{
+	return __clk_cdiv_rcg2_set_rate(hw, rate);
+}
+
+const struct clk_ops clk_cdiv_rcg2_ops = {
+	.is_enabled			= clk_cdiv_rcg2_is_enabled,
+	.get_parent			= clk_cdiv_rcg2_get_parent,
+	.set_parent			= clk_cdiv_rcg2_set_parent,
+	.recalc_rate			= clk_cdiv_rcg2_recalc_rate,
+	.determine_rate			= clk_cdiv_rcg2_determine_rate,
+	.set_rate			= clk_cdiv_rcg2_set_rate,
+	.set_rate_and_parent		= clk_cdiv_rcg2_set_rate_and_parent,
+};
+EXPORT_SYMBOL_GPL(clk_cdiv_rcg2_ops);
+
+static int clk_muxr_is_enabled(struct clk_hw *hw)
+{
+	return 0;
+}
+
+static u8 clk_muxr_get_parent(struct clk_hw *hw)
+{
+	struct clk_muxr_misc *rcg = to_clk_muxr_misc(hw);
+	int num_parents = clk_hw_get_num_parents(hw);
+	u32 cfg;
+	int i, ret;
+
+	ret = regmap_read(rcg->clkr.regmap, rcg->muxr.offset, &cfg);
+	if (ret)
+		goto err;
+
+	cfg >>= rcg->muxr.shift;
+	cfg &= rcg->muxr.mask;
+
+	for (i = 0; i < num_parents; i++)
+		if (cfg == rcg->parent_map[i].cfg)
+			return i;
+
+err:
+	pr_debug("%s: Cannot find parent of %s clock, using default.\n",
+			__func__, __clk_get_name(hw->clk));
+	return 0;
+}
+
+static int clk_muxr_set_parent(struct clk_hw *hw, u8 index)
+{
+	struct clk_muxr_misc *rcg = to_clk_muxr_misc(hw);
+	int ret;
+
+	ret = regmap_update_bits(rcg->clkr.regmap, rcg->muxr.offset,
+				 (rcg->muxr.mask<<rcg->muxr.shift),
+				 rcg->parent_map[index].cfg << rcg->muxr.shift);
+	if (ret)
+		return ret;
+
+	return 0;
+}
+
+static unsigned long
+clk_muxr_recalc_rate(struct clk_hw *hw, unsigned long parent_rate)
+{
+	struct clk_muxr_misc *rcg = to_clk_muxr_misc(hw);
+	u32 misc;
+	int ret;
+
+	ret = regmap_read(rcg->clkr.regmap, rcg->misc.offset, &misc);
+	if (ret)
+		return 0UL;
+
+	misc &= rcg->misc.mask;
+	misc >>= rcg->misc.shift;
+
+	return parent_rate * (misc + 1);
+}
+
+static int clk_muxr_determine_rate(struct clk_hw *hw,
+				   struct clk_rate_request *req)
+{
+	struct clk_muxr_misc *rcg = to_clk_muxr_misc(hw);
+	const struct freq_tbl *f;
+	unsigned long clk_flags;
+	unsigned long rate = req->rate;
+	struct clk_hw *p_hw;
+
+	f = qcom_find_freq(rcg->freq_tbl, rate);
+	if (!f)
+		return 0L;
+
+	clk_flags = __clk_get_flags(hw->clk);
+	p_hw = clk_hw_get_parent_by_index(hw, f->src);
+	if (clk_flags & CLK_SET_RATE_PARENT) {
+		if (f->pre_div)
+			rate *= f->pre_div;
+	} else {
+		rate =	clk_hw_get_rate(p_hw);
+	}
+
+	req->best_parent_rate = rate;
+	req->best_parent_hw = p_hw;
+	req->rate = f->freq;
+
+	return 0;
+}
+
+static int __clk_muxr_set_rate(struct clk_hw *hw, unsigned long rate)
+{
+	struct clk_muxr_misc *rcg = to_clk_muxr_misc(hw);
+	const struct freq_tbl *f;
+	int ret;
+
+	f = qcom_find_freq(rcg->freq_tbl, rate);
+	if (!f)
+		return -EINVAL;
+
+	ret = regmap_update_bits(rcg->clkr.regmap, rcg->muxr.offset,
+				rcg->muxr.mask << rcg->muxr.shift,
+				rcg->parent_map[f->src].cfg << rcg->muxr.shift);
+	if (ret)
+		return ret;
+
+	ret = regmap_update_bits(rcg->clkr.regmap, rcg->misc.offset,
+				rcg->misc.mask << rcg->misc.shift,
+				(f->pre_div - 1) << rcg->misc.shift);
+	return ret;
+}
+
+static int clk_muxr_set_rate(struct clk_hw *hw, unsigned long rate,
+			    unsigned long parent_rate)
+{
+	return __clk_muxr_set_rate(hw, rate);
+}
+
+static int clk_muxr_set_rate_and_parent(struct clk_hw *hw,
+		unsigned long rate, unsigned long parent_rate, u8 index)
+{
+	return __clk_muxr_set_rate(hw, rate);
+}
+
+const struct clk_ops clk_muxr_misc_ops = {
+	.is_enabled	=	clk_muxr_is_enabled,
+	.get_parent	=	clk_muxr_get_parent,
+	.set_parent	=	clk_muxr_set_parent,
+	.recalc_rate	=	clk_muxr_recalc_rate,
+	.determine_rate	=	clk_muxr_determine_rate,
+	.set_rate	=	clk_muxr_set_rate,
+	.set_rate_and_parent	=	clk_muxr_set_rate_and_parent,
+};
+EXPORT_SYMBOL_GPL(clk_muxr_misc_ops);
+
+static int clk_cpu_rcg2_is_enabled(struct clk_hw *hw)
+{
+	struct clk_cdiv_rcg2 *rcg = to_clk_cdiv_rcg2(hw);
+	u32 cmd;
+	int ret;
+
+	ret = regmap_read(rcg->clkr.regmap, rcg->cmd_rcgr + CMD_REG, &cmd);
+	if (ret)
+		return 0;
+
+	return (cmd & CMD_ROOT_OFF) == 0;
+
+}
+
+static u8 clk_cpu_rcg2_get_parent(struct clk_hw *hw)
+{
+	struct clk_cdiv_rcg2 *rcg = to_clk_cdiv_rcg2(hw);
+	int num_parents = clk_hw_get_num_parents(hw);
+	u32 cfg;
+	int i, ret;
+
+	ret = regmap_read(rcg->clkr.regmap, rcg->cmd_rcgr + CFG_REG, &cfg);
+	if (ret)
+		goto err;
+
+	cfg &= CFG_SRC_SEL_MASK;
+	cfg >>= CFG_SRC_SEL_SHIFT;
+
+	for (i = 0; i < num_parents; i++)
+		if (cfg == rcg->parent_map[i].cfg)
+			return i;
+
+err:
+	pr_debug("%s: Cannot find parent of %s clock, using default.\n",
+			__func__, __clk_get_name(hw->clk));
+	return 0;
+}
+
+static int cpu_rcg2_update_config(struct clk_cdiv_rcg2 *rcg)
+{
+	int count, ret;
+	u32 cmd;
+	struct clk_hw *hw = &rcg->clkr.hw;
+	const char *name = __clk_get_name(hw->clk);
+
+	ret = regmap_update_bits(rcg->clkr.regmap, rcg->cmd_rcgr + CMD_REG,
+				 CMD_UPDATE, CMD_UPDATE);
+	if (ret)
+		return ret;
+
+	/* Wait for update to take effect */
+	for (count = 500; count > 0; count--) {
+		/* ignore regmap errors until we exhaust retry count.*/
+		ret = regmap_read(rcg->clkr.regmap, rcg->cmd_rcgr + CMD_REG,
+									&cmd);
+		if (ret >= 0 && !(cmd & CMD_UPDATE))
+			return 0;
+
+		udelay(1);
+	}
+
+	WARN(1, "%s: rcg didn't update its configuration.", name);
+	return ret ? ret : -ETIMEDOUT;
+}
+
+static int clk_cpu_rcg2_set_parent(struct clk_hw *hw, u8 index)
+{
+	struct clk_cdiv_rcg2 *rcg = to_clk_cdiv_rcg2(hw);
+	int ret;
+
+	ret = regmap_update_bits(rcg->clkr.regmap, rcg->cmd_rcgr + CFG_REG,
+				 CFG_SRC_SEL_MASK,
+				 rcg->parent_map[index].cfg <<
+				 CFG_SRC_SEL_SHIFT);
+	if (ret)
+		return ret;
+
+	return cpu_rcg2_update_config(rcg);
+}
+
+
+/*
+ * These are used for looking up the actual divider ratios
+ * the divider used for DDR PLL Post divider is not linear,
+ * hence we need this look up table
+ */
+static const unsigned char ddrpll_div[] = {
+		12,
+		13,
+		14,
+		15,
+		16,
+		17,
+		18,
+		19,
+		20,
+		21,
+		22,
+		24,
+		26,
+		28
+};
+
+static unsigned long
+clk_cpu_rcg2_recalc_rate(struct clk_hw *hw, unsigned long parent_rate)
+{
+	struct clk_cdiv_rcg2 *rcg = to_clk_cdiv_rcg2(hw);
+	u32 cfg, hid_div, m = 0, n = 0, mode = 0, mask, cdiv;
+	unsigned long rate;
+	u32 src;
+	int ret;
+
+	ret = regmap_read(rcg->clkr.regmap, rcg->cmd_rcgr + CFG_REG, &cfg);
+	if (ret)
+		return 0UL;
+
+	if (rcg->mnd_width) {
+		mask = BIT(rcg->mnd_width) - 1;
+		ret = regmap_read(rcg->clkr.regmap, rcg->cmd_rcgr + M_REG, &m);
+		if (ret)
+			return 0UL;
+
+		m &= mask;
+
+		ret = regmap_read(rcg->clkr.regmap, rcg->cmd_rcgr + N_REG, &n);
+		if (ret)
+			return 0UL;
+
+		n =  ~n;
+		n &= mask;
+
+		n += m;
+		mode = cfg & CFG_MODE_MASK;
+		mode >>= CFG_MODE_SHIFT;
+	}
+
+	mask = BIT(rcg->hid_width) - 1;
+	hid_div = cfg >> CFG_SRC_DIV_SHIFT;
+	hid_div &= mask;
+	rate = calc_rate(parent_rate, m, n, mode, hid_div);
+	src = (cfg >> CFG_SRC_SEL_SHIFT) & 0xf;
+	if (src == 0x1) {
+		u64 tmp;
+
+		ret = regmap_read(rcg->clkr.regmap, rcg->cdiv.offset, &cdiv);
+		if (ret)
+			return 0UL;
+
+		cdiv &= (rcg->cdiv.mask << rcg->cdiv.shift);
+		cdiv = cdiv >> rcg->cdiv.shift;
+		tmp = rate;
+		do_div(tmp, ddrpll_div[cdiv]);
+		rate = tmp;
+		rate *= 16;
+		tmp = rate;
+		do_div(tmp, 1000000);
+		rate = tmp;
+		rate = rate * 1000000;
+	}
+	return rate;
+}
+
+static int _cpu_rcg2_freq_tbl_determine_rate(struct clk_hw *hw,
+		const struct freq_tbl *f,
+		struct clk_rate_request *req)
+{
+	unsigned long clk_flags;
+	struct clk_hw *p_hw;
+	unsigned long rate;
+
+	f = qcom_find_freq(f, req->rate);
+	if (!f)
+		return 0L;
+
+	clk_flags = __clk_get_flags(hw->clk);
+	p_hw = clk_hw_get_parent_by_index(hw, f->src);
+	rate = clk_hw_get_rate(p_hw);
+
+	req->best_parent_rate = rate;
+	req->best_parent_hw = p_hw;
+	req->rate = f->freq;
+
+	return 0;
+}
+
+static int clk_cpu_rcg2_determine_rate(struct clk_hw *hw,
+					struct clk_rate_request *req)
+{
+	struct clk_cdiv_rcg2 *rcg = to_clk_cdiv_rcg2(hw);
+
+	return _cpu_rcg2_freq_tbl_determine_rate(hw, rcg->freq_tbl, req);
+}
+
+
+static int clk_cpu_rcg2_configure(struct clk_cdiv_rcg2 *rcg,
+						const struct freq_tbl *f)
+{
+	u32 cfg, mask;
+	int ret;
+
+	if (rcg->mnd_width && f->n) {
+		mask = BIT(rcg->mnd_width) - 1;
+		ret = regmap_update_bits(rcg->clkr.regmap,
+				rcg->cmd_rcgr + M_REG, mask, f->m);
+		if (ret)
+			return ret;
+
+		ret = regmap_update_bits(rcg->clkr.regmap,
+				rcg->cmd_rcgr + N_REG, mask, ~(f->n - f->m));
+		if (ret)
+			return ret;
+
+		ret = regmap_update_bits(rcg->clkr.regmap,
+				rcg->cmd_rcgr + D_REG, mask, ~f->n);
+		if (ret)
+			return ret;
+	}
+
+	if ((rcg->parent_map[f->src].cfg == 0x01)) {
+		mask = (BIT(rcg->hid_width) - 1);
+		mask |= CFG_SRC_SEL_MASK | CFG_MODE_MASK;
+		cfg = FEPLL_500_SRC << CFG_SRC_SEL_SHIFT;
+		cfg |= (1 << CFG_SRC_DIV_SHIFT);
+		ret = regmap_update_bits(rcg->clkr.regmap,
+					rcg->cmd_rcgr + CFG_REG, mask, cfg);
+		if (ret)
+			return ret;
+		cpu_rcg2_update_config(rcg);
+		mask = (rcg->cdiv.mask)<<rcg->cdiv.shift;
+		ret = regmap_update_bits(rcg->clkr.regmap,
+					rcg->cdiv.offset, mask,
+				(f->pre_div << rcg->cdiv.shift) & mask);
+		udelay(1);
+		mask = BIT(rcg->hid_width) - 1;
+		mask |= CFG_SRC_SEL_MASK | CFG_MODE_MASK;
+		cfg = 1 << CFG_SRC_DIV_SHIFT;
+	} else {
+		mask = BIT(rcg->hid_width) - 1;
+		mask |= CFG_SRC_SEL_MASK | CFG_MODE_MASK;
+		cfg = f->pre_div << CFG_SRC_DIV_SHIFT;
+	}
+
+	cfg |= rcg->parent_map[f->src].cfg << CFG_SRC_SEL_SHIFT;
+	if (rcg->mnd_width && f->n)
+		cfg |= CFG_MODE_DUAL_EDGE;
+	ret = regmap_update_bits(rcg->clkr.regmap,
+					rcg->cmd_rcgr + CFG_REG, mask, cfg);
+	if (ret)
+		return ret;
+
+	return cpu_rcg2_update_config(rcg);
+}
+
+static int __clk_cpu_rcg2_set_rate(struct clk_hw *hw, unsigned long rate)
+{
+	struct clk_cdiv_rcg2 *rcg = to_clk_cdiv_rcg2(hw);
+	const struct freq_tbl *f;
+
+	f = qcom_find_freq(rcg->freq_tbl, rate);
+	if (!f)
+		return -EINVAL;
+
+	return clk_cpu_rcg2_configure(rcg, f);
+}
+
+static int clk_cpu_rcg2_set_rate(struct clk_hw *hw, unsigned long rate,
+			    unsigned long parent_rate)
+{
+	return __clk_cpu_rcg2_set_rate(hw, rate);
+}
+
+static int clk_cpu_rcg2_set_rate_and_parent(struct clk_hw *hw,
+		unsigned long rate, unsigned long parent_rate, u8 index)
+{
+	return __clk_cpu_rcg2_set_rate(hw, rate);
+}
+
+const struct clk_ops clk_cpu_rcg2_ops = {
+	.is_enabled	=	clk_cpu_rcg2_is_enabled,
+	.get_parent	=	clk_cpu_rcg2_get_parent,
+	.set_parent	=	clk_cpu_rcg2_set_parent,
+	.recalc_rate	=	clk_cpu_rcg2_recalc_rate,
+	.determine_rate	=	clk_cpu_rcg2_determine_rate,
+	.set_rate	=	clk_cpu_rcg2_set_rate,
+	.set_rate_and_parent	=	clk_cpu_rcg2_set_rate_and_parent,
+};
+EXPORT_SYMBOL_GPL(clk_cpu_rcg2_ops);
diff --git a/drivers/clk/qcom/common.c b/drivers/clk/qcom/common.c
index f7c226a..0851122 100644
--- a/drivers/clk/qcom/common.c
+++ b/drivers/clk/qcom/common.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013-2014, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2013-2016, The Linux Foundation. All rights reserved.
  *
  * This software is licensed under the terms of the GNU General Public
  * License version 2, as published by the Free Software Foundation, and
@@ -269,4 +269,11 @@ int qcom_cc_probe(struct platform_device *pdev, const struct qcom_cc_desc *desc)
 }
 EXPORT_SYMBOL_GPL(qcom_cc_probe);
 
+void qcom_cc_remove(struct platform_device *pdev)
+{
+	of_clk_del_provider(pdev->dev.of_node);
+	reset_controller_unregister(platform_get_drvdata(pdev));
+}
+EXPORT_SYMBOL_GPL(qcom_cc_remove);
+
 MODULE_LICENSE("GPL v2");
diff --git a/drivers/clk/qcom/common.h b/drivers/clk/qcom/common.h
index ae9bdeb..ad66ae2 100644
--- a/drivers/clk/qcom/common.h
+++ b/drivers/clk/qcom/common.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2014-2016 The Linux Foundation. All rights reserved.
  *
  * This software is licensed under the terms of the GNU General Public
  * License version 2, as published by the Free Software Foundation, and
@@ -48,5 +48,6 @@ extern int qcom_cc_really_probe(struct platform_device *pdev,
 				struct regmap *regmap);
 extern int qcom_cc_probe(struct platform_device *pdev,
 			 const struct qcom_cc_desc *desc);
+extern void qcom_cc_remove(struct platform_device *pdev);
 
 #endif
diff --git a/include/dt-bindings/clock/qca,adcc-ipq4019.h b/include/dt-bindings/clock/qca,adcc-ipq4019.h
new file mode 100644
index 0000000..9bd5f35
--- /dev/null
+++ b/include/dt-bindings/clock/qca,adcc-ipq4019.h
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 2015-2016, The Linux Foundation. All rights reserved.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ */
+#ifndef _DT_BINDINGS_CLK_IPQ_ADCC_4019_H
+#define _DT_BINDINGS_CLK_IPQ_ADCC_4019_H
+
+#define ADSS_PLL_SRC				1
+#define RXM_CLK_SRC				2
+#define ADCC_RXM_CLK_SRC			3
+#define TXM_CLK_SRC				4
+#define ADCC_TXM_CLK_SRC			5
+#define TXB_CLK_SRC				6
+#define ADCC_TXB_CLK_SRC			7
+#define RXB_CLK_SRC				8
+#define ADCC_RXB_CLK_SRC			9
+#define PCM_CLK_SRC				10
+#define ADCC_PCM_CLK_SRC			11
+#define AUDIO_SPDIFINFAST_SRC			12
+#define ADCC_AUDIO_SPDIFINFAST_SRC		13
+#define ADCC_AUDIO_AHB_SRC			14
+#define ADCC_AHB_I2S0				15
+#define ADCC_AHB_I2S3				16
+#define ADCC_AHB_MBOX0_SRC			17
+#define ADCC_AHB_MBOX3_SRC			18
+#define SPDIF_SRC				19
+#define ADCC_SPDIF_SRC				20
+#define SPDIFDIV2_SRC				21
+#define ADCC_SPDIFDIV2_SRC			22
+#define ADCC_SAMPLE_SRC				23
+#define ADCC_XO_SRC				24
+
+#endif
diff --git a/include/dt-bindings/clock/qcom,gcc-ipq4019.h b/include/dt-bindings/clock/qcom,gcc-ipq4019.h
index 6240e5b..c75b98a 100644
--- a/include/dt-bindings/clock/qcom,gcc-ipq4019.h
+++ b/include/dt-bindings/clock/qcom,gcc-ipq4019.h
@@ -1,4 +1,5 @@
-/* Copyright (c) 2015 The Linux Foundation. All rights reserved.
+/*
+ * Copyright (c) 2015-2016 The Linux Foundation. All rights reserved.
  *
  * Permission to use, copy, modify, and/or distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
@@ -154,5 +155,6 @@
 #define GCC_QDSS_BCR					69
 #define GCC_MPM_BCR					70
 #define GCC_SPDM_BCR					71
+#define AUDIO_BLK_ARES					GCC_AUDIO_BCR
 
 #endif
diff --git a/include/dt-bindings/sound/ipq4019-audio.h b/include/dt-bindings/sound/ipq4019-audio.h
new file mode 100644
index 0000000..7bf8036
--- /dev/null
+++ b/include/dt-bindings/sound/ipq4019-audio.h
@@ -0,0 +1,37 @@
+/*
+ * Copyright (c) 2015-2016, The Linux Foundation. All rights reserved.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ */
+
+#ifndef __DT_BINDINGS_QCOM_GSBI_H
+#define __DT_BINDINGS_QCOM_GSBI_H
+
+#define MBOX0_TX_ID		0
+#define MBOX0_RX_ID		1
+#define MBOX1_TX_ID		2
+#define MBOX1_RX_ID		3
+#define MBOX2_TX_ID		4
+#define MBOX2_RX_ID		5
+#define MBOX3_TX_ID		6
+#define MBOX3_RX_ID		7
+#define MBOX_SPDIF_TX_ID	8
+#define MBOX_SPDIF_RX_ID	9
+
+#define STEREO0_ID		0
+#define STEREO1_ID		1
+#define STEREO2_ID		2
+#define STEREO3_ID		3
+
+#endif
-- 
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
a Linux Foundation Collaborative Project

^ permalink raw reply related	[flat|nested] 24+ messages in thread

* [PATCH 2/4] qcom: ipq4019: ASoC clock driver support
@ 2016-07-15  7:07   ` njaigane at codeaurora.org
  0 siblings, 0 replies; 24+ messages in thread
From: njaigane at codeaurora.org @ 2016-07-15  7:07 UTC (permalink / raw)
  To: linux-arm-kernel

From: Jaiganesh Narayanan <njaigane@codeaurora.org>

This patch adds the support for IPQ4019 ASoC clock driver

Signed-off-by: Jaiganesh Narayanan <njaigane@codeaurora.org>
---
 drivers/clk/qcom/Kconfig                     |   8 +
 drivers/clk/qcom/Makefile                    |   2 +
 drivers/clk/qcom/adcc-ipq4019.c              | 700 +++++++++++++++++++++++++++
 drivers/clk/qcom/clk-qcapll.c                | 197 ++++++++
 drivers/clk/qcom/clk-qcapll.h                |  60 +++
 drivers/clk/qcom/clk-rcg.h                   |  68 ++-
 drivers/clk/qcom/clk-rcg2.c                  | 699 +++++++++++++++++++++++++-
 drivers/clk/qcom/common.c                    |   9 +-
 drivers/clk/qcom/common.h                    |   3 +-
 include/dt-bindings/clock/qca,adcc-ipq4019.h |  45 ++
 include/dt-bindings/clock/qcom,gcc-ipq4019.h |   4 +-
 include/dt-bindings/sound/ipq4019-audio.h    |  37 ++
 12 files changed, 1825 insertions(+), 7 deletions(-)
 create mode 100644 drivers/clk/qcom/adcc-ipq4019.c
 create mode 100644 drivers/clk/qcom/clk-qcapll.c
 create mode 100644 drivers/clk/qcom/clk-qcapll.h
 create mode 100644 include/dt-bindings/clock/qca,adcc-ipq4019.h
 create mode 100644 include/dt-bindings/sound/ipq4019-audio.h

diff --git a/drivers/clk/qcom/Kconfig b/drivers/clk/qcom/Kconfig
index 95e3b3e..e21417a 100644
--- a/drivers/clk/qcom/Kconfig
+++ b/drivers/clk/qcom/Kconfig
@@ -36,6 +36,14 @@ config IPQ_GCC_4019
 	  Say Y if you want to use peripheral devices such as UART, SPI,
 	  i2c, USB, SD/eMMC, etc.
 
+config IPQ_ADCC_4019
+	tristate "IPQ4019 Audio Clock Controller"
+	depends on COMMON_CLK_QCOM
+	help
+	  Say Y if you need support for audio clock controller on IPQ4019 devices.
+	  Audio clocks TXM, RXM, TXB and RXB depend on ADCC. ADCC also is used for
+	  selecting the pad's as the source for the ADSS [audio subsystem] clocks.
+
 config IPQ_GCC_806X
 	tristate "IPQ806x Global Clock Controller"
 	depends on COMMON_CLK_QCOM
diff --git a/drivers/clk/qcom/Makefile b/drivers/clk/qcom/Makefile
index 2a25f4e..aec6ab4 100644
--- a/drivers/clk/qcom/Makefile
+++ b/drivers/clk/qcom/Makefile
@@ -4,6 +4,7 @@ clk-qcom-y += common.o
 clk-qcom-y += clk-regmap.o
 clk-qcom-y += clk-alpha-pll.o
 clk-qcom-y += clk-pll.o
+clk-qcom-y += clk-qcapll.o
 clk-qcom-y += clk-rcg.o
 clk-qcom-y += clk-rcg2.o
 clk-qcom-y += clk-branch.o
@@ -15,6 +16,7 @@ clk-qcom-$(CONFIG_QCOM_GDSC) += gdsc.o
 obj-$(CONFIG_APQ_GCC_8084) += gcc-apq8084.o
 obj-$(CONFIG_APQ_MMCC_8084) += mmcc-apq8084.o
 obj-$(CONFIG_IPQ_GCC_4019) += gcc-ipq4019.o
+obj-$(CONFIG_IPQ_ADCC_4019) += adcc-ipq4019.o
 obj-$(CONFIG_IPQ_GCC_806X) += gcc-ipq806x.o
 obj-$(CONFIG_IPQ_LCC_806X) += lcc-ipq806x.o
 obj-$(CONFIG_MSM_GCC_8660) += gcc-msm8660.o
diff --git a/drivers/clk/qcom/adcc-ipq4019.c b/drivers/clk/qcom/adcc-ipq4019.c
new file mode 100644
index 0000000..0ed90e1
--- /dev/null
+++ b/drivers/clk/qcom/adcc-ipq4019.c
@@ -0,0 +1,700 @@
+/*
+ * Copyright (c) 2014 - 2016 The Linux Foundation. All rights reserved.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * 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 <linux/kernel.h>
+#include <linux/err.h>
+#include <linux/platform_device.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/clk-provider.h>
+#include <linux/delay.h>
+#include <linux/regmap.h>
+#include <linux/reset-controller.h>
+
+#include <dt-bindings/clock/qca,adcc-ipq4019.h>
+
+#include "common.h"
+#include "clk-regmap.h"
+#include "clk-rcg.h"
+#include "clk-qcapll.h"
+#include "clk-branch.h"
+#include "reset.h"
+
+#define AUDIO_PLL_CONFIG_REG				0x00000
+#define AUDIO_PLL_MODULATION_REG			0x00004
+#define AUDIO_PLL_MOD_STEP_REG				0x00008
+#define CURRENT_AUDIO_PLL_MODULATION_REG		0x0000c
+#define AUDIO_PLL_CONFIG1_REG				0x00010
+#define AUDIO_ATB_SETTING_REG				0x00014
+#define AUDIO_RXB_CFG_MUXR_REG				0x000cc
+#define AUDIO_RXB_MISC_REG				0x000d0
+#define AUDIO_RXB_CBCR_REG				0x000D4
+#define AUDIO_RXM_CMD_RCGR_REG				0x000e8
+#define AUDIO_RXM_CFG_RCGR_REG				0x000ec
+#define AUDIO_RXM_MISC_REG				0x000f0
+#define AUDIO_RXM_CBCR_REG				0x000F4
+#define AUDIO_TXB_CFG_MUXR_REG				0x0010c
+#define AUDIO_TXB_MISC_REG				0x00110
+#define AUDIO_TXB_CBCR_REG				0x00114
+#define AUDIO_SPDIF_MISC_REG				0x00118
+#define AUDIO_SPDIF_CBCR_REG				0x0011c
+#define AUDIO_SPDIFDIV2_MISC_REG			0x00120
+#define AUDIO_SPDIFDIV2_CBCR_REG			0x00124
+#define AUDIO_TXM_CMD_RCGR_REG				0x00128
+#define AUDIO_TXM_CFG_RCGR_REG				0x0012c
+#define AUDIO_TXM_MISC_REG				0x00130
+#define AUDIO_TXM_CBCR_REG				0x00134
+#define AUDIO_SAMPLE_CBCR_REG				0x00154
+#define AUDIO_PCM_CMD_RCGR_REG				0x00168
+#define AUDIO_PCM_CFG_RCGR_REG				0x0016C
+#define AUDIO_PCM_MISC_REG				0x00170
+#define AUDIO_PCM_CBCR_REG				0x00174
+#define AUDIO_XO_CBCR_REG				0x00194
+#define AUDIO_SPDIFINFAST_CMD_RCGR_REG			0x001A8
+#define AUDIO_SPDIFINFAST_CFG_RCGR_REG			0x001AC
+#define AUDIO_SPDIFINFAST_CBCR_REG			0x001B4
+#define AUDIO_AHB_CBCR_REG				0x001c8
+#define AUDIO_AHB_I2S0_CBCR_REG				0x001cc
+#define AUDIO_AHB_I2S3_CBCR_REG				0x001d0
+#define AUDIO_AHB_MBOX0_CBCR_REG			0x001D4
+#define AUDIO_AHB_MBOX3_CBCR_REG			0x001d8
+
+#define F(f, s, h, m, n) { (f), (s), (2 * (h) - 1), (m), (n) }
+#define P_XO 0
+#define ADSS_PLL 1
+#define MCLK_MCLK_IN 2
+#define BCLK_BCLK_IN 2
+#define BCLK_MCLK_IN 3
+
+static struct parent_map adcc_xo_adpll_padmclk_map[] = {
+	{  P_XO, 0 },
+	{  ADSS_PLL, 1 },
+	{  MCLK_MCLK_IN, 2 },
+};
+
+static const char * const adcc_xo_adpll_padmclk[] = {
+	"xo",
+	"adss_pll",
+	"padmclk",
+};
+
+static struct parent_map adcc_xo_adpll_padbclk_padmclk_map[] = {
+	{  P_XO, 0 },
+	{  ADSS_PLL, 1 },
+	{  MCLK_MCLK_IN, 2 },
+	{  BCLK_MCLK_IN, 3 },
+};
+
+static const char * const adcc_xo_adpll_padbclk_padmclk[] = {
+	"xo",
+	"adss_pll",
+	"padbclk",
+	"padmclk",
+};
+
+static struct parent_map adcc_xo_adpll_map[] = {
+	{  P_XO, 0 },
+	{  ADSS_PLL, 1 },
+};
+
+static const char * const adcc_xo_adpll[] = {
+	"xo",
+	"adss_pll",
+};
+
+static const struct pll_freq_tbl adss_freq_tbl[] = {
+	{163840000, 1, 5, 40, 0x3D708},
+	{180633600, 1, 5, 45, 0xA234},
+	{184320000, 1, 5, 46, 0x51E9},
+	{196608000, 1, 5, 49, 0x9bA6},
+	{197568000, 1, 5, 49, 0x19168},
+	{}
+};
+
+static struct clk_qcapll adss_pll_src = {
+	.config_reg		= AUDIO_PLL_CONFIG_REG,
+	.mod_reg		= AUDIO_PLL_MODULATION_REG,
+	.modstep_reg		= AUDIO_PLL_MOD_STEP_REG,
+	.current_mod_pll_reg	= CURRENT_AUDIO_PLL_MODULATION_REG,
+	.config1_reg		= AUDIO_PLL_CONFIG1_REG,
+	.freq_tbl = adss_freq_tbl,
+	.clkr.hw.init = &(struct clk_init_data){
+		.name = "adss_pll",
+		.parent_names = (const char *[]){ "xo" },
+		.num_parents = 1,
+		.ops = &clk_qcapll_ops,
+		.flags = CLK_IGNORE_UNUSED,
+	},
+};
+
+static const struct freq_tbl ftbl_m_clk[] = {
+	{255, MCLK_MCLK_IN, 1, 0, 0},
+	{2048000, ADSS_PLL, 96, 0, 0},
+	{2822400, ADSS_PLL, 64, 0, 0},
+	{4096000, ADSS_PLL, 48, 0, 0},
+	{5644800, ADSS_PLL, 32, 0, 0},
+	{6144000, ADSS_PLL, 32, 0, 0},
+	{8192000, ADSS_PLL, 24, 0, 0},
+	{11289600, ADSS_PLL, 16, 0, 0},
+	{12288000, ADSS_PLL, 16, 0, 0},
+	{14112000, ADSS_PLL, 14, 0, 0},
+	{15360000, ADSS_PLL, 12, 0, 0},
+	{16384000, ADSS_PLL, 12, 0, 0},
+	{20480000, ADSS_PLL, 8, 0, 0},
+	{22579200, ADSS_PLL, 8, 0, 0},
+	{24576000, ADSS_PLL, 8, 0, 0},
+	{30720000, ADSS_PLL, 6, 0, 0},
+	{ }
+};
+
+static struct clk_cdiv_rcg2 rxm_clk_src = {
+	.cdiv.offset = AUDIO_RXM_MISC_REG,
+	.cdiv.shift = 4,
+	.cdiv.mask = 0xf,
+	.cmd_rcgr = AUDIO_RXM_CMD_RCGR_REG,
+	.hid_width = 5,
+	.parent_map = adcc_xo_adpll_padmclk_map,
+	.freq_tbl = ftbl_m_clk,
+	.clkr.hw.init = &(struct clk_init_data){
+		.name = "rxm_clk_src",
+		.parent_names = adcc_xo_adpll_padmclk,
+		.num_parents = 3,
+		.ops = &clk_cdiv_rcg2_ops,
+		.flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED,
+	},
+};
+
+static struct clk_branch adcc_rxm_clk_src = {
+	.halt_reg = AUDIO_RXM_CBCR_REG,
+	.clkr = {
+		.enable_reg = AUDIO_RXM_CBCR_REG,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "adcc_rxm_clk_src",
+			.parent_names = (const char *[]){"rxm_clk_src"},
+			.num_parents = 1,
+			.ops = &clk_branch2_ops,
+			.flags = CLK_SET_RATE_PARENT,
+		},
+	},
+};
+
+static struct clk_cdiv_rcg2 txm_clk_src = {
+	.cdiv.offset = AUDIO_TXM_MISC_REG,
+	.cdiv.shift = 4,
+	.cdiv.mask = 0xf,
+	.cmd_rcgr = AUDIO_TXM_CMD_RCGR_REG,
+	.hid_width = 5,
+	.parent_map = adcc_xo_adpll_padmclk_map,
+	.freq_tbl = ftbl_m_clk,
+	.clkr.hw.init = &(struct clk_init_data){
+		.name = "txm_clk_src",
+		.parent_names = adcc_xo_adpll_padmclk,
+		.num_parents = 3,
+		.ops = &clk_cdiv_rcg2_ops,
+		.flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED,
+	},
+};
+
+static struct clk_branch adcc_txm_clk_src = {
+	.halt_reg = AUDIO_TXM_CBCR_REG,
+	.clkr = {
+		.enable_reg = AUDIO_TXM_CBCR_REG,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "adcc_txm_clk_src",
+			.parent_names = (const char *[]){
+				"txm_clk_src",
+			},
+			.num_parents = 1,
+			.ops = &clk_branch2_ops,
+			.flags = CLK_SET_RATE_PARENT,
+		},
+	},
+};
+
+static const struct freq_tbl ftbl_bclk_clk[] = {
+	{254, BCLK_BCLK_IN, 1, 0, 0},
+	{255, BCLK_MCLK_IN, 1, 0, 0},
+	{512000, ADSS_PLL, 384, 0, 0},
+	{705600, ADSS_PLL, 256, 0, 0},
+	{1024000, ADSS_PLL, 192, 0, 0},
+	{1411200, ADSS_PLL, 128, 0, 0},
+	{1536000, ADSS_PLL, 128, 0, 0},
+	{2048000, ADSS_PLL, 96, 0, 0},
+	{2822400, ADSS_PLL, 64, 0, 0},
+	{3072000, ADSS_PLL, 64, 0, 0},
+	{4096000, ADSS_PLL, 48, 0, 0},
+	{5120000, ADSS_PLL, 32, 0, 0},
+	{5644800, ADSS_PLL, 32, 0, 0},
+	{6144000, ADSS_PLL, 32, 0, 0},
+	{7056000, ADSS_PLL, 24, 0, 0},
+	{7680000, ADSS_PLL, 24, 0, 0},
+	{8192000, ADSS_PLL, 24, 0, 0},
+	{10240000, ADSS_PLL, 16, 0, 0},
+	{11289600, ADSS_PLL, 16, 0, 0},
+	{12288000, ADSS_PLL, 16, 0, 0},
+	{14112000, ADSS_PLL, 16, 0, 0},
+	{15360000, ADSS_PLL, 12, 0, 0},
+	{16384000, ADSS_PLL, 12, 0, 0},
+	{22579200, ADSS_PLL, 8, 0, 0},
+	{24576000, ADSS_PLL,  8, 0, 0},
+	{30720000, ADSS_PLL,  6, 0, 0},
+	{ }
+};
+
+static struct clk_muxr_misc txb_clk_src = {
+	.misc.offset = AUDIO_TXB_MISC_REG,
+	.misc.shift = 1,
+	.misc.mask = 0x1FF,
+	.muxr.offset = AUDIO_TXB_CFG_MUXR_REG,
+	.muxr.shift = 8,
+	.muxr.mask = 0x7,
+	.parent_map = adcc_xo_adpll_padbclk_padmclk_map,
+	.freq_tbl = ftbl_bclk_clk,
+	.clkr.hw.init = &(struct clk_init_data){
+		.name = "txb_clk_src",
+		.parent_names = adcc_xo_adpll_padbclk_padmclk,
+		.num_parents = 4,
+		.ops = &clk_muxr_misc_ops,
+		.flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED,
+	},
+};
+
+static struct clk_branch adcc_txb_clk_src = {
+	.halt_reg = AUDIO_TXB_CBCR_REG,
+	.clkr = {
+		.enable_reg = AUDIO_TXB_CBCR_REG,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "adcc_txb_clk_src",
+			.parent_names = (const char *[]){
+				"txb_clk_src",
+			},
+			.num_parents = 1,
+			.ops = &clk_branch2_ops,
+			.flags = CLK_SET_RATE_PARENT,
+		},
+	},
+};
+
+static struct clk_muxr_misc rxb_clk_src = {
+	.misc.offset = AUDIO_RXB_MISC_REG,
+	.misc.shift = 1,
+	.misc.mask = 0x1FF,
+	.muxr.offset = AUDIO_RXB_CFG_MUXR_REG,
+	.muxr.shift = 8,
+	.muxr.mask = 0x7,
+	.parent_map = adcc_xo_adpll_padbclk_padmclk_map,
+	.freq_tbl = ftbl_bclk_clk,
+	.clkr.hw.init = &(struct clk_init_data){
+		.name = "rxb_clk_src",
+		.parent_names = adcc_xo_adpll_padbclk_padmclk,
+		.num_parents = 4,
+		.ops = &clk_muxr_misc_ops,
+		.flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED,
+	},
+};
+
+
+static struct clk_branch adcc_rxb_clk_src = {
+	.halt_reg = AUDIO_RXB_CBCR_REG,
+	.clkr = {
+		.enable_reg = AUDIO_RXB_CBCR_REG,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "adcc_rxb_clk_src",
+			.parent_names = (const char *[]){
+				"rxb_clk_src",
+			},
+			.num_parents = 1,
+			.ops = &clk_branch2_ops,
+			.flags = CLK_SET_RATE_PARENT,
+		},
+	},
+};
+
+
+
+static const struct freq_tbl ftbl_adcc_pcm_clk[] = {
+	{8192000, ADSS_PLL, 24, 0, 0},
+	{16384000, ADSS_PLL, 12, 0, 0},
+	{ }
+};
+
+static struct clk_cdiv_rcg2 pcm_clk_src = {
+	.cdiv.offset = AUDIO_PCM_MISC_REG,
+	.cdiv.shift = 4,
+	.cdiv.mask = 0xf,
+	.cmd_rcgr = AUDIO_PCM_CMD_RCGR_REG,
+	.hid_width = 5,
+	.parent_map = adcc_xo_adpll_map,
+	.freq_tbl = ftbl_adcc_pcm_clk,
+	.clkr.hw.init = &(struct clk_init_data){
+		.name = "pcm_clk_src",
+		.parent_names = adcc_xo_adpll,
+		.num_parents = 2,
+		.ops = &clk_cdiv_rcg2_ops,
+		.flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED,
+	},
+};
+
+
+
+static struct clk_branch adcc_pcm_clk_src = {
+	.halt_reg = AUDIO_PCM_CBCR_REG,
+	.clkr = {
+		.enable_reg = AUDIO_PCM_CBCR_REG,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "adcc_pcm_clk_src",
+			.parent_names = (const char *[]){
+				"pcm_clk_src",
+			},
+			.num_parents = 1,
+			.ops = &clk_branch2_ops,
+			.flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED,
+		},
+	},
+};
+
+
+
+static const struct freq_tbl ftbl_adcc_spdifinfast_clk[] = {
+	F(49152000, ADSS_PLL, 0x04, 0, 0),
+	{ }
+};
+
+static struct clk_rcg2 spdifinfast_src = {
+	.cmd_rcgr = AUDIO_SPDIFINFAST_CMD_RCGR_REG,
+	.hid_width = 5,
+	.parent_map = adcc_xo_adpll_map,
+	.freq_tbl = ftbl_adcc_spdifinfast_clk,
+	.clkr.hw.init = &(struct clk_init_data){
+		.name = "spdifinfast_src",
+		.parent_names = adcc_xo_adpll,
+		.num_parents = 2,
+		.ops = &clk_rcg2_ops,
+		.flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED,
+	},
+};
+
+static struct clk_branch adcc_spdifinfast_src = {
+	.halt_reg = AUDIO_SPDIFINFAST_CBCR_REG,
+	.clkr = {
+		.enable_reg = AUDIO_SPDIFINFAST_CBCR_REG,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "adcc_spdifinfast_src",
+			.parent_names = (const char *[]){
+				"spdifinfast_src",
+			},
+			.num_parents = 1,
+			.ops = &clk_branch2_ops,
+			.flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED,
+		},
+	},
+};
+
+static struct clk_muxr_misc spdif_src = {
+	.misc.offset = AUDIO_SPDIF_MISC_REG,
+	.misc.shift = 1,
+	.misc.mask = 0x1FF,
+	.muxr.offset = AUDIO_TXB_CFG_MUXR_REG,
+	.muxr.shift = 8,
+	.muxr.mask = 0x7,
+	.parent_map = adcc_xo_adpll_padbclk_padmclk_map,
+	.freq_tbl = ftbl_m_clk,
+	.clkr.hw.init = &(struct clk_init_data){
+		.name = "spdif_src",
+		.parent_names = adcc_xo_adpll_padbclk_padmclk,
+		.num_parents = 4,
+		.ops = &clk_muxr_misc_ops,
+		.flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED,
+	},
+};
+
+static struct clk_branch adcc_spdif_src = {
+	.halt_reg = AUDIO_SPDIF_CBCR_REG,
+	.clkr = {
+		.enable_reg = AUDIO_SPDIF_CBCR_REG,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "adcc_spdif_src",
+			.parent_names = (const char *[]){
+				"spdif_src",
+			},
+			.num_parents = 1,
+			.ops = &clk_branch2_ops,
+			.flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED,
+		},
+	},
+};
+
+static struct clk_muxr_misc spdifdiv2_src = {
+	.misc.offset = AUDIO_SPDIFDIV2_MISC_REG,
+	.misc.shift = 1,
+	.misc.mask = 0x1FF,
+	.parent_map = adcc_xo_adpll_padbclk_padmclk_map,
+	.muxr.offset = AUDIO_TXB_CFG_MUXR_REG,
+	.muxr.shift = 8,
+	.muxr.mask = 0x7,
+	.freq_tbl = ftbl_bclk_clk,
+	.clkr.hw.init = &(struct clk_init_data){
+		.name = "spdifdiv2_src",
+		.parent_names = adcc_xo_adpll_padbclk_padmclk,
+		.num_parents = 4,
+		.ops = &clk_muxr_misc_ops,
+		.flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED,
+	},
+};
+
+static struct clk_branch adcc_spdifdiv2_src = {
+	.halt_reg = AUDIO_SPDIFDIV2_CBCR_REG,
+	.clkr = {
+		.enable_reg = AUDIO_SPDIFDIV2_CBCR_REG,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "adcc_spdifdiv2_src",
+			.parent_names = (const char *[]){
+				"spdifdiv2_src",
+			},
+			.num_parents = 1,
+			.ops = &clk_branch2_ops,
+			.flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED,
+		},
+	},
+};
+
+static struct clk_branch adcc_sample_src = {
+	.halt_reg = AUDIO_SAMPLE_CBCR_REG,
+	.clkr = {
+		.enable_reg = AUDIO_SAMPLE_CBCR_REG,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "adcc_sample_src",
+			.parent_names = (const char *[]){
+				"pcnoc_clk_src",
+			},
+			.num_parents = 1,
+			.ops = &clk_branch2_ops,
+			.flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED,
+		},
+	},
+};
+
+static struct clk_branch adcc_xo_src = {
+	.halt_reg = AUDIO_XO_CBCR_REG,
+	.clkr = {
+		.enable_reg = AUDIO_XO_CBCR_REG,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "adcc_xo_src",
+			.parent_names = (const char *[]){
+				"XO",
+			},
+			.num_parents = 1,
+			.ops = &clk_branch2_ops,
+			.flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED,
+		},
+	},
+};
+
+
+static struct clk_branch adcc_ahb_src = {
+	.halt_reg = AUDIO_AHB_CBCR_REG,
+	.clkr = {
+		.enable_reg = AUDIO_AHB_CBCR_REG,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "adcc_audio_ahb_src",
+			.parent_names = (const char *[]){
+				"pcnoc_clk_src",
+			},
+			.num_parents = 1,
+			.ops = &clk_branch2_ops,
+			.flags = CLK_IGNORE_UNUSED,
+		},
+	},
+};
+
+static struct clk_branch adcc_ahb_i2s0_src = {
+	.halt_reg = AUDIO_AHB_I2S0_CBCR_REG,
+	.clkr = {
+		.enable_reg = AUDIO_AHB_I2S0_CBCR_REG,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "adcc_audio_ahb_i2s0",
+			.parent_names = (const char *[]){
+				"pcnoc_clk_src",
+			},
+			.num_parents = 1,
+			.ops = &clk_branch2_ops,
+			.flags = CLK_IGNORE_UNUSED,
+		},
+	},
+};
+
+static struct clk_branch adcc_ahb_i2s3_src = {
+	.halt_reg = AUDIO_AHB_I2S3_CBCR_REG,
+	.clkr = {
+		.enable_reg = AUDIO_AHB_I2S3_CBCR_REG,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "adcc_audio_ahb_i2s3",
+			.parent_names = (const char *[]){
+				"pcnoc_clk_src",
+			},
+			.num_parents = 1,
+			.ops = &clk_branch2_ops,
+			.flags = CLK_IGNORE_UNUSED,
+		},
+	},
+};
+
+static struct clk_branch adcc_ahb_mbox0_src = {
+	.halt_reg = AUDIO_AHB_MBOX0_CBCR_REG,
+	.clkr = {
+		.enable_reg = AUDIO_AHB_MBOX0_CBCR_REG,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "adcc_audio_mbox0_src",
+			.parent_names = (const char *[]){
+				"pcnoc_clk_src",
+			},
+			.num_parents = 1,
+			.ops = &clk_branch2_ops,
+			.flags = CLK_IGNORE_UNUSED,
+		},
+	},
+};
+
+static struct clk_branch adcc_ahb_mbox3_src = {
+	.halt_reg = AUDIO_AHB_MBOX3_CBCR_REG,
+	.clkr = {
+		.enable_reg = AUDIO_AHB_MBOX3_CBCR_REG,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "adcc_ahb_mbox3_src",
+			.parent_names = (const char *[]){
+				"pcnoc_clk_src",
+			},
+			.num_parents = 1,
+			.ops = &clk_branch2_ops,
+			.flags = CLK_IGNORE_UNUSED,
+		},
+	},
+};
+
+static struct clk_regmap *adcc_ipq4019_clocks[] = {
+	[ADSS_PLL_SRC]				= &adss_pll_src.clkr,
+	[RXM_CLK_SRC]				= &rxm_clk_src.clkr,
+	[ADCC_RXM_CLK_SRC]			= &adcc_rxm_clk_src.clkr,
+	[TXM_CLK_SRC]				= &txm_clk_src.clkr,
+	[ADCC_TXM_CLK_SRC]			= &adcc_txm_clk_src.clkr,
+	[TXB_CLK_SRC]				= &txb_clk_src.clkr,
+	[ADCC_TXB_CLK_SRC]			= &adcc_txb_clk_src.clkr,
+	[RXB_CLK_SRC]				= &rxb_clk_src.clkr,
+	[ADCC_RXB_CLK_SRC]			= &adcc_rxb_clk_src.clkr,
+	[PCM_CLK_SRC]				= &pcm_clk_src.clkr,
+	[ADCC_PCM_CLK_SRC]			= &adcc_pcm_clk_src.clkr,
+	[AUDIO_SPDIFINFAST_SRC]			= &spdifinfast_src.clkr,
+	[ADCC_AUDIO_SPDIFINFAST_SRC]		= &adcc_spdifinfast_src.clkr,
+	[ADCC_AUDIO_AHB_SRC]			= &adcc_ahb_src.clkr,
+	[ADCC_AHB_I2S0]				= &adcc_ahb_i2s0_src.clkr,
+	[ADCC_AHB_I2S3]				= &adcc_ahb_i2s3_src.clkr,
+	[ADCC_AHB_MBOX0_SRC]			= &adcc_ahb_mbox0_src.clkr,
+	[ADCC_AHB_MBOX3_SRC]			= &adcc_ahb_mbox3_src.clkr,
+	[SPDIF_SRC]				= &spdif_src.clkr,
+	[ADCC_SPDIF_SRC]			= &adcc_spdif_src.clkr,
+	[SPDIFDIV2_SRC]				= &spdifdiv2_src.clkr,
+	[ADCC_SPDIFDIV2_SRC]			= &adcc_spdifdiv2_src.clkr,
+	[ADCC_SAMPLE_SRC]			= &adcc_sample_src.clkr,
+	[ADCC_XO_SRC]				= &adcc_xo_src.clkr,
+};
+
+static const struct qcom_reset_map adcc_ipq4019_resets[] = {
+};
+
+struct cdiv_fixed {
+	char	*name;
+	char	*pname;
+	u32	flags;
+	u32	mult;
+	u32	div;
+};
+
+static const struct regmap_config adcc_ipq4019_regmap_config = {
+	.reg_bits	= 32,
+	.reg_stride	= 4,
+	.val_bits	= 32,
+	.max_register	= 0x2ff,
+	.fast_io	= true,
+};
+
+static const struct qcom_cc_desc adcc_ipq4019_desc = {
+	.config = &adcc_ipq4019_regmap_config,
+	.clks = adcc_ipq4019_clocks,
+	.num_clks = ARRAY_SIZE(adcc_ipq4019_clocks),
+	.resets = adcc_ipq4019_resets,
+	.num_resets = ARRAY_SIZE(adcc_ipq4019_resets),
+};
+
+static const struct of_device_id adcc_ipq4019_match_table[] = {
+	{ .compatible = "qcom,adcc-ipq4019" },
+	{ }
+};
+MODULE_DEVICE_TABLE(of, gcc_ipq4019_match_table);
+
+static int adcc_ipq4019_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct regmap *regmap;
+
+	/* High speed external clock */
+	clk_register_fixed_rate(dev, "xo", NULL, CLK_IS_ROOT, 48000000);
+
+	/* External padbclk & padmclk clock.These [254 & 255] frequencies are
+	 * taken as tokens only to support the INPUTS from PADS.
+	 * Reference: ADSS_HPG/HDD document for IPQ4019
+	 */
+	clk_register_fixed_rate(dev, "padbclk", NULL, CLK_IS_ROOT, 254);
+	clk_register_fixed_rate(dev, "padmclk", NULL, CLK_IS_ROOT, 255);
+
+	regmap = qcom_cc_map(pdev, &adcc_ipq4019_desc);
+	if (IS_ERR(regmap))
+		return PTR_ERR(regmap);
+
+	return qcom_cc_really_probe(pdev, &adcc_ipq4019_desc, regmap);
+}
+
+static int adcc_ipq4019_remove(struct platform_device *pdev)
+{
+	qcom_cc_remove(pdev);
+	return 0;
+}
+
+static struct platform_driver adcc_ipq4019_driver = {
+	.probe		= adcc_ipq4019_probe,
+	.remove		= adcc_ipq4019_remove,
+	.driver		= {
+		.name	= "adcc-ipq4019",
+		.of_match_table = adcc_ipq4019_match_table,
+	},
+};
+module_platform_driver(adcc_ipq4019_driver);
+
+MODULE_DESCRIPTION("Audio Digital Clock controller Driver for IPQ4019");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:adcc-ipq4019");
diff --git a/drivers/clk/qcom/clk-qcapll.c b/drivers/clk/qcom/clk-qcapll.c
new file mode 100644
index 0000000..fac45c8
--- /dev/null
+++ b/drivers/clk/qcom/clk-qcapll.c
@@ -0,0 +1,197 @@
+/*
+ * Copyright (c) 2013, 2015-2016 The Linux Foundation. All rights reserved.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * 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 <linux/kernel.h>
+#include <linux/bitops.h>
+#include <linux/err.h>
+#include <linux/delay.h>
+#include <linux/export.h>
+#include <linux/clk-provider.h>
+#include <linux/regmap.h>
+
+#include <asm/div64.h>
+
+#include "clk-qcapll.h"
+
+#define PLL_CONFIG1_SRESET_L		BIT(0)
+#define PLL_MODULATION_START		BIT(0)
+#define PLL_CONFIG_PLLPWD		BIT(5)
+
+#define PLL_POSTDIV_MASK	0x380
+#define PLL_POSTDIV_SHFT	7
+#define PLL_PLLPWD_MASK         0x20
+#define PLL_PLLPWD_SHFT         5
+#define PLL_REFDIV_MASK		0x7
+#define PLL_REFDIV_SHFT		0
+#define PLL_TGT_INT_SHFT	1
+#define PLL_TGT_INT_MASK	0x3FE
+#define PLL_TGT_FRAC_MASK	0x1FFFF800
+#define PLL_TGT_FRAC_SHFT	11
+
+
+static int clk_qcapll_enable(struct clk_hw *hw)
+{
+	struct clk_qcapll *pll = to_clk_qcapll(hw);
+	int ret;
+
+	/* Enable PLL bypass mode. */
+	ret = regmap_update_bits(pll->clkr.regmap, pll->config_reg,
+				 PLL_CONFIG_PLLPWD, 0);
+	if (ret)
+		return ret;
+
+	return 0;
+}
+
+static void clk_qcapll_disable(struct clk_hw *hw)
+{
+	struct clk_qcapll *pll = to_clk_qcapll(hw);
+
+	/* Disable PLL bypass mode. */
+	regmap_update_bits(pll->clkr.regmap, pll->config_reg, PLL_CONFIG_PLLPWD,
+			   0x1);
+}
+
+static int clk_qcapll_is_enabled(struct clk_hw *hw)
+{
+	u32 config;
+	struct clk_qcapll *pll = to_clk_qcapll(hw);
+
+	regmap_read(pll->clkr.regmap, pll->config_reg, &config);
+	return config & PLL_PLLPWD_MASK;
+}
+
+static unsigned long
+clk_qcapll_recalc_rate(struct clk_hw *hw, unsigned long parent_rate)
+{
+	struct clk_qcapll *pll = to_clk_qcapll(hw);
+	u32 ref_div, post_plldiv, tgt_div_frac, tgt_div_int;
+	u32 config, mod_reg;
+
+	regmap_read(pll->clkr.regmap, pll->config_reg, &config);
+	regmap_read(pll->clkr.regmap, pll->mod_reg, &mod_reg);
+
+	ref_div = (config & PLL_REFDIV_MASK) >> PLL_REFDIV_SHFT;
+	post_plldiv = (config & PLL_POSTDIV_SHFT) >> PLL_POSTDIV_SHFT;
+	tgt_div_frac = (mod_reg & PLL_TGT_FRAC_MASK) >>  PLL_TGT_FRAC_SHFT;
+	tgt_div_int = (mod_reg & PLL_TGT_INT_MASK) >> PLL_TGT_INT_SHFT;
+
+	/*
+	 * FICO = (Fref / (refdiv+1)) * (Ninv + Nfrac[17:5]/2^13
+	 *	   + Nfrac[4:0]/(25*2^13)).
+	 *
+	 * we use this Lookups to get the precise frequencies as we need
+	 * the calculation would need use of some math functions to get
+	 * precise values which will add to the complexity. Hence, a simple
+	 * lookup table based on the Fract values
+	 */
+
+	if (tgt_div_frac == 0x3D708)
+		return 163840000;
+	else if (tgt_div_frac == 0xA234)
+		return 180633600;
+	else if (tgt_div_frac == 0x51E9)
+		return 184320000;
+	else if (tgt_div_frac == 0x9bA6)
+		return 196608000;
+	else if (tgt_div_frac == 0x19168)
+		return 197568000;
+
+	return 0;
+}
+
+static const
+struct pll_freq_tbl *find_freq(const struct pll_freq_tbl *f, unsigned long rate)
+{
+	if (!f)
+		return NULL;
+
+	for (; f->freq; f++)
+		if (rate <= f->freq)
+			return f;
+
+	return NULL;
+}
+
+static int
+clk_qcapll_determine_rate(struct clk_hw *hw, struct clk_rate_request *req)
+{
+	struct clk_qcapll *pll = to_clk_qcapll(hw);
+	const struct pll_freq_tbl *f;
+	unsigned long rate;
+
+	f = find_freq(pll->freq_tbl, req->rate);
+	if (!f)
+		rate = clk_qcapll_recalc_rate(hw, req->best_parent_rate);
+	else
+		rate = f->freq;
+
+	req->best_parent_rate = req->rate = rate;
+
+	return 0;
+}
+
+static int
+clk_qcapll_set_rate(struct clk_hw *hw, unsigned long rate, unsigned long p_rate)
+{
+	struct clk_qcapll *pll = to_clk_qcapll(hw);
+	const struct pll_freq_tbl *f;
+	u32 val, mask;
+
+	f = find_freq(pll->freq_tbl, rate);
+	if (!f)
+		return -EINVAL;
+
+	if (clk_qcapll_is_enabled(hw))
+		clk_qcapll_disable(hw);
+
+	regmap_write(pll->clkr.regmap, pll->config1_reg, 0xc);
+	udelay(2);
+	regmap_write(pll->clkr.regmap, pll->config1_reg, 0xd);
+
+	val = f->postplldiv << PLL_POSTDIV_SHFT;
+	val |= f->refdiv << PLL_REFDIV_SHFT;
+
+	mask = PLL_POSTDIV_MASK | PLL_REFDIV_MASK;
+	regmap_update_bits(pll->clkr.regmap, pll->config_reg, mask, val);
+
+	clk_qcapll_enable(hw);
+
+	val = f->tgt_div_int << PLL_TGT_INT_SHFT;
+	val |= f->tgt_div_frac << PLL_TGT_FRAC_SHFT;
+
+	mask = PLL_TGT_FRAC_MASK | PLL_TGT_INT_MASK;
+	regmap_update_bits(pll->clkr.regmap, pll->mod_reg, mask, val);
+
+	/* Start the PLL to initiate the Modulation. */
+	regmap_update_bits(pll->clkr.regmap, pll->mod_reg,
+						PLL_MODULATION_START, 0);
+
+	/*
+	 * Wait until PLL is locked. Refer DPLL document for IPQ4019.
+	 * This is recommended settling time for the PLL.
+	 */
+	udelay(50);
+
+	return 0;
+}
+
+const struct clk_ops clk_qcapll_ops = {
+	.enable = clk_qcapll_enable,
+	.disable = clk_qcapll_disable,
+	.is_enabled = clk_qcapll_is_enabled,
+	.recalc_rate = clk_qcapll_recalc_rate,
+	.determine_rate = clk_qcapll_determine_rate,
+	.set_rate = clk_qcapll_set_rate,
+};
+EXPORT_SYMBOL_GPL(clk_qcapll_ops);
diff --git a/drivers/clk/qcom/clk-qcapll.h b/drivers/clk/qcom/clk-qcapll.h
new file mode 100644
index 0000000..c0304ac
--- /dev/null
+++ b/drivers/clk/qcom/clk-qcapll.h
@@ -0,0 +1,60 @@
+/*
+ * Copyright (c) 2013, 2015-2016 The Linux Foundation. All rights reserved.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * 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.
+ */
+
+#ifndef __QCOM_CLK_QCA_PLL_H__
+#define __QCOM_CLK_QCA_PLL_H__
+
+#include <linux/clk-provider.h>
+#include "clk-regmap.h"
+
+/**
+ * struct pll_freq_tbl - PLL frequency table
+ * @postplldiv: postplldiv value
+ * @refdiv: refdiv value
+ * @tgt_div_int: tgt_div_int value
+ * @tgt_div_frac: tgt_div_frac values
+ */
+struct pll_freq_tbl {
+	unsigned long freq;
+	u8 postplldiv;
+	u8 refdiv;
+	u8 tgt_div_int;
+	u32 tgt_div_frac;
+};
+
+/**
+ * struct clk_pll - phase locked loop (PLL)
+ * @config_reg: config register
+ * @mode_reg: mode register
+ * @status_reg: status register
+ * @status_bit: ANDed with @status_reg to determine if PLL is enabled
+ * @freq_tbl: PLL frequency table
+ * @hw: handle between common and hardware-specific interfaces
+ */
+struct clk_qcapll {
+	u32 config_reg;
+	u32 mod_reg;
+	u32 modstep_reg;
+	u32 current_mod_pll_reg;
+	u32 config1_reg;
+
+	const struct pll_freq_tbl *freq_tbl;
+	struct clk_regmap clkr;
+};
+
+extern const struct clk_ops clk_qcapll_ops;
+
+#define to_clk_qcapll(_hw) container_of(to_clk_regmap(_hw), \
+						struct clk_qcapll, clkr)
+
+#endif
diff --git a/drivers/clk/qcom/clk-rcg.h b/drivers/clk/qcom/clk-rcg.h
index b904c33..562207c 100644
--- a/drivers/clk/qcom/clk-rcg.h
+++ b/drivers/clk/qcom/clk-rcg.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2013-2016 The Linux Foundation. All rights reserved.
  *
  * This software is licensed under the terms of the GNU General Public
  * License version 2, as published by the Free Software Foundation, and
@@ -20,7 +20,7 @@
 struct freq_tbl {
 	unsigned long freq;
 	u8 src;
-	u8 pre_div;
+	u16 pre_div;
 	u16 m;
 	u16 n;
 };
@@ -68,6 +68,18 @@ struct pre_div {
 };
 
 /**
+ * struct c_div - custom-divider used with Different Offsets
+ * @c_div_offset: offset of the CDIV in the ADDRESS Space
+ * @c_div_shift: lowest bit of pre divider field
+ * @c_div_width: number of bits in pre divider
+ */
+struct c_div {
+	u32	offset;
+	u8	shift;
+	u32	mask;
+};
+
+/**
  * struct src_sel - source selector
  * @src_sel_shift: lowest bit of source selection field
  * @parent_map: map from software's parent index to hardware's src_sel field
@@ -172,6 +184,55 @@ struct clk_rcg2 {
 
 #define to_clk_rcg2(_hw) container_of(to_clk_regmap(_hw), struct clk_rcg2, clkr)
 
+/**
+ * struct clk_cdiv_rcg2 - cdiv with root clock generator
+ *
+ * @cmd_rcgr: corresponds to *_CMD_RCGR
+ * @mnd_width: number of bits in m/n/d values
+ * @hid_width: number of bits in half integer divider
+ * @parent_map: map from software's parent index to hardware's src_sel field
+ * @freq_tbl: frequency table
+ * @clkr: regmap clock handle
+ * @lock: register lock
+ *
+ */
+struct clk_cdiv_rcg2 {
+	u32		cmd_rcgr;
+	u8		mnd_width;
+	u8		hid_width;
+	struct c_div	cdiv;
+	const struct parent_map	*parent_map;
+	const struct freq_tbl	*freq_tbl;
+	struct clk_regmap	clkr;
+};
+
+#define to_clk_cdiv_rcg2(_hw) container_of(to_clk_regmap(_hw), \
+						struct clk_cdiv_rcg2, clkr)
+
+
+/**
+ * struct clk_muxr_misc - mux and misc register
+ *
+ * @cmd_rcgr: corresponds to *_CMD_RCGR
+ * @mnd_width: number of bits in m/n/d values
+ * @hid_width: number of bits in half integer divider
+ * @parent_map: map from software's parent index to hardware's src_sel field
+ * @freq_tbl: frequency table
+ * @clkr: regmap clock handle
+ * @lock: register lock
+ *
+ */
+struct clk_muxr_misc {
+	struct c_div			muxr;
+	struct c_div			misc;
+	const struct parent_map		*parent_map;
+	const struct freq_tbl	*freq_tbl;
+	struct clk_regmap		clkr;
+};
+
+#define to_clk_muxr_misc(_hw) container_of(to_clk_regmap(_hw), \
+						struct clk_muxr_misc, clkr)
+
 extern const struct clk_ops clk_rcg2_ops;
 extern const struct clk_ops clk_rcg2_shared_ops;
 extern const struct clk_ops clk_edp_pixel_ops;
@@ -179,5 +240,8 @@ extern const struct clk_ops clk_byte_ops;
 extern const struct clk_ops clk_byte2_ops;
 extern const struct clk_ops clk_pixel_ops;
 extern const struct clk_ops clk_gfx3d_ops;
+extern const struct clk_ops clk_cdiv_rcg2_ops;
+extern const struct clk_ops clk_cpu_rcg2_ops;
+extern const struct clk_ops clk_muxr_misc_ops;
 
 #endif
diff --git a/drivers/clk/qcom/clk-rcg2.c b/drivers/clk/qcom/clk-rcg2.c
index a071bba..000c423 100644
--- a/drivers/clk/qcom/clk-rcg2.c
+++ b/drivers/clk/qcom/clk-rcg2.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2013-2016, The Linux Foundation. All rights reserved.
  *
  * This software is licensed under the terms of the GNU General Public
  * License version 2, as published by the Free Software Foundation, and
@@ -20,7 +20,6 @@
 #include <linux/delay.h>
 #include <linux/regmap.h>
 #include <linux/math64.h>
-
 #include <asm/div64.h>
 
 #include "clk-rcg.h"
@@ -46,6 +45,7 @@
 #define M_REG			0x8
 #define N_REG			0xc
 #define D_REG			0x10
+#define FEPLL_500_SRC		0x2
 
 static int clk_rcg2_is_enabled(struct clk_hw *hw)
 {
@@ -209,6 +209,7 @@ static int _freq_tbl_determine_rate(struct clk_hw *hw,
 	} else {
 		rate =  clk_hw_get_rate(p);
 	}
+
 	req->best_parent_hw = p;
 	req->best_parent_rate = rate;
 	req->rate = f->freq;
@@ -810,3 +811,697 @@ const struct clk_ops clk_gfx3d_ops = {
 	.determine_rate = clk_gfx3d_determine_rate,
 };
 EXPORT_SYMBOL_GPL(clk_gfx3d_ops);
+
+static int clk_cdiv_rcg2_is_enabled(struct clk_hw *hw)
+{
+	struct clk_cdiv_rcg2 *rcg = to_clk_cdiv_rcg2(hw);
+	u32 cmd = 0;
+	int ret;
+
+	ret = regmap_read(rcg->clkr.regmap, rcg->cmd_rcgr + CMD_REG, &cmd);
+	if (ret < 0)
+		return false;
+
+	return (cmd & CMD_ROOT_OFF) == 0;
+}
+
+static u8 clk_cdiv_rcg2_get_parent(struct clk_hw *hw)
+{
+	struct clk_cdiv_rcg2 *rcg = to_clk_cdiv_rcg2(hw);
+	int num_parents = clk_hw_get_num_parents(hw);
+	u32 cfg;
+	int i, ret;
+
+	ret = regmap_read(rcg->clkr.regmap, rcg->cmd_rcgr + CFG_REG, &cfg);
+	if (ret)
+		goto err;
+
+	cfg &= CFG_SRC_SEL_MASK;
+	cfg >>= CFG_SRC_SEL_SHIFT;
+
+	for (i = 0; i < num_parents; i++)
+		if (cfg == rcg->parent_map[i].cfg)
+			return i;
+err:
+	pr_debug("%s: Cannot find parent of %s clock, using default.\n",
+			__func__, __clk_get_name(hw->clk));
+	return 0;
+}
+
+static int cdiv_update_config(struct clk_cdiv_rcg2 *rcg)
+{
+	int count, ret;
+	struct clk_hw *hw = &rcg->clkr.hw;
+	const char *name = __clk_get_name(hw->clk);
+
+	ret = regmap_update_bits(rcg->clkr.regmap, rcg->cmd_rcgr + CMD_REG,
+				 CMD_UPDATE, CMD_UPDATE);
+	if (ret)
+		return ret;
+
+	/* Wait for update to take effect */
+	for (count = 500; count > 0; count--) {
+		u32 cmd = ~0U;
+
+		/* ignore regmap errors - until we exhaust retry count. */
+		ret = regmap_read(rcg->clkr.regmap, rcg->cmd_rcgr + CMD_REG,
+									&cmd);
+
+		if (ret >= 0 && !(cmd & CMD_UPDATE))
+			return 0;
+
+		udelay(1);
+	}
+
+	WARN(ret, "%s: rcg didn't update its configuration.", name);
+	return ret ? ret : -ETIMEDOUT;
+}
+
+static int clk_cdiv_rcg2_set_parent(struct clk_hw *hw, u8 index)
+{
+	struct clk_cdiv_rcg2 *rcg = to_clk_cdiv_rcg2(hw);
+	int ret;
+
+	ret = regmap_update_bits(rcg->clkr.regmap, rcg->cmd_rcgr + CFG_REG,
+				 CFG_SRC_SEL_MASK,
+				 rcg->parent_map[index].cfg <<
+				 CFG_SRC_SEL_SHIFT);
+	if (ret)
+		return ret;
+
+	return cdiv_update_config(rcg);
+}
+
+static unsigned long
+clk_cdiv_rcg2_recalc_rate(struct clk_hw *hw, unsigned long parent_rate)
+{
+	struct clk_cdiv_rcg2 *rcg = to_clk_cdiv_rcg2(hw);
+	u32 cfg, hid_div, m = 0, n = 0, mode = 0, mask, rate, cdiv;
+	int ret;
+
+	ret = regmap_read(rcg->clkr.regmap, rcg->cmd_rcgr + CFG_REG, &cfg);
+	if (ret)
+		return 0UL;
+
+	if (rcg->mnd_width) {
+		mask = BIT(rcg->mnd_width) - 1;
+		ret = regmap_read(rcg->clkr.regmap, rcg->cmd_rcgr + M_REG, &m);
+		if (ret)
+			return 0UL;
+
+		m &= mask;
+		ret = regmap_read(rcg->clkr.regmap, rcg->cmd_rcgr + N_REG, &n);
+		if (ret)
+			return 0UL;
+
+		n =  ~n;
+		n &= mask;
+
+		n += m;
+		mode = cfg & CFG_MODE_MASK;
+		mode >>= CFG_MODE_SHIFT;
+	}
+
+	mask = BIT(rcg->hid_width) - 1;
+	hid_div = cfg >> CFG_SRC_DIV_SHIFT;
+	hid_div &= mask;
+	rate = calc_rate(parent_rate, m, n, mode, hid_div);
+
+	ret = regmap_read(rcg->clkr.regmap, rcg->cdiv.offset, &cdiv);
+	if (ret)
+		return 0UL;
+
+	cdiv &= (rcg->cdiv.mask << rcg->cdiv.shift);
+	cdiv =  (cdiv >> rcg->cdiv.shift);
+	if (cdiv)
+		rate *= cdiv + 1;
+	return rate;
+}
+
+static int _cdiv_rcg2_freq_tbl_determine_rate(struct clk_hw *hw,
+		const struct freq_tbl *f,
+		struct clk_rate_request *req)
+{
+	unsigned long clk_flags;
+	struct clk_hw *p_hw;
+	unsigned long rate = req->rate;
+
+	f = qcom_find_freq(f, rate);
+	if (!f)
+		return 0L;
+
+	clk_flags = __clk_get_flags(hw->clk);
+	p_hw = clk_hw_get_parent_by_index(hw, f->src);
+	if (clk_flags & CLK_SET_RATE_PARENT) {
+		if (f->pre_div)
+			rate *= f->pre_div;
+		if (f->n) {
+			u64 tmp = rate;
+
+			tmp = tmp * f->n;
+			do_div(tmp, f->m);
+			rate = tmp;
+		}
+	} else {
+		rate =	clk_hw_get_rate(p_hw);
+	}
+
+	req->best_parent_rate = rate;
+	req->best_parent_hw = p_hw;
+	req->rate = f->freq;
+
+	return 0;
+}
+
+
+static int clk_cdiv_rcg2_determine_rate(struct clk_hw *hw,
+					struct clk_rate_request *req)
+{
+	struct clk_cdiv_rcg2 *rcg = to_clk_cdiv_rcg2(hw);
+
+	return _cdiv_rcg2_freq_tbl_determine_rate(hw, rcg->freq_tbl, req);
+}
+
+static int clk_cdiv_rcg2_configure(struct clk_cdiv_rcg2 *rcg,
+				const struct freq_tbl *f)
+{
+	u32 cfg = 0, mask;
+	u32 i;
+	int ret;
+
+	if (rcg->mnd_width && f->n) {
+		mask = BIT(rcg->mnd_width) - 1;
+		ret = regmap_update_bits(rcg->clkr.regmap,
+				rcg->cmd_rcgr + M_REG, mask, f->m);
+		if (ret)
+			return ret;
+
+		ret = regmap_update_bits(rcg->clkr.regmap,
+				rcg->cmd_rcgr + N_REG, mask, ~(f->n - f->m));
+		if (ret)
+			return ret;
+
+		ret = regmap_update_bits(rcg->clkr.regmap,
+				rcg->cmd_rcgr + D_REG, mask, ~f->n);
+		if (ret)
+			return ret;
+	}
+
+
+	if (rcg->cdiv.mask && f->pre_div > 16) {
+
+		/* The division is handled by two dividers. Both of which can
+		 * divide by a maximum value of 16. To achieve a division of
+		 * 256 = 16 * 16, we use a divider of 16 in the RCGR and the
+		 * other divider of 16 in the MISC Register.
+		 */
+		for (i = 2; i <= 16; i++) {
+			if (f->pre_div % i == 0)
+				cfg = i;
+		}
+
+		if (f->pre_div/cfg > 16)
+			return -EINVAL;
+		mask = (rcg->cdiv.mask)<<rcg->cdiv.shift;
+		ret = regmap_update_bits(rcg->clkr.regmap,
+					rcg->cdiv.offset, mask,
+				((cfg - 1) << rcg->cdiv.shift) & mask);
+		if (ret)
+			return ret;
+		cfg = (2 * (f->pre_div / cfg)) - 1;
+	} else {
+		ret = regmap_write(rcg->clkr.regmap, rcg->cdiv.offset, 0x0);
+		if (ret)
+			return ret;
+		cfg = ((2 * f->pre_div) - 1) << CFG_SRC_DIV_SHIFT;
+	}
+
+	mask = BIT(rcg->hid_width) - 1;
+	mask |= CFG_SRC_SEL_MASK | CFG_MODE_MASK;
+	cfg |= rcg->parent_map[f->src].cfg << CFG_SRC_SEL_SHIFT;
+	if (rcg->mnd_width && f->n)
+		cfg |= CFG_MODE_DUAL_EDGE;
+	ret = regmap_update_bits(rcg->clkr.regmap,
+			rcg->cmd_rcgr + CFG_REG, mask, cfg);
+	if (ret)
+		return ret;
+
+	return cdiv_update_config(rcg);
+}
+
+static int __clk_cdiv_rcg2_set_rate(struct clk_hw *hw, unsigned long rate)
+{
+	struct clk_cdiv_rcg2 *rcg = to_clk_cdiv_rcg2(hw);
+	const struct freq_tbl *f;
+
+	f = qcom_find_freq(rcg->freq_tbl, rate);
+	if (!f)
+		return -EINVAL;
+
+	return clk_cdiv_rcg2_configure(rcg, f);
+}
+
+static int clk_cdiv_rcg2_set_rate(struct clk_hw *hw, unsigned long rate,
+			    unsigned long parent_rate)
+{
+	return __clk_cdiv_rcg2_set_rate(hw, rate);
+}
+
+static int clk_cdiv_rcg2_set_rate_and_parent(struct clk_hw *hw,
+		unsigned long rate, unsigned long parent_rate, u8 index)
+{
+	return __clk_cdiv_rcg2_set_rate(hw, rate);
+}
+
+const struct clk_ops clk_cdiv_rcg2_ops = {
+	.is_enabled			= clk_cdiv_rcg2_is_enabled,
+	.get_parent			= clk_cdiv_rcg2_get_parent,
+	.set_parent			= clk_cdiv_rcg2_set_parent,
+	.recalc_rate			= clk_cdiv_rcg2_recalc_rate,
+	.determine_rate			= clk_cdiv_rcg2_determine_rate,
+	.set_rate			= clk_cdiv_rcg2_set_rate,
+	.set_rate_and_parent		= clk_cdiv_rcg2_set_rate_and_parent,
+};
+EXPORT_SYMBOL_GPL(clk_cdiv_rcg2_ops);
+
+static int clk_muxr_is_enabled(struct clk_hw *hw)
+{
+	return 0;
+}
+
+static u8 clk_muxr_get_parent(struct clk_hw *hw)
+{
+	struct clk_muxr_misc *rcg = to_clk_muxr_misc(hw);
+	int num_parents = clk_hw_get_num_parents(hw);
+	u32 cfg;
+	int i, ret;
+
+	ret = regmap_read(rcg->clkr.regmap, rcg->muxr.offset, &cfg);
+	if (ret)
+		goto err;
+
+	cfg >>= rcg->muxr.shift;
+	cfg &= rcg->muxr.mask;
+
+	for (i = 0; i < num_parents; i++)
+		if (cfg == rcg->parent_map[i].cfg)
+			return i;
+
+err:
+	pr_debug("%s: Cannot find parent of %s clock, using default.\n",
+			__func__, __clk_get_name(hw->clk));
+	return 0;
+}
+
+static int clk_muxr_set_parent(struct clk_hw *hw, u8 index)
+{
+	struct clk_muxr_misc *rcg = to_clk_muxr_misc(hw);
+	int ret;
+
+	ret = regmap_update_bits(rcg->clkr.regmap, rcg->muxr.offset,
+				 (rcg->muxr.mask<<rcg->muxr.shift),
+				 rcg->parent_map[index].cfg << rcg->muxr.shift);
+	if (ret)
+		return ret;
+
+	return 0;
+}
+
+static unsigned long
+clk_muxr_recalc_rate(struct clk_hw *hw, unsigned long parent_rate)
+{
+	struct clk_muxr_misc *rcg = to_clk_muxr_misc(hw);
+	u32 misc;
+	int ret;
+
+	ret = regmap_read(rcg->clkr.regmap, rcg->misc.offset, &misc);
+	if (ret)
+		return 0UL;
+
+	misc &= rcg->misc.mask;
+	misc >>= rcg->misc.shift;
+
+	return parent_rate * (misc + 1);
+}
+
+static int clk_muxr_determine_rate(struct clk_hw *hw,
+				   struct clk_rate_request *req)
+{
+	struct clk_muxr_misc *rcg = to_clk_muxr_misc(hw);
+	const struct freq_tbl *f;
+	unsigned long clk_flags;
+	unsigned long rate = req->rate;
+	struct clk_hw *p_hw;
+
+	f = qcom_find_freq(rcg->freq_tbl, rate);
+	if (!f)
+		return 0L;
+
+	clk_flags = __clk_get_flags(hw->clk);
+	p_hw = clk_hw_get_parent_by_index(hw, f->src);
+	if (clk_flags & CLK_SET_RATE_PARENT) {
+		if (f->pre_div)
+			rate *= f->pre_div;
+	} else {
+		rate =	clk_hw_get_rate(p_hw);
+	}
+
+	req->best_parent_rate = rate;
+	req->best_parent_hw = p_hw;
+	req->rate = f->freq;
+
+	return 0;
+}
+
+static int __clk_muxr_set_rate(struct clk_hw *hw, unsigned long rate)
+{
+	struct clk_muxr_misc *rcg = to_clk_muxr_misc(hw);
+	const struct freq_tbl *f;
+	int ret;
+
+	f = qcom_find_freq(rcg->freq_tbl, rate);
+	if (!f)
+		return -EINVAL;
+
+	ret = regmap_update_bits(rcg->clkr.regmap, rcg->muxr.offset,
+				rcg->muxr.mask << rcg->muxr.shift,
+				rcg->parent_map[f->src].cfg << rcg->muxr.shift);
+	if (ret)
+		return ret;
+
+	ret = regmap_update_bits(rcg->clkr.regmap, rcg->misc.offset,
+				rcg->misc.mask << rcg->misc.shift,
+				(f->pre_div - 1) << rcg->misc.shift);
+	return ret;
+}
+
+static int clk_muxr_set_rate(struct clk_hw *hw, unsigned long rate,
+			    unsigned long parent_rate)
+{
+	return __clk_muxr_set_rate(hw, rate);
+}
+
+static int clk_muxr_set_rate_and_parent(struct clk_hw *hw,
+		unsigned long rate, unsigned long parent_rate, u8 index)
+{
+	return __clk_muxr_set_rate(hw, rate);
+}
+
+const struct clk_ops clk_muxr_misc_ops = {
+	.is_enabled	=	clk_muxr_is_enabled,
+	.get_parent	=	clk_muxr_get_parent,
+	.set_parent	=	clk_muxr_set_parent,
+	.recalc_rate	=	clk_muxr_recalc_rate,
+	.determine_rate	=	clk_muxr_determine_rate,
+	.set_rate	=	clk_muxr_set_rate,
+	.set_rate_and_parent	=	clk_muxr_set_rate_and_parent,
+};
+EXPORT_SYMBOL_GPL(clk_muxr_misc_ops);
+
+static int clk_cpu_rcg2_is_enabled(struct clk_hw *hw)
+{
+	struct clk_cdiv_rcg2 *rcg = to_clk_cdiv_rcg2(hw);
+	u32 cmd;
+	int ret;
+
+	ret = regmap_read(rcg->clkr.regmap, rcg->cmd_rcgr + CMD_REG, &cmd);
+	if (ret)
+		return 0;
+
+	return (cmd & CMD_ROOT_OFF) == 0;
+
+}
+
+static u8 clk_cpu_rcg2_get_parent(struct clk_hw *hw)
+{
+	struct clk_cdiv_rcg2 *rcg = to_clk_cdiv_rcg2(hw);
+	int num_parents = clk_hw_get_num_parents(hw);
+	u32 cfg;
+	int i, ret;
+
+	ret = regmap_read(rcg->clkr.regmap, rcg->cmd_rcgr + CFG_REG, &cfg);
+	if (ret)
+		goto err;
+
+	cfg &= CFG_SRC_SEL_MASK;
+	cfg >>= CFG_SRC_SEL_SHIFT;
+
+	for (i = 0; i < num_parents; i++)
+		if (cfg == rcg->parent_map[i].cfg)
+			return i;
+
+err:
+	pr_debug("%s: Cannot find parent of %s clock, using default.\n",
+			__func__, __clk_get_name(hw->clk));
+	return 0;
+}
+
+static int cpu_rcg2_update_config(struct clk_cdiv_rcg2 *rcg)
+{
+	int count, ret;
+	u32 cmd;
+	struct clk_hw *hw = &rcg->clkr.hw;
+	const char *name = __clk_get_name(hw->clk);
+
+	ret = regmap_update_bits(rcg->clkr.regmap, rcg->cmd_rcgr + CMD_REG,
+				 CMD_UPDATE, CMD_UPDATE);
+	if (ret)
+		return ret;
+
+	/* Wait for update to take effect */
+	for (count = 500; count > 0; count--) {
+		/* ignore regmap errors until we exhaust retry count.*/
+		ret = regmap_read(rcg->clkr.regmap, rcg->cmd_rcgr + CMD_REG,
+									&cmd);
+		if (ret >= 0 && !(cmd & CMD_UPDATE))
+			return 0;
+
+		udelay(1);
+	}
+
+	WARN(1, "%s: rcg didn't update its configuration.", name);
+	return ret ? ret : -ETIMEDOUT;
+}
+
+static int clk_cpu_rcg2_set_parent(struct clk_hw *hw, u8 index)
+{
+	struct clk_cdiv_rcg2 *rcg = to_clk_cdiv_rcg2(hw);
+	int ret;
+
+	ret = regmap_update_bits(rcg->clkr.regmap, rcg->cmd_rcgr + CFG_REG,
+				 CFG_SRC_SEL_MASK,
+				 rcg->parent_map[index].cfg <<
+				 CFG_SRC_SEL_SHIFT);
+	if (ret)
+		return ret;
+
+	return cpu_rcg2_update_config(rcg);
+}
+
+
+/*
+ * These are used for looking up the actual divider ratios
+ * the divider used for DDR PLL Post divider is not linear,
+ * hence we need this look up table
+ */
+static const unsigned char ddrpll_div[] = {
+		12,
+		13,
+		14,
+		15,
+		16,
+		17,
+		18,
+		19,
+		20,
+		21,
+		22,
+		24,
+		26,
+		28
+};
+
+static unsigned long
+clk_cpu_rcg2_recalc_rate(struct clk_hw *hw, unsigned long parent_rate)
+{
+	struct clk_cdiv_rcg2 *rcg = to_clk_cdiv_rcg2(hw);
+	u32 cfg, hid_div, m = 0, n = 0, mode = 0, mask, cdiv;
+	unsigned long rate;
+	u32 src;
+	int ret;
+
+	ret = regmap_read(rcg->clkr.regmap, rcg->cmd_rcgr + CFG_REG, &cfg);
+	if (ret)
+		return 0UL;
+
+	if (rcg->mnd_width) {
+		mask = BIT(rcg->mnd_width) - 1;
+		ret = regmap_read(rcg->clkr.regmap, rcg->cmd_rcgr + M_REG, &m);
+		if (ret)
+			return 0UL;
+
+		m &= mask;
+
+		ret = regmap_read(rcg->clkr.regmap, rcg->cmd_rcgr + N_REG, &n);
+		if (ret)
+			return 0UL;
+
+		n =  ~n;
+		n &= mask;
+
+		n += m;
+		mode = cfg & CFG_MODE_MASK;
+		mode >>= CFG_MODE_SHIFT;
+	}
+
+	mask = BIT(rcg->hid_width) - 1;
+	hid_div = cfg >> CFG_SRC_DIV_SHIFT;
+	hid_div &= mask;
+	rate = calc_rate(parent_rate, m, n, mode, hid_div);
+	src = (cfg >> CFG_SRC_SEL_SHIFT) & 0xf;
+	if (src == 0x1) {
+		u64 tmp;
+
+		ret = regmap_read(rcg->clkr.regmap, rcg->cdiv.offset, &cdiv);
+		if (ret)
+			return 0UL;
+
+		cdiv &= (rcg->cdiv.mask << rcg->cdiv.shift);
+		cdiv = cdiv >> rcg->cdiv.shift;
+		tmp = rate;
+		do_div(tmp, ddrpll_div[cdiv]);
+		rate = tmp;
+		rate *= 16;
+		tmp = rate;
+		do_div(tmp, 1000000);
+		rate = tmp;
+		rate = rate * 1000000;
+	}
+	return rate;
+}
+
+static int _cpu_rcg2_freq_tbl_determine_rate(struct clk_hw *hw,
+		const struct freq_tbl *f,
+		struct clk_rate_request *req)
+{
+	unsigned long clk_flags;
+	struct clk_hw *p_hw;
+	unsigned long rate;
+
+	f = qcom_find_freq(f, req->rate);
+	if (!f)
+		return 0L;
+
+	clk_flags = __clk_get_flags(hw->clk);
+	p_hw = clk_hw_get_parent_by_index(hw, f->src);
+	rate = clk_hw_get_rate(p_hw);
+
+	req->best_parent_rate = rate;
+	req->best_parent_hw = p_hw;
+	req->rate = f->freq;
+
+	return 0;
+}
+
+static int clk_cpu_rcg2_determine_rate(struct clk_hw *hw,
+					struct clk_rate_request *req)
+{
+	struct clk_cdiv_rcg2 *rcg = to_clk_cdiv_rcg2(hw);
+
+	return _cpu_rcg2_freq_tbl_determine_rate(hw, rcg->freq_tbl, req);
+}
+
+
+static int clk_cpu_rcg2_configure(struct clk_cdiv_rcg2 *rcg,
+						const struct freq_tbl *f)
+{
+	u32 cfg, mask;
+	int ret;
+
+	if (rcg->mnd_width && f->n) {
+		mask = BIT(rcg->mnd_width) - 1;
+		ret = regmap_update_bits(rcg->clkr.regmap,
+				rcg->cmd_rcgr + M_REG, mask, f->m);
+		if (ret)
+			return ret;
+
+		ret = regmap_update_bits(rcg->clkr.regmap,
+				rcg->cmd_rcgr + N_REG, mask, ~(f->n - f->m));
+		if (ret)
+			return ret;
+
+		ret = regmap_update_bits(rcg->clkr.regmap,
+				rcg->cmd_rcgr + D_REG, mask, ~f->n);
+		if (ret)
+			return ret;
+	}
+
+	if ((rcg->parent_map[f->src].cfg == 0x01)) {
+		mask = (BIT(rcg->hid_width) - 1);
+		mask |= CFG_SRC_SEL_MASK | CFG_MODE_MASK;
+		cfg = FEPLL_500_SRC << CFG_SRC_SEL_SHIFT;
+		cfg |= (1 << CFG_SRC_DIV_SHIFT);
+		ret = regmap_update_bits(rcg->clkr.regmap,
+					rcg->cmd_rcgr + CFG_REG, mask, cfg);
+		if (ret)
+			return ret;
+		cpu_rcg2_update_config(rcg);
+		mask = (rcg->cdiv.mask)<<rcg->cdiv.shift;
+		ret = regmap_update_bits(rcg->clkr.regmap,
+					rcg->cdiv.offset, mask,
+				(f->pre_div << rcg->cdiv.shift) & mask);
+		udelay(1);
+		mask = BIT(rcg->hid_width) - 1;
+		mask |= CFG_SRC_SEL_MASK | CFG_MODE_MASK;
+		cfg = 1 << CFG_SRC_DIV_SHIFT;
+	} else {
+		mask = BIT(rcg->hid_width) - 1;
+		mask |= CFG_SRC_SEL_MASK | CFG_MODE_MASK;
+		cfg = f->pre_div << CFG_SRC_DIV_SHIFT;
+	}
+
+	cfg |= rcg->parent_map[f->src].cfg << CFG_SRC_SEL_SHIFT;
+	if (rcg->mnd_width && f->n)
+		cfg |= CFG_MODE_DUAL_EDGE;
+	ret = regmap_update_bits(rcg->clkr.regmap,
+					rcg->cmd_rcgr + CFG_REG, mask, cfg);
+	if (ret)
+		return ret;
+
+	return cpu_rcg2_update_config(rcg);
+}
+
+static int __clk_cpu_rcg2_set_rate(struct clk_hw *hw, unsigned long rate)
+{
+	struct clk_cdiv_rcg2 *rcg = to_clk_cdiv_rcg2(hw);
+	const struct freq_tbl *f;
+
+	f = qcom_find_freq(rcg->freq_tbl, rate);
+	if (!f)
+		return -EINVAL;
+
+	return clk_cpu_rcg2_configure(rcg, f);
+}
+
+static int clk_cpu_rcg2_set_rate(struct clk_hw *hw, unsigned long rate,
+			    unsigned long parent_rate)
+{
+	return __clk_cpu_rcg2_set_rate(hw, rate);
+}
+
+static int clk_cpu_rcg2_set_rate_and_parent(struct clk_hw *hw,
+		unsigned long rate, unsigned long parent_rate, u8 index)
+{
+	return __clk_cpu_rcg2_set_rate(hw, rate);
+}
+
+const struct clk_ops clk_cpu_rcg2_ops = {
+	.is_enabled	=	clk_cpu_rcg2_is_enabled,
+	.get_parent	=	clk_cpu_rcg2_get_parent,
+	.set_parent	=	clk_cpu_rcg2_set_parent,
+	.recalc_rate	=	clk_cpu_rcg2_recalc_rate,
+	.determine_rate	=	clk_cpu_rcg2_determine_rate,
+	.set_rate	=	clk_cpu_rcg2_set_rate,
+	.set_rate_and_parent	=	clk_cpu_rcg2_set_rate_and_parent,
+};
+EXPORT_SYMBOL_GPL(clk_cpu_rcg2_ops);
diff --git a/drivers/clk/qcom/common.c b/drivers/clk/qcom/common.c
index f7c226a..0851122 100644
--- a/drivers/clk/qcom/common.c
+++ b/drivers/clk/qcom/common.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013-2014, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2013-2016, The Linux Foundation. All rights reserved.
  *
  * This software is licensed under the terms of the GNU General Public
  * License version 2, as published by the Free Software Foundation, and
@@ -269,4 +269,11 @@ int qcom_cc_probe(struct platform_device *pdev, const struct qcom_cc_desc *desc)
 }
 EXPORT_SYMBOL_GPL(qcom_cc_probe);
 
+void qcom_cc_remove(struct platform_device *pdev)
+{
+	of_clk_del_provider(pdev->dev.of_node);
+	reset_controller_unregister(platform_get_drvdata(pdev));
+}
+EXPORT_SYMBOL_GPL(qcom_cc_remove);
+
 MODULE_LICENSE("GPL v2");
diff --git a/drivers/clk/qcom/common.h b/drivers/clk/qcom/common.h
index ae9bdeb..ad66ae2 100644
--- a/drivers/clk/qcom/common.h
+++ b/drivers/clk/qcom/common.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2014-2016 The Linux Foundation. All rights reserved.
  *
  * This software is licensed under the terms of the GNU General Public
  * License version 2, as published by the Free Software Foundation, and
@@ -48,5 +48,6 @@ extern int qcom_cc_really_probe(struct platform_device *pdev,
 				struct regmap *regmap);
 extern int qcom_cc_probe(struct platform_device *pdev,
 			 const struct qcom_cc_desc *desc);
+extern void qcom_cc_remove(struct platform_device *pdev);
 
 #endif
diff --git a/include/dt-bindings/clock/qca,adcc-ipq4019.h b/include/dt-bindings/clock/qca,adcc-ipq4019.h
new file mode 100644
index 0000000..9bd5f35
--- /dev/null
+++ b/include/dt-bindings/clock/qca,adcc-ipq4019.h
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 2015-2016, The Linux Foundation. All rights reserved.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ */
+#ifndef _DT_BINDINGS_CLK_IPQ_ADCC_4019_H
+#define _DT_BINDINGS_CLK_IPQ_ADCC_4019_H
+
+#define ADSS_PLL_SRC				1
+#define RXM_CLK_SRC				2
+#define ADCC_RXM_CLK_SRC			3
+#define TXM_CLK_SRC				4
+#define ADCC_TXM_CLK_SRC			5
+#define TXB_CLK_SRC				6
+#define ADCC_TXB_CLK_SRC			7
+#define RXB_CLK_SRC				8
+#define ADCC_RXB_CLK_SRC			9
+#define PCM_CLK_SRC				10
+#define ADCC_PCM_CLK_SRC			11
+#define AUDIO_SPDIFINFAST_SRC			12
+#define ADCC_AUDIO_SPDIFINFAST_SRC		13
+#define ADCC_AUDIO_AHB_SRC			14
+#define ADCC_AHB_I2S0				15
+#define ADCC_AHB_I2S3				16
+#define ADCC_AHB_MBOX0_SRC			17
+#define ADCC_AHB_MBOX3_SRC			18
+#define SPDIF_SRC				19
+#define ADCC_SPDIF_SRC				20
+#define SPDIFDIV2_SRC				21
+#define ADCC_SPDIFDIV2_SRC			22
+#define ADCC_SAMPLE_SRC				23
+#define ADCC_XO_SRC				24
+
+#endif
diff --git a/include/dt-bindings/clock/qcom,gcc-ipq4019.h b/include/dt-bindings/clock/qcom,gcc-ipq4019.h
index 6240e5b..c75b98a 100644
--- a/include/dt-bindings/clock/qcom,gcc-ipq4019.h
+++ b/include/dt-bindings/clock/qcom,gcc-ipq4019.h
@@ -1,4 +1,5 @@
-/* Copyright (c) 2015 The Linux Foundation. All rights reserved.
+/*
+ * Copyright (c) 2015-2016 The Linux Foundation. All rights reserved.
  *
  * Permission to use, copy, modify, and/or distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
@@ -154,5 +155,6 @@
 #define GCC_QDSS_BCR					69
 #define GCC_MPM_BCR					70
 #define GCC_SPDM_BCR					71
+#define AUDIO_BLK_ARES					GCC_AUDIO_BCR
 
 #endif
diff --git a/include/dt-bindings/sound/ipq4019-audio.h b/include/dt-bindings/sound/ipq4019-audio.h
new file mode 100644
index 0000000..7bf8036
--- /dev/null
+++ b/include/dt-bindings/sound/ipq4019-audio.h
@@ -0,0 +1,37 @@
+/*
+ * Copyright (c) 2015-2016, The Linux Foundation. All rights reserved.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ */
+
+#ifndef __DT_BINDINGS_QCOM_GSBI_H
+#define __DT_BINDINGS_QCOM_GSBI_H
+
+#define MBOX0_TX_ID		0
+#define MBOX0_RX_ID		1
+#define MBOX1_TX_ID		2
+#define MBOX1_RX_ID		3
+#define MBOX2_TX_ID		4
+#define MBOX2_RX_ID		5
+#define MBOX3_TX_ID		6
+#define MBOX3_RX_ID		7
+#define MBOX_SPDIF_TX_ID	8
+#define MBOX_SPDIF_RX_ID	9
+
+#define STEREO0_ID		0
+#define STEREO1_ID		1
+#define STEREO2_ID		2
+#define STEREO3_ID		3
+
+#endif
-- 
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
a Linux Foundation Collaborative Project

^ permalink raw reply related	[flat|nested] 24+ messages in thread

* [PATCH 3/4] qcom: ipq4019: ASoC tlmm/pinctrl support
  2016-07-15  7:07 ` njaigane
@ 2016-07-15  7:07   ` njaigane at codeaurora.org
  -1 siblings, 0 replies; 24+ messages in thread
From: njaigane @ 2016-07-15  7:07 UTC (permalink / raw)
  To: linux-arm-msm
  Cc: linux, devicetree, linux-kernel, linux-soc, linux-arm-kernel,
	twp, andy.gross, david.brown, robh+dt, pawel.moll, mark.rutland,
	ijc+devicetree, galak, linux, mturquette, sboyd, linus.walleij,
	plai, bgoswami, lgirdwood, broonie, perex, tiwai,
	bjorn.andersson, varada, pradeepb, snlakshm, linux-clk,
	linux-gpio, alsa-devel, bselvara, Jaiganesh Narayanan

From: Jaiganesh Narayanan <njaigane@codeaurora.org>

This patch adds the tlmm/pinctrl support for IPQ4019 ASoC.

Signed-off-by: Jaiganesh Narayanan <njaigane@codeaurora.org>
---
 drivers/pinctrl/qcom/pinctrl-ipq4019.c | 116 +++++++++++++++++++++++++--------
 1 file changed, 88 insertions(+), 28 deletions(-)

diff --git a/drivers/pinctrl/qcom/pinctrl-ipq4019.c b/drivers/pinctrl/qcom/pinctrl-ipq4019.c
index b68ae42..bc22597 100644
--- a/drivers/pinctrl/qcom/pinctrl-ipq4019.c
+++ b/drivers/pinctrl/qcom/pinctrl-ipq4019.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2015-2016, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -283,6 +283,18 @@ enum ipq4019_functions {
 	qca_mux_blsp_uart0,
 	qca_mux_blsp_spi1,
 	qca_mux_blsp_spi0,
+	qca_mux_i2s_rx_mclk,
+	qca_mux_i2s_rx_bclk,
+	qca_mux_i2s_rx_fsync,
+	qca_mux_i2s_rxd,
+	qca_mux_i2s_tx_mclk,
+	qca_mux_i2s_tx_bclk,
+	qca_mux_i2s_tx_fsync,
+	qca_mux_i2s_txd1,
+	qca_mux_i2s_txd2,
+	qca_mux_i2s_txd3,
+	qca_mux_i2s_spdif_out,
+	qca_mux_i2s_spdif_in,
 	qca_mux_NA,
 };
 
@@ -304,6 +316,42 @@ static const char * const gpio_groups[] = {
 	"gpio99",
 };
 
+static const char * const i2s_rx_bclk_groups[] = {
+	"gpio0", "gpio21", "gpio60",
+};
+static const char * const i2s_rx_mclk_groups[] = {
+	"gpio20", "gpio58",
+};
+static const char * const i2s_rx_fsync_groups[] = {
+	"gpio1", "gpio22", "gpio61",
+};
+static const char * const i2s_rxd_groups[] = {
+	"gpio2", "gpio23", "gpio63",
+};
+static const char * const i2s_tx_bclk_groups[] = {
+	"gpio25", "gpio53", "gpio60",
+};
+static const char * const i2s_tx_mclk_groups[] = {
+	"gpio24", "gpio52",
+};
+static const char * const i2s_tx_fsync_groups[] = {
+	"gpio26", "gpio57", "gpio61",
+};
+static const char * const i2s_txd1_groups[] = {
+	"gpio27", "gpio54", "gpio63",
+};
+static const char * const i2s_txd2_groups[] = {
+	"gpio28", "gpio55",
+};
+static const char * const i2s_txd3_groups[] = {
+	"gpio29", "gpio56",
+};
+static const char * const i2s_spdif_out_groups[] = {
+	"gpio35", "gpio62", "gpio63",
+};
+static const char * const i2s_spdif_in_groups[] = {
+	"gpio34", "gpio59", "gpio63",
+};
 static const char * const blsp_uart1_groups[] = {
 	"gpio8", "gpio9", "gpio10", "gpio11",
 };
@@ -332,12 +380,24 @@ static const struct msm_function ipq4019_functions[] = {
 	FUNCTION(blsp_uart0),
 	FUNCTION(blsp_spi1),
 	FUNCTION(blsp_spi0),
+	FUNCTION(i2s_rx_mclk),
+	FUNCTION(i2s_rx_bclk),
+	FUNCTION(i2s_rx_fsync),
+	FUNCTION(i2s_rxd),
+	FUNCTION(i2s_tx_mclk),
+	FUNCTION(i2s_tx_bclk),
+	FUNCTION(i2s_tx_fsync),
+	FUNCTION(i2s_txd1),
+	FUNCTION(i2s_txd2),
+	FUNCTION(i2s_txd3),
+	FUNCTION(i2s_spdif_out),
+	FUNCTION(i2s_spdif_in),
 };
 
 static const struct msm_pingroup ipq4019_groups[] = {
-	PINGROUP(0, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA),
-	PINGROUP(1, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA),
-	PINGROUP(2, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+	PINGROUP(0, NA, NA, i2s_rx_bclk, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+	PINGROUP(1, NA, NA, i2s_rx_fsync, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+	PINGROUP(2, NA, NA, i2s_rxd, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA),
 	PINGROUP(3, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA),
 	PINGROUP(4, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA),
 	PINGROUP(5, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA),
@@ -355,22 +415,22 @@ static const struct msm_pingroup ipq4019_groups[] = {
 	PINGROUP(17, blsp_uart0, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA),
 	PINGROUP(18, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA),
 	PINGROUP(19, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA),
-	PINGROUP(20, blsp_i2c0, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA),
-	PINGROUP(21, blsp_i2c0, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA),
-	PINGROUP(22, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA),
-	PINGROUP(23, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA),
-	PINGROUP(24, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA),
-	PINGROUP(25, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA),
-	PINGROUP(26, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA),
-	PINGROUP(27, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA),
-	PINGROUP(28, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA),
-	PINGROUP(29, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+	PINGROUP(20, blsp_i2c0, i2s_rx_mclk, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+	PINGROUP(21, blsp_i2c0, i2s_rx_bclk, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+	PINGROUP(22, NA, i2s_rx_fsync, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+	PINGROUP(23, NA, NA, i2s_rxd, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+	PINGROUP(24, NA, NA, i2s_tx_mclk, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+	PINGROUP(25, NA, NA, i2s_tx_bclk, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+	PINGROUP(26, NA, NA, i2s_tx_fsync, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+	PINGROUP(27, NA, NA, i2s_txd1, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+	PINGROUP(28, NA, NA, i2s_txd2, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+	PINGROUP(29, NA, NA, i2s_txd3, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA),
 	PINGROUP(30, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA),
 	PINGROUP(31, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA),
 	PINGROUP(32, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA),
 	PINGROUP(33, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA),
-	PINGROUP(34, blsp_i2c1, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA),
-	PINGROUP(35, blsp_i2c1, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+	PINGROUP(34, blsp_i2c1, i2s_spdif_in, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+	PINGROUP(35, blsp_i2c1, i2s_spdif_out, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA),
 	PINGROUP(36, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA),
 	PINGROUP(37, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA),
 	PINGROUP(38, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA),
@@ -387,18 +447,18 @@ static const struct msm_pingroup ipq4019_groups[] = {
 	PINGROUP(49, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA),
 	PINGROUP(50, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA),
 	PINGROUP(51, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA),
-	PINGROUP(52, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA),
-	PINGROUP(53, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA),
-	PINGROUP(54, NA, blsp_spi0, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA),
-	PINGROUP(55, NA, blsp_spi0, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA),
-	PINGROUP(56, NA, blsp_spi0, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA),
-	PINGROUP(57, NA, blsp_spi0, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA),
-	PINGROUP(58, NA, NA, blsp_i2c0, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA),
-	PINGROUP(59, NA, blsp_i2c0, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA),
-	PINGROUP(60, NA, blsp_uart0, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA),
-	PINGROUP(61, NA, blsp_uart0, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA),
-	PINGROUP(62, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA),
-	PINGROUP(63, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+	PINGROUP(52, NA, NA, NA, i2s_tx_mclk, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+	PINGROUP(53, NA, NA, i2s_tx_bclk, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+	PINGROUP(54, NA, blsp_spi0, i2s_txd1, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+	PINGROUP(55, NA, blsp_spi0, i2s_txd2, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+	PINGROUP(56, NA, blsp_spi0, i2s_txd3, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+	PINGROUP(57, NA, blsp_spi0, i2s_tx_fsync, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+	PINGROUP(58, NA, NA, blsp_i2c0, NA, NA, i2s_rx_mclk, NA, NA, NA, NA, NA, NA, NA, NA),
+	PINGROUP(59, NA, blsp_i2c0, NA, NA, i2s_spdif_in, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+	PINGROUP(60, NA, blsp_uart0, NA, NA, NA, i2s_tx_bclk, i2s_rx_bclk, NA, NA, NA, NA, NA, NA, NA),
+	PINGROUP(61, NA, blsp_uart0, NA, NA, NA, i2s_tx_fsync, i2s_rx_fsync, NA, NA, NA, NA, NA, NA, NA),
+	PINGROUP(62, NA, NA, NA, NA, i2s_spdif_out, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+	PINGROUP(63, NA, NA, NA, NA, i2s_txd1, i2s_rxd, i2s_spdif_out, i2s_spdif_in, NA, NA, NA, NA, NA, NA),
 	PINGROUP(64, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA),
 	PINGROUP(65, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA),
 	PINGROUP(66, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA),
-- 
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
a Linux Foundation Collaborative Project

^ permalink raw reply related	[flat|nested] 24+ messages in thread

* [PATCH 3/4] qcom: ipq4019: ASoC tlmm/pinctrl support
@ 2016-07-15  7:07   ` njaigane at codeaurora.org
  0 siblings, 0 replies; 24+ messages in thread
From: njaigane at codeaurora.org @ 2016-07-15  7:07 UTC (permalink / raw)
  To: linux-arm-kernel

From: Jaiganesh Narayanan <njaigane@codeaurora.org>

This patch adds the tlmm/pinctrl support for IPQ4019 ASoC.

Signed-off-by: Jaiganesh Narayanan <njaigane@codeaurora.org>
---
 drivers/pinctrl/qcom/pinctrl-ipq4019.c | 116 +++++++++++++++++++++++++--------
 1 file changed, 88 insertions(+), 28 deletions(-)

diff --git a/drivers/pinctrl/qcom/pinctrl-ipq4019.c b/drivers/pinctrl/qcom/pinctrl-ipq4019.c
index b68ae42..bc22597 100644
--- a/drivers/pinctrl/qcom/pinctrl-ipq4019.c
+++ b/drivers/pinctrl/qcom/pinctrl-ipq4019.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2015-2016, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -283,6 +283,18 @@ enum ipq4019_functions {
 	qca_mux_blsp_uart0,
 	qca_mux_blsp_spi1,
 	qca_mux_blsp_spi0,
+	qca_mux_i2s_rx_mclk,
+	qca_mux_i2s_rx_bclk,
+	qca_mux_i2s_rx_fsync,
+	qca_mux_i2s_rxd,
+	qca_mux_i2s_tx_mclk,
+	qca_mux_i2s_tx_bclk,
+	qca_mux_i2s_tx_fsync,
+	qca_mux_i2s_txd1,
+	qca_mux_i2s_txd2,
+	qca_mux_i2s_txd3,
+	qca_mux_i2s_spdif_out,
+	qca_mux_i2s_spdif_in,
 	qca_mux_NA,
 };
 
@@ -304,6 +316,42 @@ static const char * const gpio_groups[] = {
 	"gpio99",
 };
 
+static const char * const i2s_rx_bclk_groups[] = {
+	"gpio0", "gpio21", "gpio60",
+};
+static const char * const i2s_rx_mclk_groups[] = {
+	"gpio20", "gpio58",
+};
+static const char * const i2s_rx_fsync_groups[] = {
+	"gpio1", "gpio22", "gpio61",
+};
+static const char * const i2s_rxd_groups[] = {
+	"gpio2", "gpio23", "gpio63",
+};
+static const char * const i2s_tx_bclk_groups[] = {
+	"gpio25", "gpio53", "gpio60",
+};
+static const char * const i2s_tx_mclk_groups[] = {
+	"gpio24", "gpio52",
+};
+static const char * const i2s_tx_fsync_groups[] = {
+	"gpio26", "gpio57", "gpio61",
+};
+static const char * const i2s_txd1_groups[] = {
+	"gpio27", "gpio54", "gpio63",
+};
+static const char * const i2s_txd2_groups[] = {
+	"gpio28", "gpio55",
+};
+static const char * const i2s_txd3_groups[] = {
+	"gpio29", "gpio56",
+};
+static const char * const i2s_spdif_out_groups[] = {
+	"gpio35", "gpio62", "gpio63",
+};
+static const char * const i2s_spdif_in_groups[] = {
+	"gpio34", "gpio59", "gpio63",
+};
 static const char * const blsp_uart1_groups[] = {
 	"gpio8", "gpio9", "gpio10", "gpio11",
 };
@@ -332,12 +380,24 @@ static const struct msm_function ipq4019_functions[] = {
 	FUNCTION(blsp_uart0),
 	FUNCTION(blsp_spi1),
 	FUNCTION(blsp_spi0),
+	FUNCTION(i2s_rx_mclk),
+	FUNCTION(i2s_rx_bclk),
+	FUNCTION(i2s_rx_fsync),
+	FUNCTION(i2s_rxd),
+	FUNCTION(i2s_tx_mclk),
+	FUNCTION(i2s_tx_bclk),
+	FUNCTION(i2s_tx_fsync),
+	FUNCTION(i2s_txd1),
+	FUNCTION(i2s_txd2),
+	FUNCTION(i2s_txd3),
+	FUNCTION(i2s_spdif_out),
+	FUNCTION(i2s_spdif_in),
 };
 
 static const struct msm_pingroup ipq4019_groups[] = {
-	PINGROUP(0, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA),
-	PINGROUP(1, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA),
-	PINGROUP(2, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+	PINGROUP(0, NA, NA, i2s_rx_bclk, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+	PINGROUP(1, NA, NA, i2s_rx_fsync, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+	PINGROUP(2, NA, NA, i2s_rxd, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA),
 	PINGROUP(3, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA),
 	PINGROUP(4, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA),
 	PINGROUP(5, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA),
@@ -355,22 +415,22 @@ static const struct msm_pingroup ipq4019_groups[] = {
 	PINGROUP(17, blsp_uart0, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA),
 	PINGROUP(18, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA),
 	PINGROUP(19, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA),
-	PINGROUP(20, blsp_i2c0, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA),
-	PINGROUP(21, blsp_i2c0, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA),
-	PINGROUP(22, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA),
-	PINGROUP(23, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA),
-	PINGROUP(24, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA),
-	PINGROUP(25, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA),
-	PINGROUP(26, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA),
-	PINGROUP(27, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA),
-	PINGROUP(28, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA),
-	PINGROUP(29, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+	PINGROUP(20, blsp_i2c0, i2s_rx_mclk, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+	PINGROUP(21, blsp_i2c0, i2s_rx_bclk, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+	PINGROUP(22, NA, i2s_rx_fsync, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+	PINGROUP(23, NA, NA, i2s_rxd, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+	PINGROUP(24, NA, NA, i2s_tx_mclk, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+	PINGROUP(25, NA, NA, i2s_tx_bclk, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+	PINGROUP(26, NA, NA, i2s_tx_fsync, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+	PINGROUP(27, NA, NA, i2s_txd1, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+	PINGROUP(28, NA, NA, i2s_txd2, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+	PINGROUP(29, NA, NA, i2s_txd3, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA),
 	PINGROUP(30, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA),
 	PINGROUP(31, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA),
 	PINGROUP(32, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA),
 	PINGROUP(33, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA),
-	PINGROUP(34, blsp_i2c1, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA),
-	PINGROUP(35, blsp_i2c1, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+	PINGROUP(34, blsp_i2c1, i2s_spdif_in, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+	PINGROUP(35, blsp_i2c1, i2s_spdif_out, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA),
 	PINGROUP(36, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA),
 	PINGROUP(37, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA),
 	PINGROUP(38, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA),
@@ -387,18 +447,18 @@ static const struct msm_pingroup ipq4019_groups[] = {
 	PINGROUP(49, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA),
 	PINGROUP(50, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA),
 	PINGROUP(51, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA),
-	PINGROUP(52, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA),
-	PINGROUP(53, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA),
-	PINGROUP(54, NA, blsp_spi0, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA),
-	PINGROUP(55, NA, blsp_spi0, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA),
-	PINGROUP(56, NA, blsp_spi0, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA),
-	PINGROUP(57, NA, blsp_spi0, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA),
-	PINGROUP(58, NA, NA, blsp_i2c0, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA),
-	PINGROUP(59, NA, blsp_i2c0, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA),
-	PINGROUP(60, NA, blsp_uart0, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA),
-	PINGROUP(61, NA, blsp_uart0, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA),
-	PINGROUP(62, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA),
-	PINGROUP(63, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+	PINGROUP(52, NA, NA, NA, i2s_tx_mclk, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+	PINGROUP(53, NA, NA, i2s_tx_bclk, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+	PINGROUP(54, NA, blsp_spi0, i2s_txd1, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+	PINGROUP(55, NA, blsp_spi0, i2s_txd2, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+	PINGROUP(56, NA, blsp_spi0, i2s_txd3, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+	PINGROUP(57, NA, blsp_spi0, i2s_tx_fsync, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+	PINGROUP(58, NA, NA, blsp_i2c0, NA, NA, i2s_rx_mclk, NA, NA, NA, NA, NA, NA, NA, NA),
+	PINGROUP(59, NA, blsp_i2c0, NA, NA, i2s_spdif_in, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+	PINGROUP(60, NA, blsp_uart0, NA, NA, NA, i2s_tx_bclk, i2s_rx_bclk, NA, NA, NA, NA, NA, NA, NA),
+	PINGROUP(61, NA, blsp_uart0, NA, NA, NA, i2s_tx_fsync, i2s_rx_fsync, NA, NA, NA, NA, NA, NA, NA),
+	PINGROUP(62, NA, NA, NA, NA, i2s_spdif_out, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+	PINGROUP(63, NA, NA, NA, NA, i2s_txd1, i2s_rxd, i2s_spdif_out, i2s_spdif_in, NA, NA, NA, NA, NA, NA),
 	PINGROUP(64, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA),
 	PINGROUP(65, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA),
 	PINGROUP(66, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA),
-- 
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
a Linux Foundation Collaborative Project

^ permalink raw reply related	[flat|nested] 24+ messages in thread

* [PATCH 4/4] qcom: ipq4019: Add ASoC driver modules
  2016-07-15  7:07 ` njaigane
                   ` (4 preceding siblings ...)
  (?)
@ 2016-07-15  7:07 ` njaigane
  2016-07-15 12:52     ` Mark Brown
  -1 siblings, 1 reply; 24+ messages in thread
From: njaigane @ 2016-07-15  7:07 UTC (permalink / raw)
  To: linux-arm-msm
  Cc: linux, devicetree, linux-kernel, linux-soc, linux-arm-kernel,
	twp, andy.gross, david.brown, robh+dt, pawel.moll, mark.rutland,
	ijc+devicetree, galak, linux, mturquette, sboyd, linus.walleij,
	plai, bgoswami, lgirdwood, broonie, perex, tiwai,
	bjorn.andersson, varada, pradeepb, snlakshm, linux-clk,
	linux-gpio, alsa-devel, bselvara, Jaiganesh Narayanan

From: Jaiganesh Narayanan <njaigane@codeaurora.org>

This patch adds the alsa based audio driver for IPQ4019 ASoC.

Signed-off-by: Jaiganesh Narayanan <njaigane@codeaurora.org>
---
 sound/soc/qcom/Kconfig                     |  47 ++
 sound/soc/qcom/Makefile                    |   1 +
 sound/soc/qcom/ipq4019/Makefile            |  16 +
 sound/soc/qcom/ipq4019/ipq4019-adss.c      | 407 ++++++++++++++
 sound/soc/qcom/ipq4019/ipq4019-adss.h      | 432 +++++++++++++++
 sound/soc/qcom/ipq4019/ipq4019-codec.c     | 475 +++++++++++++++++
 sound/soc/qcom/ipq4019/ipq4019-codec.h     |  91 ++++
 sound/soc/qcom/ipq4019/ipq4019-cpu-dai.c   | 687 ++++++++++++++++++++++++
 sound/soc/qcom/ipq4019/ipq4019-mbox.c      | 825 +++++++++++++++++++++++++++++
 sound/soc/qcom/ipq4019/ipq4019-mbox.h      | 146 +++++
 sound/soc/qcom/ipq4019/ipq4019-pcm-i2s.c   | 609 +++++++++++++++++++++
 sound/soc/qcom/ipq4019/ipq4019-pcm-spdif.c | 664 +++++++++++++++++++++++
 sound/soc/qcom/ipq4019/ipq4019-pcm-tdm.c   | 609 +++++++++++++++++++++
 sound/soc/qcom/ipq4019/ipq4019-pcm.h       |  37 ++
 sound/soc/qcom/ipq4019/ipq4019-stereo.c    | 313 +++++++++++
 sound/soc/qcom/ipq4019/ipq4019.c           | 121 +++++
 16 files changed, 5480 insertions(+)
 create mode 100644 sound/soc/qcom/ipq4019/Makefile
 create mode 100644 sound/soc/qcom/ipq4019/ipq4019-adss.c
 create mode 100644 sound/soc/qcom/ipq4019/ipq4019-adss.h
 create mode 100644 sound/soc/qcom/ipq4019/ipq4019-codec.c
 create mode 100644 sound/soc/qcom/ipq4019/ipq4019-codec.h
 create mode 100644 sound/soc/qcom/ipq4019/ipq4019-cpu-dai.c
 create mode 100644 sound/soc/qcom/ipq4019/ipq4019-mbox.c
 create mode 100644 sound/soc/qcom/ipq4019/ipq4019-mbox.h
 create mode 100644 sound/soc/qcom/ipq4019/ipq4019-pcm-i2s.c
 create mode 100644 sound/soc/qcom/ipq4019/ipq4019-pcm-spdif.c
 create mode 100644 sound/soc/qcom/ipq4019/ipq4019-pcm-tdm.c
 create mode 100644 sound/soc/qcom/ipq4019/ipq4019-pcm.h
 create mode 100644 sound/soc/qcom/ipq4019/ipq4019-stereo.c
 create mode 100644 sound/soc/qcom/ipq4019/ipq4019.c

diff --git a/sound/soc/qcom/Kconfig b/sound/soc/qcom/Kconfig
index 8ec9a07..de1f5b1 100644
--- a/sound/soc/qcom/Kconfig
+++ b/sound/soc/qcom/Kconfig
@@ -43,3 +43,50 @@ config SND_SOC_APQ8016_SBC
           Support for Qualcomm Technologies LPASS audio block in
           APQ8016 SOC-based systems.
           Say Y if you want to use audio devices on MI2S.
+
+config SND_SOC_IPQ4019
+	tristate "Soc Audio support for IPQ4019 platforms"
+	depends on SND_SOC_QCOM
+	select SND_SOC_IPQ4019_ADSS
+	select SND_SOC_IPQ4019_CPU_DAI
+	select SND_SOC_IPQ4019_STEREO
+	select SND_SOC_IPQ4019_MBOX
+	select SND_SOC_IPQ4019_PCM_I2S
+	select SND_SOC_IPQ4019_CODEC
+	select SND_SOC_IPQ4019_PCM_TDM
+	select SND_SOC_IPQ4019_PCM_SPDIF
+	help
+	Say Y or M to if you want to add support for SoC audio on
+	Qualcomm Atheros IPQ4019 based board.
+
+config SND_SOC_IPQ4019_ADSS
+	tristate
+	depends on SND_SOC_IPQ4019
+
+config SND_SOC_IPQ4019_CPU_DAI
+	tristate
+	depends on SND_SOC_IPQ4019
+
+config SND_SOC_IPQ4019_STEREO
+	tristate
+	depends on SND_SOC_IPQ4019
+
+config SND_SOC_IPQ4019_MBOX
+	tristate
+	depends on SND_SOC_IPQ4019
+
+config SND_SOC_IPQ4019_PCM_I2S
+	tristate
+	depends on SND_SOC_IPQ4019
+
+config SND_SOC_IPQ4019_CODEC
+	tristate
+	depends on SND_SOC_IPQ4019
+
+config SND_SOC_IPQ4019_PCM_TDM
+	tristate
+	depends on SND_SOC_IPQ4019
+
+config SND_SOC_IPQ4019_PCM_SPDIF
+	tristate
+	depends on SND_SOC_IPQ4019
diff --git a/sound/soc/qcom/Makefile b/sound/soc/qcom/Makefile
index 79e5c50..f326b6a 100644
--- a/sound/soc/qcom/Makefile
+++ b/sound/soc/qcom/Makefile
@@ -15,3 +15,4 @@ snd-soc-apq8016-sbc-objs := apq8016_sbc.o
 
 obj-$(CONFIG_SND_SOC_STORM) += snd-soc-storm.o
 obj-$(CONFIG_SND_SOC_APQ8016_SBC) += snd-soc-apq8016-sbc.o
+obj-$(CONFIG_SND_SOC_IPQ4019) += ipq4019/
diff --git a/sound/soc/qcom/ipq4019/Makefile b/sound/soc/qcom/ipq4019/Makefile
new file mode 100644
index 0000000..ee46f51
--- /dev/null
+++ b/sound/soc/qcom/ipq4019/Makefile
@@ -0,0 +1,16 @@
+# QCA IPQ4019 Sound Card Support
+snd-soc-ipq4019-objs := ipq4019.o
+snd-soc-ipq4019-cpu-dai-objs := ipq4019-cpu-dai.o
+snd-soc-ipq4019-pcm-i2s-objs := ipq4019-pcm-i2s.o
+snd-soc-ipq4019-pcm-tdm-objs := ipq4019-pcm-tdm.o
+snd-soc-ipq4019-pcm-spdif-objs := ipq4019-pcm-spdif.o
+
+obj-$(CONFIG_SND_SOC_IPQ4019) += ipq4019.o
+obj-$(CONFIG_SND_SOC_IPQ4019_ADSS) += ipq4019-adss.o
+obj-$(CONFIG_SND_SOC_IPQ4019_CPU_DAI) += snd-soc-ipq4019-cpu-dai.o
+obj-$(CONFIG_SND_SOC_IPQ4019_STEREO) += ipq4019-stereo.o
+obj-$(CONFIG_SND_SOC_IPQ4019_MBOX) += ipq4019-mbox.o
+obj-$(CONFIG_SND_SOC_IPQ4019_PCM_I2S) += snd-soc-ipq4019-pcm-i2s.o
+obj-$(CONFIG_SND_SOC_IPQ4019_CODEC) += ipq4019-codec.o
+obj-$(CONFIG_SND_SOC_IPQ4019_PCM_SPDIF) += snd-soc-ipq4019-pcm-spdif.o
+obj-$(CONFIG_SND_SOC_IPQ4019_PCM_TDM) += snd-soc-ipq4019-pcm-tdm.o
diff --git a/sound/soc/qcom/ipq4019/ipq4019-adss.c b/sound/soc/qcom/ipq4019/ipq4019-adss.c
new file mode 100644
index 0000000..a3d21a193
--- /dev/null
+++ b/sound/soc/qcom/ipq4019/ipq4019-adss.c
@@ -0,0 +1,407 @@
+/*
+ * Copyright (c) 2015-2016, The Linux Foundation. All rights reserved.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <linux/bitops.h>
+#include <sound/pcm.h>
+#include <linux/io.h>
+#include <linux/delay.h>
+#include <linux/reset.h>
+#include <linux/spinlock.h>
+
+#include "ipq4019-adss.h"
+
+static void __iomem *adss_audio_local_base;
+void __iomem *adss_audio_spdifin_base;
+static struct reset_control *audio_blk_rst;
+static spinlock_t i2s_ctrl_lock;
+static spinlock_t tdm_ctrl_lock;
+static spinlock_t glb_mode_lock;
+
+/* Channel Number Per Frame for Transmitter/Receiver
+ * Real value = val + 1
+ */
+void ipq4019_glb_tdm_ctrl_ch_num(uint32_t val, uint32_t dir)
+{
+	uint32_t cfg;
+	unsigned long flags;
+
+	spin_lock_irqsave(&tdm_ctrl_lock, flags);
+	cfg = readl(adss_audio_local_base + ADSS_GLB_TDM_CTRL_REG);
+
+	if (dir == PLAYBACK) {
+		cfg &= ~(GLB_TDM_CTRL_TX_CHAN_NUM_MASK);
+		cfg |= GLB_TDM_CTRL_TX_CHAN_NUM(val);
+	} else if (dir == CAPTURE) {
+		cfg &= ~(GLB_TDM_CTRL_RX_CHAN_NUM_MASK);
+		cfg |= GLB_TDM_CTRL_RX_CHAN_NUM(val);
+	}
+	writel(cfg, adss_audio_local_base + ADSS_GLB_TDM_CTRL_REG);
+	spin_unlock_irqrestore(&tdm_ctrl_lock, flags);
+}
+EXPORT_SYMBOL(ipq4019_glb_tdm_ctrl_ch_num);
+
+/* FSYNC Hi Duration for Transmitter/Receiver */
+void ipq4019_glb_tdm_ctrl_sync_num(uint32_t val, uint32_t dir)
+{
+	uint32_t cfg;
+	unsigned long flags;
+
+	spin_lock_irqsave(&tdm_ctrl_lock, flags);
+	cfg = readl(adss_audio_local_base + ADSS_GLB_TDM_CTRL_REG);
+
+	if (dir == PLAYBACK) {
+		cfg &= ~(GLB_TDM_CTRL_TX_SYNC_NUM_MASK);
+		cfg |= GLB_TDM_CTRL_TX_SYNC_NUM(val);
+	} else if (dir == CAPTURE) {
+		cfg &= ~(GLB_TDM_CTRL_RX_SYNC_NUM_MASK);
+		cfg |= GLB_TDM_CTRL_RX_SYNC_NUM(val);
+	}
+	writel(cfg, adss_audio_local_base + ADSS_GLB_TDM_CTRL_REG);
+	spin_unlock_irqrestore(&tdm_ctrl_lock, flags);
+}
+EXPORT_SYMBOL(ipq4019_glb_tdm_ctrl_sync_num);
+
+/* Serial Data Delay for transmitter/receiver */
+void ipq4019_glb_tdm_ctrl_delay(uint32_t delay, uint32_t dir)
+{
+	uint32_t cfg;
+	unsigned long flags;
+
+	spin_lock_irqsave(&tdm_ctrl_lock, flags);
+	cfg = readl(adss_audio_local_base + ADSS_GLB_TDM_CTRL_REG);
+
+	if (dir == PLAYBACK) {
+		cfg &= ~(GLB_TDM_CTRL_TX_DELAY);
+		if (delay)
+			cfg |= GLB_TDM_CTRL_TX_DELAY;
+	} else if (dir == CAPTURE) {
+		cfg &= ~(GLB_TDM_CTRL_RX_DELAY);
+		if (delay)
+			cfg |= GLB_TDM_CTRL_RX_DELAY;
+	}
+	writel(cfg, adss_audio_local_base + ADSS_GLB_TDM_CTRL_REG);
+	spin_unlock_irqrestore(&tdm_ctrl_lock, flags);
+}
+EXPORT_SYMBOL(ipq4019_glb_tdm_ctrl_delay);
+
+/* I2S Interface Enable */
+static void ipq4019_glb_i2s_interface_en(int enable)
+{
+	u32 cfg;
+	unsigned long flags;
+
+	spin_lock_irqsave(&i2s_ctrl_lock, flags);
+	cfg = readl(adss_audio_local_base + ADSS_GLB_CHIP_CTRL_I2S_REG);
+	cfg &= ~GLB_CHIP_CTRL_I2S_INTERFACE_EN;
+	if (enable)
+		cfg |= GLB_CHIP_CTRL_I2S_INTERFACE_EN;
+	writel(cfg, adss_audio_local_base + ADSS_GLB_CHIP_CTRL_I2S_REG);
+	spin_unlock_irqrestore(&i2s_ctrl_lock, flags);
+	/*
+	 * As per the audio controller susbsytem after writing to
+	 * the register wait 5ms for the i2s settle down.
+	 */
+	mdelay(5);
+}
+EXPORT_SYMBOL(ipq4019_glb_i2s_interface_en);
+
+/* Enable Stereo0/Stereo1/Stereo2 channel */
+void ipq4019_glb_stereo_ch_en(int enable, int stereo_ch)
+{
+	uint32_t cfg;
+	unsigned long flags;
+
+	spin_lock_irqsave(&i2s_ctrl_lock, flags);
+	cfg = readl(adss_audio_local_base + ADSS_GLB_CHIP_CTRL_I2S_REG);
+	if (stereo_ch == STEREO0) {
+		cfg &= ~(GLB_CHIP_CTRL_I2S_STEREO0_GLB_EN);
+		cfg |= GLB_CHIP_CTRL_I2S_STEREO0_GLB_EN;
+	} else if (stereo_ch == STEREO1) {
+		cfg &= ~(GLB_CHIP_CTRL_I2S_STEREO1_GLB_EN);
+		cfg |= GLB_CHIP_CTRL_I2S_STEREO1_GLB_EN;
+	} else if (stereo_ch == STEREO2) {
+		cfg &= ~(GLB_CHIP_CTRL_I2S_STEREO2_GLB_EN);
+		cfg |= GLB_CHIP_CTRL_I2S_STEREO2_GLB_EN;
+	}
+	writel(cfg, adss_audio_local_base + ADSS_GLB_CHIP_CTRL_I2S_REG);
+	spin_unlock_irqrestore(&i2s_ctrl_lock, flags);
+}
+EXPORT_SYMBOL(ipq4019_glb_stereo_ch_en);
+
+/*
+ * I2S Module Reset
+ */
+static void ipq4019_glb_i2s_reset(void)
+{
+	writel(GLB_I2S_RESET_VAL, adss_audio_local_base + ADSS_GLB_I2S_RST_REG);
+	mdelay(5);
+	writel(0x0, adss_audio_local_base + ADSS_GLB_I2S_RST_REG);
+}
+
+/*
+ * Enable I2S/TDM and Playback/Capture Audio Mode
+ */
+void ipq4019_glb_audio_mode(int mode, int dir)
+{
+	u32 cfg;
+	unsigned long flags;
+
+	spin_lock_irqsave(&glb_mode_lock, flags);
+	cfg = readl(adss_audio_local_base + ADSS_GLB_AUDIO_MODE_REG);
+	if (mode == I2S && dir == PLAYBACK) {
+		cfg &= ~GLB_AUDIO_MODE_XMIT_MASK;
+		cfg |= GLB_AUDIO_MODE_XMIT_I2S;
+	} else if (mode == I2S && dir == CAPTURE) {
+		cfg &= ~GLB_AUDIO_MODE_RECV_MASK;
+		cfg |= GLB_AUDIO_MODE_RECV_I2S;
+	} else if (mode == TDM && dir == PLAYBACK) {
+		cfg &= ~GLB_AUDIO_MODE_XMIT_MASK;
+		cfg |= GLB_AUDIO_MODE_XMIT_TDM;
+	} else if (mode == TDM && dir == CAPTURE) {
+		cfg &= ~GLB_AUDIO_MODE_RECV_MASK;
+		cfg |= GLB_AUDIO_MODE_RECV_TDM;
+	}
+	writel(cfg, adss_audio_local_base + ADSS_GLB_AUDIO_MODE_REG);
+	spin_unlock_irqrestore(&glb_mode_lock, flags);
+}
+EXPORT_SYMBOL(ipq4019_glb_audio_mode);
+
+/*
+ * I2S0 TX Data Port Enable
+ *
+ * Todo :
+ * Check if bits 6:4 configures only
+ * I2S0 or other channels as well
+ */
+void ipq4019_glb_tx_data_port_en(u32 enable)
+{
+	u32 cfg;
+	unsigned long flags;
+
+	spin_lock_irqsave(&glb_mode_lock, flags);
+	cfg = readl(adss_audio_local_base + ADSS_GLB_AUDIO_MODE_REG);
+	cfg &= ~GLB_AUDIO_MODE_I2S0_TXD_OE;
+	if (enable)
+		cfg |= GLB_AUDIO_MODE_I2S0_TXD_OE;
+	writel(cfg, adss_audio_local_base + ADSS_GLB_AUDIO_MODE_REG);
+	spin_unlock_irqrestore(&glb_mode_lock, flags);
+}
+EXPORT_SYMBOL(ipq4019_glb_tx_data_port_en);
+
+/*
+ * I2S3 RX Data Port Enable
+ */
+void ipq4019_glb_rx_data_port_en(u32 enable)
+{
+	u32 cfg;
+	unsigned long flags;
+
+	spin_lock_irqsave(&glb_mode_lock, flags);
+	cfg = readl(adss_audio_local_base + ADSS_GLB_AUDIO_MODE_REG);
+	cfg &= ~GLB_AUDIO_MODE_I2S3_RXD_OE;
+	if (enable)
+		cfg |= GLB_AUDIO_MODE_I2S3_RXD_OE;
+	writel(cfg, adss_audio_local_base + ADSS_GLB_AUDIO_MODE_REG);
+	spin_unlock_irqrestore(&glb_mode_lock, flags);
+}
+EXPORT_SYMBOL(ipq4019_glb_rx_data_port_en);
+
+/*
+ * Cross 1K Boundary
+ */
+void ipq4019_glb_audio_mode_B1K(void)
+{
+	u32 cfg;
+	unsigned long flags;
+
+	spin_lock_irqsave(&glb_mode_lock, flags);
+	cfg =  readl(adss_audio_local_base + ADSS_GLB_AUDIO_MODE_REG);
+	cfg &= ~GLB_AUDIO_MODE_B1K;
+	cfg |= GLB_AUDIO_MODE_B1K;
+	writel(cfg, adss_audio_local_base + ADSS_GLB_AUDIO_MODE_REG);
+	spin_unlock_irqrestore(&glb_mode_lock, flags);
+}
+EXPORT_SYMBOL(ipq4019_glb_audio_mode_B1K);
+
+/*
+ * Frame Sync Port Enable for I2S0 TX
+ */
+void ipq4019_glb_tx_framesync_port_en(u32 enable)
+{
+	u32 cfg;
+	unsigned long flags;
+
+	spin_lock_irqsave(&glb_mode_lock, flags);
+	cfg =  readl(adss_audio_local_base + ADSS_GLB_AUDIO_MODE_REG);
+	cfg &= ~GLB_AUDIO_MODE_I2S0_FS_OE;
+	if (enable)
+		cfg |= GLB_AUDIO_MODE_I2S0_FS_OE;
+	writel(cfg, adss_audio_local_base + ADSS_GLB_AUDIO_MODE_REG);
+	spin_unlock_irqrestore(&glb_mode_lock, flags);
+}
+EXPORT_SYMBOL(ipq4019_glb_tx_framesync_port_en);
+
+/*
+ * Frame Sync Port Enable for I2S3 RX
+ */
+void ipq4019_glb_rx_framesync_port_en(u32 enable)
+{
+	u32 cfg;
+	unsigned long flags;
+
+	spin_lock_irqsave(&glb_mode_lock, flags);
+	cfg =  readl(adss_audio_local_base + ADSS_GLB_AUDIO_MODE_REG);
+	cfg &= ~GLB_AUDIO_MODE_I2S3_FS_OE;
+	if (enable)
+		cfg |= GLB_AUDIO_MODE_I2S3_FS_OE;
+	writel(cfg, adss_audio_local_base + ADSS_GLB_AUDIO_MODE_REG);
+	spin_unlock_irqrestore(&glb_mode_lock, flags);
+}
+EXPORT_SYMBOL(ipq4019_glb_rx_framesync_port_en);
+
+void ipq4019_glb_clk_enable_oe(u32 dir)
+{
+	u32 cfg;
+	unsigned long flags;
+
+	spin_lock_irqsave(&i2s_ctrl_lock, flags);
+	cfg = readl(adss_audio_local_base + ADSS_GLB_CLK_I2S_CTRL_REG);
+
+	if (dir == PLAYBACK) {
+		cfg |= (GLB_CLK_I2S_CTRL_TX_BCLK_OE |
+			GLB_CLK_I2S_CTRL_TX_MCLK_OE);
+	} else {
+		cfg |= (GLB_CLK_I2S_CTRL_RX_BCLK_OE |
+			GLB_CLK_I2S_CTRL_RX_MCLK_OE);
+	}
+	writel(cfg, adss_audio_local_base + ADSS_GLB_CLK_I2S_CTRL_REG);
+	spin_unlock_irqrestore(&i2s_ctrl_lock, flags);
+}
+EXPORT_SYMBOL(ipq4019_glb_clk_enable_oe);
+
+void ipq4019_spdifin_ctrl_spdif_en(uint32_t enable)
+{
+	uint32_t reg_val;
+
+	reg_val = readl(adss_audio_spdifin_base + ADSS_SPDIFIN_SPDIF_CTRL_REG);
+
+	if (enable)
+		reg_val |= SPDIF_CTRL_SPDIF_ENABLE;
+	else
+		reg_val &= ~SPDIF_CTRL_SPDIF_ENABLE;
+
+	writel(reg_val, adss_audio_spdifin_base + ADSS_SPDIFIN_SPDIF_CTRL_REG);
+
+}
+EXPORT_SYMBOL(ipq4019_spdifin_ctrl_spdif_en);
+
+void ipq4019_spdifin_cfg(void)
+{
+	uint32_t reg_val;
+
+	reg_val = readl(adss_audio_spdifin_base + ADSS_SPDIFIN_SPDIF_CTRL_REG);
+	reg_val &= ~(SPDIF_CTRL_CHANNEL_MODE
+			| SPDIF_CTRL_VALIDITYCHECK
+			| SPDIF_CTRL_PARITYCHECK);
+	reg_val |= (SPDIF_CTRL_USE_FIFO_IF
+			| SPDIF_CTRL_SFR_ENABLE
+			| SPDIF_CTRL_FIFO_ENABLE);
+	writel(reg_val, adss_audio_spdifin_base + ADSS_SPDIFIN_SPDIF_CTRL_REG);
+}
+EXPORT_SYMBOL(ipq4019_spdifin_cfg);
+
+void ipq4019_glb_spdif_out_en(uint32_t enable)
+{
+	int32_t cfg;
+
+	cfg = readl(adss_audio_local_base + ADSS_GLB_AUDIO_MODE_REG);
+	cfg &= ~(GLB_AUDIO_MODE_SPDIF_OUT_OE);
+	if (enable)
+		cfg |= GLB_AUDIO_MODE_SPDIF_OUT_OE;
+	writel(cfg, adss_audio_local_base + ADSS_GLB_AUDIO_MODE_REG);
+}
+EXPORT_SYMBOL(ipq4019_glb_spdif_out_en);
+
+static const struct of_device_id ipq4019_audio_adss_id_table[] = {
+	{ .compatible = "qca,ipq4019-audio-adss" },
+	{},
+};
+MODULE_DEVICE_TABLE(of, ipq4019_audio_adss_id_table);
+
+static int ipq4019_audio_adss_probe(struct platform_device *pdev)
+{
+	struct resource *res;
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	adss_audio_local_base = devm_ioremap_resource(&pdev->dev, res);
+	if (IS_ERR(adss_audio_local_base))
+		return PTR_ERR(adss_audio_local_base);
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+	adss_audio_spdifin_base = devm_ioremap_resource(&pdev->dev, res);
+	if (IS_ERR(adss_audio_spdifin_base))
+		return PTR_ERR(adss_audio_spdifin_base);
+
+	audio_blk_rst = devm_reset_control_get(&pdev->dev, "blk_rst");
+	if (IS_ERR(audio_blk_rst))
+		return PTR_ERR(audio_blk_rst);
+
+	spin_lock_init(&i2s_ctrl_lock);
+	spin_lock_init(&glb_mode_lock);
+	spin_lock_init(&tdm_ctrl_lock);
+
+	/*
+	 * Reset order is critical here.
+	 * First audio block should be out of reset,
+	 * followed by I2S block.
+	 * Since the audio block is brought out of
+	 * reset by hardware by default, it is not
+	 * required to be done in software explicitly.
+	 */
+	ipq4019_glb_i2s_reset();
+
+	ipq4019_glb_i2s_interface_en(ENABLE);
+
+	ipq4019_glb_audio_mode_B1K();
+
+	return 0;
+}
+
+static int ipq4019_audio_adss_remove(struct platform_device *pdev)
+{
+	ipq4019_glb_i2s_interface_en(DISABLE);
+	return 0;
+}
+
+static struct platform_driver ipq4019_audio_adss_driver = {
+	.probe = ipq4019_audio_adss_probe,
+	.remove = ipq4019_audio_adss_remove,
+	.driver = {
+		.name = "ipq4019-adss",
+		.of_match_table = ipq4019_audio_adss_id_table,
+	},
+};
+
+module_platform_driver(ipq4019_audio_adss_driver);
+
+MODULE_ALIAS("platform:ipq4019-adss");
+MODULE_LICENSE("Dual BSD/GPL");
+MODULE_DESCRIPTION("IPQ4019 Audio subsytem driver");
diff --git a/sound/soc/qcom/ipq4019/ipq4019-adss.h b/sound/soc/qcom/ipq4019/ipq4019-adss.h
new file mode 100644
index 0000000..87f3e0f
--- /dev/null
+++ b/sound/soc/qcom/ipq4019/ipq4019-adss.h
@@ -0,0 +1,432 @@
+/* 
+ * Copyright (c) 2015-2016, The Linux Foundation. All rights reserved.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ */
+
+#ifndef IPQ4019_ADSS_H
+#define IPQ4019_ADSS_H
+
+/* ADSS AUDIO Registers */
+
+#define ADSS_BASE	0x7700000
+#define ADSS_RANGE	0x20000
+
+/* ADSS_AUDIO_LOCAL_REG Registers */
+
+#define ADSS_GLB_PCM_MBOX_CTRL_REG		0x0C
+
+#define ADSS_GLB_CHIP_CTRL_I2S_REG		0x10
+#define GLB_CHIP_CTRL_I2S_INTERFACE_EN		BIT(0)
+#define GLB_CHIP_CTRL_I2S_STEREO0_GLB_EN	BIT(1)
+#define GLB_CHIP_CTRL_I2S_STEREO1_GLB_EN	BIT(2)
+#define GLB_CHIP_CTRL_I2S_STEREO2_GLB_EN	BIT(3)
+
+#define ADSS_GLB_I2S_RST_REG		0x14
+#define GLB_I2S_RST_CTRL_MBOX0		BIT(0)
+#define GLB_I2S_RST_CTRL_I2S0		BIT(1)
+#define GLB_I2S_RST_CTRL_MBOX3		BIT(2)
+#define GLB_I2S_RESET_VAL		0xF
+
+#define ADSS_GLB_CLK_I2S_CTRL_REG	0x18
+#define GLB_CLK_I2S_CTRL_TX_BCLK_OE	BIT(28)
+#define GLB_CLK_I2S_CTRL_RX_BCLK_OE	BIT(27)
+#define GLB_CLK_I2S_CTRL_RX_MCLK_OE	BIT(16)
+#define GLB_CLK_I2S_CTRL_TX_MCLK_OE	BIT(17)
+
+#define ADSS_GLB_TDM_CTRL_REG			0x1C
+#define GLB_TDM_CTRL_TX_CHAN_NUM(x)	(x << 0)
+#define GLB_TDM_CTRL_TX_CHAN_NUM_MASK	0xF
+#define GLB_TDM_CTRL_TX_SYNC_NUM(x)	(x << 4)
+#define GLB_TDM_CTRL_TX_SYNC_NUM_MASK	(0x1F << 4)
+#define GLB_TDM_CTRL_RX_CHAN_NUM(x)	(x << 16)
+#define GLB_TDM_CTRL_RX_CHAN_NUM_MASK	(0xF << 16)
+#define GLB_TDM_CTRL_RX_SYNC_NUM(x)	(x << 20)
+#define GLB_TDM_CTRL_RX_SYNC_NUM_MASK	(0x1F << 20)
+#define GLB_TDM_CTRL_TX_DELAY			BIT(25)
+#define GLB_TDM_CTRL_RX_DELAY			BIT(26)
+
+#define ADSS_GLB_AUDIO_MODE_REG		0x30
+#define GLB_AUDIO_MODE_RECV_MASK	BIT(2)
+#define GLB_AUDIO_MODE_XMIT_MASK	BIT(0)
+#define GLB_AUDIO_MODE_RECV_I2S		(0 << 2)
+#define GLB_AUDIO_MODE_RECV_TDM		BIT(2)
+#define GLB_AUDIO_MODE_XMIT_I2S		(0 << 0)
+#define GLB_AUDIO_MODE_XMIT_TDM		BIT(0)
+#define GLB_AUDIO_MODE_I2S0_TXD_OE	(7 << 4)
+#define GLB_AUDIO_MODE_I2S0_FS_OE	BIT(7)
+#define GLB_AUDIO_MODE_I2S3_FS_OE	BIT(8)
+#define GLB_AUDIO_MODE_I2S3_RXD_OE	BIT(9)
+#define GLB_AUDIO_MODE_SPDIF_OUT_OE	BIT(10)
+#define GLB_AUDIO_MODE_B1K			BIT(28)
+
+#define ADSS_MBOX_STEREO_AUDIO_BASE		(ADSS_BASE + 0x8000)
+
+/* ADSS_MBOX_STEREO_AUDIO_BASE + 0x0 */
+#define ADSS_MBOX0_AUDIO_BASE				0x0
+#define ADSS_MBOX1_AUDIO_BASE				0x2000
+#define ADSS_MBOX2_AUDIO_BASE				0x4000
+#define ADSS_MBOX3_AUDIO_BASE				0x6000
+
+#define ADSS_MBOXn_MBOX_FIFO0_REG			0x0
+#define MBOX_FIFO_RESET_TX_INIT				BIT(0)
+#define MBOX_FIFO_RESET_RX_INIT				BIT(2)
+
+#define ADSS_MBOXn_MBOX_FIFO_STATUS0_REG		0x08
+
+#define ADSS_MBOXn_MBOX_DMA_POLICY_REG			0x10
+#define MBOX_DMA_POLICY_SW_RESET			BIT(31)
+#define MBOX_DMA_POLICY_TX_INT_TYPE			BIT(17)
+#define MBOX_DMA_POLICY_RX_INT_TYPE			BIT(16)
+#define MBOX_DMA_POLICY_RXD_16BIT_SWAP			BIT(10)
+#define MBOX_DMA_POLICY_RXD_END_SWAP			BIT(8)
+#define ADSS_MBOX_DMA_POLICY_SRAM_AC(x)		((((x) >> 28) & 0xf) << 12)
+#define ADSS_MBOX_DMA_POLICY_TX_FIFO_THRESHOLD(x)	((((x) & 0xf) << 4))
+
+#define ADSS_MBOXn_MBOXn_DMA_RX_DESCRIPTOR_BASE_REG	0x18
+
+#define ADSS_MBOXn_MBOXn_DMA_RX_CONTROL_REG		0x1C
+#define ADSS_MBOXn_DMA_RX_CONTROL_STOP			BIT(0)
+#define ADSS_MBOXn_DMA_RX_CONTROL_START			BIT(1)
+#define ADSS_MBOXn_DMA_RX_CONTROL_RESUME		BIT(2)
+
+#define ADSS_MBOXn_MBOXn_DMA_TX_DESCRIPTOR_BASE_REG	0x20
+
+#define ADSS_MBOXn_MBOXn_DMA_TX_CONTROL_REG		0x24
+#define ADSS_MBOXn_DMA_TX_CONTROL_STOP			BIT(0)
+#define ADSS_MBOXn_DMA_TX_CONTROL_START			BIT(1)
+#define ADSS_MBOXn_DMA_TX_CONTROL_RESUME		BIT(2)
+
+#define ADSS_MBOXn_MBOX_FRAME_REG			0x38
+#define ADSS_MBOXn_FIFO_TIMEOUT_REG			0x40
+
+#define ADSS_MBOXn_MBOX_INT_STATUS_REG			0x44
+#define MBOX_INT_STATUS_TX_DMA_COMPLETE			BIT(6)
+#define MBOX_INT_STATUS_RX_DMA_COMPLETE			BIT(10)
+
+#define ADSS_MBOXn_MBOX_INT_ENABLE_REG			0x4C
+#define MBOX_INT_ENABLE_RX_DMA_COMPLETE			BIT(10)
+#define MBOX_INT_STATUS_RX_UNDERFLOW			BIT(4)
+#define MBOX_INT_STATUS_RX_FIFO_UNDERFLOW		BIT(12)
+#define MBOX_INT_ENABLE_TX_DMA_COMPLETE			BIT(6)
+#define MBOX_INT_STATUS_TX_OVERFLOW			BIT(5)
+#define MBOX_INT_STATUS_TX_FIFO_OVERFLOW		BIT(13)
+
+#define ADSS_MBOXn_MBOX_FIFO_RESET_REG			0x58
+#define MBOX_FIFO_RESET_TX_INIT				BIT(0)
+#define MBOX_FIFO_RESET_RX_INIT				BIT(2)
+
+#define ADSS_MBOXn_MBOX_DEBUG_CHAIN0_REG		0x60
+#define ADSS_MBOXn_MBOX_DEBUG_CHAIN1_REG		0x64
+#define ADSS_MBOXn_MBOX_DEBUG_CHAIN0_SIGNALS_REG	0x68
+#define ADSS_MBOXn_MBOX_DEBUG_CHAIN1_SIGNALS_REG	0x6C
+
+/* ADSS_STEREO0_AUDIO_STEREO_REG Registers */
+
+#define ADSS_STEREO0_AUDIO_BASE		0x9000
+#define ADSS_STEREO1_AUDIO_BASE		0xB000
+#define ADSS_STEREO2_AUDIO_BASE		0xD000
+#define ADSS_STEREO3_AUDIO_BASE		0xF000
+
+#define STEREO0_OFFSET			0x0
+#define STEREO1_OFFSET			0x2000
+#define STEREO2_OFFSET			0x4000
+#define STEREO3_OFFSET			0x6000
+
+#define ADSS_STEREOn_STEREO0_CONFIG_REG			0x0
+#define STEREOn_CONFIG_MIC_SWAP				BIT(24)
+#define STEREOn_CONFIG_SPDIF_ENABLE			BIT(23)
+#define STEREOn_CONFIG_ENABLE				BIT(21)
+#define STEREOn_CONFIG_MIC_RESET			BIT(20)
+#define STEREOn_CONFIG_RESET				BIT(19)
+#define STEREOn_CONFIG_I2S_DELAY			(0 << 18)
+#define STEREOn_CONFIG_PCM_SWAP				BIT(17)
+#define STEREOn_CONFIG_MIC_WORD_SIZE_32			BIT(16)
+#define STEREOn_CONFIG_MIC_WORD_SIZE_16			(0 << 16)
+#define STEREOn_CONFIG_STEREO_MODE			(0 << 14)
+#define STEREOn_CONFIG_MONO_MODE			BIT(14)
+#define STEREOn_CONFIG_STEREO_MONO_MASK			(3 << 14)
+#define STEREOn_CONFIG_DATA_WORD_SIZE(x)		((x) << 12)
+#define STEREOn_CONFIG_DATA_WORD_SIZE_MASK		(3 << 12)
+#define STEREOn_CONFIG_I2S_WORD_SIZE_32			BIT(11)
+#define STEREOn_CONFIG_I2S_WORD_SIZE_16			(0 << 11)
+#define STEREOn_CONFIG_MCK_SEL				BIT(10)
+#define STEREOn_CONFIG_SAMPLE_CNT_CLEAR_TYPE		BIT(9)
+#define STEREOn_CONFIG_MASTER				BIT(8)
+
+#define MAX_STEREO_ENTRIES	4
+#define TDM_SYNC_NUM		2
+#define TDM_DELAY		0
+#define MCLK_MULTI		4
+
+/* ADSS_AUDIO_PCM_REG Registers */
+
+#define ADSS_AUDIO_PCM_REG_BASE		ADSS_BASE + 0x4000
+
+#define AADSS_PCM_BITMAP_REG		0x0
+
+#define AADSS_PCM_CTRL_REG		0x04
+#define PCM_CTRL_TX2RX_LP_EN(x)		(x << 31)
+#define PCM_CTRL_RX2TX_LP_EN(x)		(x << 30)
+#define PCM_CTRL_CPU_MODE(x)		(x << 29)
+#define PCM_CTRL_PCM_GCLK_EN(x)		(x << 28)
+#define PCM_CTRL_FRAME_SYNC_LEN(x)	(x << 26)
+#define PCM_CTRL_PCM_CLK_MODE(x)	(x << 25)
+#define PCM_CTRL_PCM_SLOT_MODE(x)	(x << 24)
+#define PCM_CTRL_PCM_DCLK_MODE(x)	(x << 4)
+#define PCM_CTRL_PCM_TX_PHASE(x)	(x << 2)
+#define PCM_CTRL_PCM_RX_PHASE(x)	(x << 0)
+
+#define AADSS_PCM_OFFSET_REG		0x08
+#define AADSS_PCM_START_REG		0x0C
+#define AADSS_PCM_INT_STATUS_REG	0x10
+#define AADSS_PCM_INT_ENABLE_REG	0x14
+#define AADSS_PCM_RX_DATA_8BIT_REG	0x18
+#define AADSS_PCM_TX_DATA_8BIT_REG	0x1C
+#define AADSS_PCM_DIVIDER_REG		0x20
+#define AADSS_PCM_TH_REG		0x24
+#define AADSS_PCM_FIFO_CNT_REG		0x28
+#define AADSS_PCM_FIFO_ERR_SLOT_REG	0x2C
+#define AADSS_PCM_RX_DATA_16BIT_REG	0x30
+#define AADSS_PCM_TX_DATA_16BIT_REG	0x34
+
+/* I2S Parameters */
+#define IPQ4019_I2S_NO_OF_PERIODS	(130)
+#define IPQ4019_I2S_PERIOD_BYTES_MIN	ALIGN(4032, L1_CACHE_BYTES)
+#define IPQ4019_I2S_BUFF_SIZE		(IPQ4019_I2S_PERIOD_BYTES_MIN * \
+						IPQ4019_I2S_NO_OF_PERIODS)
+#define IPQ4019_I2S_CAPTURE_BUFF_SIZE	(IPQ4019_I2S_PERIOD_BYTES_MIN * \
+						IPQ4019_I2S_NO_OF_PERIODS)
+
+/* TDM Parameters */
+#define IPQ4019_TDM_NO_OF_PERIODS	(260)
+#define IPQ4019_TDM_PERIOD_BYTES_MIN	ALIGN(4032, L1_CACHE_BYTES)
+#define IPQ4019_TDM_BUFF_SIZE		(IPQ4019_TDM_PERIOD_BYTES_MIN * \
+						IPQ4019_TDM_NO_OF_PERIODS)
+#define IPQ4019_TDM_CAPTURE_BUFF_SIZE	(IPQ4019_TDM_PERIOD_BYTES_MIN * \
+						IPQ4019_TDM_NO_OF_PERIODS)
+
+/* SPDIF area */
+
+
+/* ADSS_MBOXSPDIFIN_AUDIO_MBOX_REG Registers */
+
+#define ADSS_MBOXSPDIFIN_AUDIO_MBOX_REG_BASE	ADSS_BASE + 0x6000
+
+#define AADSS_MBOXSPDIFIN_MBOX_FIFO0_REG \\
+	((ADSS_MBOXSPDIFIN_AUDIO_MBOX_REG_BASE) + 0x0)
+
+#define AADSS_MBOXSPDIFIN_MBOX_FIFO_STATUS0_REG \\
+	((ADSS_MBOXSPDIFIN_AUDIO_MBOX_REG_BASE) + 0x08)
+
+#define AADSS_MBOXSPDIFIN_MBOX_DMA_POLICY_REG \\
+	((ADSS_MBOXSPDIFIN_AUDIO_MBOX_REG_BASE) + 0x10)
+
+#define AADSS_MBOXSPDIFIN_MBOX0_DMA_RX_DESCRIPTOR_BASE_REG \\
+	((ADSS_MBOXSPDIFIN_AUDIO_MBOX_REG_BASE) + 0x18)
+
+#define AADSS_MBOXSPDIFIN_MBOX0_DMA_RX_CONTROL_REG \\
+	((ADSS_MBOXSPDIFIN_AUDIO_MBOX_REG_BASE) + 0x1C)
+
+#define AADSS_MBOXSPDIFIN_MBOX0_DMA_TX_DESCRIPTOR_BASE_REG \\
+	((ADSS_MBOXSPDIFIN_AUDIO_MBOX_REG_BASE) + 0x20)
+
+#define AADSS_MBOXSPDIFIN_MBOX0_DMA_TX_CONTROL_REG \\
+	((ADSS_MBOXSPDIFIN_AUDIO_MBOX_REG_BASE) + 0x24)
+
+#define AADSS_MBOXSPDIFIN_MBOX_FRAME_REG \\
+	((ADSS_MBOXSPDIFIN_AUDIO_MBOX_REG_BASE) + 0x38)
+
+#define AADSS_MBOXSPDIFIN_FIFO_TIMEOUT_REG \\
+	((ADSS_MBOXSPDIFIN_AUDIO_MBOX_REG_BASE) + 0x40)
+
+#define AADSS_MBOXSPDIFIN_MBOX_INT_STATUS_REG \\
+	((ADSS_MBOXSPDIFIN_AUDIO_MBOX_REG_BASE) + 0x44)
+
+#define AADSS_MBOXSPDIFIN_MBOX_INT_ENABLE_REG \\
+	((ADSS_MBOXSPDIFIN_AUDIO_MBOX_REG_BASE) + 0x4C)
+
+#define AADSS_MBOXSPDIFIN_MBOX_FIFO_RESET_REG \\
+	((ADSS_MBOXSPDIFIN_AUDIO_MBOX_REG_BASE) + 0x58)
+
+#define AADSS_MBOXSPDIFIN_MBOX_DEBUG_CHAIN0_REG \\
+	((ADSS_MBOXSPDIFIN_AUDIO_MBOX_REG_BASE) + 0x60)
+
+#define AADSS_MBOXSPDIFIN_MBOX_DEBUG_CHAIN1_REG \\
+	((ADSS_MBOXSPDIFIN_AUDIO_MBOX_REG_BASE) + 0x64)
+
+#define AADSS_MBOXSPDIFIN_MBOX_DEBUG_CHAIN0_SIGNALS_REG \\
+	((ADSS_MBOXSPDIFIN_AUDIO_MBOX_REG_BASE) + 0x68)
+
+#define AADSS_MBOXSPDIFIN_MBOX_DEBUG_CHAIN1_SIGNALS_REG \\
+	((ADSS_MBOXSPDIFIN_AUDIO_MBOX_REG_BASE) + 0x6C)
+
+/* ADSS_SPDIFIN_AUDIO_SPDIF_BASE Registers */
+
+#define ADSS_SPDIFIN_SPDIF_CTRL_REG		(0x00)
+#define SPDIF_CTRL_INTREQ_MASK			BIT(31)
+#define SPDIF_CTRL_BEGIN_MASK			BIT(30)
+#define SPDIF_CTRL_LOCK_MASK			BIT(29)
+#define SPDIF_CTRL_SYNCERR_MASK			BIT(28)
+#define SPDIF_CTRL_AFULL_MASK			BIT(27)
+#define SPDIF_CTRL_FULL_MASK			BIT(26)
+#define SPDIF_CTRL_AEMPTY_MASK			BIT(25)
+#define SPDIF_CTRL_EMPTY_MASK			BIT(24)
+#define SPDIF_CTRL_OVRERR_MASK			BIT(23)
+#define SPDIF_CTRL_UNDERR_MASK			BIT(22)
+#define SPDIF_CTRL_PARITY_MASK			BIT(21)
+#define SPDIF_CTRL_USE_FIFO_IF			BIT(19)
+#define SPDIF_CTRL_SETPREAMBB			BIT(18)
+#define SPDIF_CTRL_DUPLICATE			BIT(17)
+#define SPDIF_CTRL_CHANNEL_MODE			BIT(16)
+#define SPDIF_CTRL_VALIDITYCHECK		BIT(15)
+#define SPDIF_CTRL_PARITYGEN			BIT(14)
+#define SPDIF_CTRL_PARITYCHECK			BIT(13)
+#define SPDIF_CTRL_TR_MODE			BIT(12)
+#define SPDIF_CTRL_CLK_ENABLE			BIT(11)
+#define SPDIF_CTRL_FIFO_ENABLE			BIT(10)
+#define SPDIF_CTRL_SPDIF_ENABLE			BIT(9)
+#define SPDIF_CTRL_SFR_ENABLE			BIT(8)
+#define SPDIF_CTRL_TSAMPLERATE			BIT(7)
+
+#define ADSS_SPDIFIN_STEREO0_VOLUME		(0x04)
+#define ADSS_SPDIFIN_FIFO_CTRL_REG		(0x08)
+#define ADSS_SPDIFIN_START_REG_REG		(0x0C)
+#define ADSS_SPDIFIN_SELFIFO_REG		(0x10)
+
+
+#define ADSS_AUDIO_SPDIF_MISC_REG		0x150
+#define AUDIO_SPDIF_MISC_AUTO_SCALE_DIV_MASK	(0xF << 1)
+#define AUDIO_SPDIF_MISC_AUTO_SCALE_DIV(x)	(x << 1)
+
+#define ADSS_AUDIO_SPDIF_CBCR_REG		0x154
+
+#define ADSS_AUDIO_SPDIFDIV2_MISC_REG		0x158
+#define AUDIO_SPDIFDIV2_MISC_AUTO_SCALE_DIV_MASK	(0xF << 1)
+#define AUDIO_SPDIFDIV2_MISC_AUTO_SCALE_DIV(x)	(x << 1)
+
+#define ADSS_AUDIO_SPDIFDIV2_CBCR_REG		0x15C
+#define ADSS_AUDIO_SPDIFINFAST_CMD_RCGR_REG	0x1E0
+#define AUDIO_SPDIFINFAST_CMD_RCGR_ROOT_EN	(1 << 1)
+#define AUDIO_SPDIFINFAST_CMD_RCGR_UPDATE	(1 << 0)
+
+#define ADSS_AUDIO_SPDIFINFAST_CFG_RCGR_REG	0x1E4
+#define AUDIO_SPDIFINFAST_CFG_RCGR_SRC_SEL(x)	(x << 8)
+#define AUDIO_SPDIFINFAST_CFG_RCGR_SRC_DIV(x)	(x << 0)
+
+#define ADSS_AUDIO_SPDIFINFAST_CBCR_REG		0x1EC
+#define AUDIO_SPDIFINFAST			49152000
+
+#define SNDRV_PCM_FMTBIT_S24_3			SNDRV_PCM_FMTBIT_S24_3LE
+
+/* Enumerations */
+
+enum intf {
+	I2S,
+	TDM,
+	SPDIF,
+	I2S1,
+	I2S2,
+	MAX_INTF
+};
+
+enum dir {
+	PLAYBACK,
+	CAPTURE
+};
+
+enum cfg {
+	DISABLE,
+	ENABLE
+};
+
+/* Supported Channels */
+enum channels {
+	CH_STEREO = 2,
+	CH_3_1 = 4,
+	CH_5_1 = 6,
+	CH_7_1 = 8
+};
+
+enum ipq4019_samp_freq {
+	FREQ_8000 = 8000,
+	FREQ_11025 = 11025,
+	FREQ_16000 = 16000,
+	FREQ_22050 = 22050,
+	FREQ_32000 = 32000,
+	FREQ_44100 = 44100,
+	FREQ_48000 = 48000,
+	FREQ_64000 = 64000,
+	FREQ_88200 = 88200,
+	FREQ_96000 = 96000,
+	FREQ_176400 = 176400,
+	FREQ_192000 = 192000,
+};
+
+#define RATE_16000_96000 \
+		(SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_22050 |\
+		SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 |\
+		SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_64000 |\
+		SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000)
+
+enum stereo_ch {
+	STEREO0,
+	STEREO1,
+	STEREO2,
+	STEREO3
+};
+
+enum bit_width {
+	__BIT_8 = 8,
+	__BIT_16 = 16,
+	__BIT_24 = 24,
+	__BIT_32 = 32,
+	__BIT_INVAL = -1
+};
+
+/* ADSS APIs */
+extern void ipq4019_glb_audio_mode(int mode, int dir);
+extern void ipq4019_glb_tx_data_port_en(uint32_t enable);
+extern void ipq4019_glb_rx_data_port_en(uint32_t enable);
+extern void ipq4019_glb_tx_framesync_port_en(uint32_t enable);
+extern void ipq4019_glb_rx_framesync_port_en(uint32_t enable);
+extern void ipq4019_glb_clk_enable_oe(uint32_t dir);
+/* Stereo APIs */
+extern void ipq4019_stereo_config_reset(uint32_t reset, uint32_t stereo_offset);
+extern void ipq4019_stereo_config_mic_reset(uint32_t reset,
+					uint32_t stereo_offset);
+extern void ipq4019_stereo_config_enable(uint32_t enable,
+					uint32_t stereo_offset);
+extern int ipq4019_cfg_bit_width(uint32_t bit_width, uint32_t stereo_offset);
+extern void ipq4019_config_stereo_mode(uint32_t mode, uint32_t stereo_offset);
+extern void ipq4019_config_master(uint32_t enable, uint32_t stereo_offset);
+extern void ipq4019_config_mclk_sel(uint32_t stereo_offset, uint32_t val);
+extern void ipq4019_config_sample_cnt_clear_type(uint32_t stereo_offset);
+
+/* APIs in DAI driver */
+extern int ipq4019_get_mbox_id(struct snd_pcm_substream *substream, int intf);
+extern int ipq4019_get_stereo_id(struct snd_pcm_substream *substream, int intf);
+extern u32 ipq4019_get_act_bit_width(u32 bit_width);
+extern void ipq4019_stereo_spdif_enable(uint32_t enable, uint32_t stereo_id);
+extern void ipq4019_stereo_spdif_pcmswap(uint32_t enable, uint32_t stereo_id);
+extern void ipq4019_spdifin_ctrl_spdif_en(uint32_t enable);
+extern void ipq4019_glb_spdif_out_en(uint32_t enable);
+extern void ipq4019_spdifin_cfg(void);
+extern void ipq4019_glb_tdm_ctrl_ch_num(uint32_t val, uint32_t dir);
+extern void ipq4019_glb_tdm_ctrl_sync_num(uint32_t val, uint32_t dir);
+extern void ipq4019_glb_tdm_ctrl_delay(uint32_t delay, uint32_t dir);
+
+void ipq4019_glb_audio_mode_B1K(void);
+
+#endif
diff --git a/sound/soc/qcom/ipq4019/ipq4019-codec.c b/sound/soc/qcom/ipq4019/ipq4019-codec.c
new file mode 100644
index 0000000..61421d9
--- /dev/null
+++ b/sound/soc/qcom/ipq4019/ipq4019-codec.c
@@ -0,0 +1,475 @@
+/*
+ * Copyright (c) 2015-2016, The Linux Foundation. All rights reserved.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <sound/soc.h>
+#include <sound/pcm.h>
+#include <sound/soc.h>
+#include <sound/soc-dai.h>
+#include <sound/control.h>
+#include <linux/platform_device.h>
+#include <linux/spi/spi.h>
+#include <linux/i2c.h>
+#include <linux/gpio.h>
+#include <linux/delay.h>
+#include <sound/initval.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+
+#include "ipq4019-adss.h"
+#include "ipq4019-codec.h"
+
+struct audio_hw_params audio_params;
+
+static const u8 akd4613_reg[AK4613_MAX_REG] = {
+	0x0F, 0x07, 0x3F, 0x20, 0x20, 0x55, 0x05, 0x07,
+	0x0F, 0x07, 0x3F, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+};
+
+uint8_t ipq4019_compare_hw_params(struct audio_hw_params *curr_params)
+{
+	if ((curr_params->bit_width == audio_params.bit_width) &&
+		(curr_params->freq == audio_params.freq) &&
+		(curr_params->channels == audio_params.channels))
+		return 0;
+	else
+		return -EINVAL;
+}
+
+/* DFS : Sampling Speed
+ *
+ * DFS1	DFS0		Sampling Speed Mode (fs)
+ * 0	0	Normal Speed Mode	32kHz~48kHz (default)
+ * 0	1	Double Speed Mode	64kHz~96kHz
+ * 1	0	Quad Speed Mode	128kHz~192kHz
+ * 1	1	N/A			-
+ */
+
+static int ipq4019_codec_i2c_set_dfs(struct snd_soc_codec *codec, int mode)
+{
+	uint32_t reg;
+
+	if (mode > QUAD_SPEED) {
+		pr_err("%s: %d: Invalid DFS mode", __func__, __LINE__);
+		return -EINVAL;
+	}
+
+	reg = snd_soc_read(codec, AKD4613_04_CTRL2);
+
+	reg &= ~(AKD4613_DFS_MASK);
+	reg |= AKD4613_DFS(mode);
+
+	snd_soc_write(codec, AKD4613_04_CTRL2, reg);
+
+	return 0;
+}
+
+/* CKS : Master Clock Input Frequency Select
+ *
+ * CKS1	CKS0	Normal Speed	Double Speed	Quad Speed
+ * 0	0	256fs		256fs		128fs
+ * 0	1	384fs		256fs		128fs
+ * 1	0	512fs		256fs		128fs (default)
+ * 1	1	512fs		256fs		128fs
+ */
+
+static int ipq4019_codec_i2c_set_cks(struct snd_soc_codec *codec,
+					int config, int mode)
+{
+	uint32_t cks_val;
+	uint32_t reg;
+
+	if (mode == NORMAL_SPEED) {
+		if (config == FS_256)
+			cks_val = 0;
+		else if (config == FS_384)
+			cks_val = 1;
+		else if (config == FS_512)
+			cks_val = 2;
+		else
+			cks_val = -EINVAL;
+	} else if (mode == DOUBLE_SPEED) {
+		if (config == FS_256)
+			cks_val = 2;
+		else
+			cks_val = -EINVAL;
+	} else if (mode == QUAD_SPEED) {
+		if (config == FS_128)
+			cks_val = 2;
+		else
+			cks_val = -EINVAL;
+	} else {
+		pr_err("%s: %d: Invalid DFS mode", __func__, __LINE__);
+		return -EINVAL;
+	}
+
+	if (cks_val < 0) {
+		pr_err("%s: %d: Invalid CKS config", __func__, __LINE__);
+		return cks_val;
+	}
+
+	reg = snd_soc_read(codec, AKD4613_04_CTRL2);
+
+	reg &= ~(AKD4613_CKS_MASK);
+	reg |= AKD4613_CKS(cks_val);
+
+	snd_soc_write(codec, AKD4613_04_CTRL2, reg);
+
+	return 0;
+}
+
+static int ipq4019_codec_i2c_set_tdm_mode(struct snd_soc_codec *codec,
+						int tdm_mode)
+{
+	uint32_t reg;
+
+	if (tdm_mode >= TDM_MAX) {
+		pr_err("%s: %d: Invalid DFS mode", __func__, __LINE__);
+		return -EINVAL;
+	}
+
+	reg = snd_soc_read(codec, AKD4613_03_CTRL1);
+
+	reg &= ~(AKD4613_TDM_MODE_MASK);
+	reg |= AKD4613_TDM_MODE(tdm_mode);
+
+	snd_soc_write(codec, AKD4613_03_CTRL1, reg);
+
+	return 0;
+}
+
+static int ipq4019_codec_i2c_set_dif(struct snd_soc_codec *codec,
+						int dif_val)
+{
+	uint32_t reg;
+
+	reg = snd_soc_read(codec, AKD4613_03_CTRL1);
+
+	reg &= ~(AKD4613_DIF_MASK);
+	reg |= AKD4613_DIF(dif_val);
+
+	snd_soc_write(codec, AKD4613_03_CTRL1, reg);
+
+	return 0;
+}
+
+static void ipq4019_codec_i2c_write_defaults(struct snd_soc_codec *codec)
+{
+	int i;
+
+	for (i = 0; i < AK4613_MAX_REG; i++)
+		snd_soc_write(codec, i, akd4613_reg[i]);
+	udelay(10);
+}
+
+static int ipq4019_codec_audio_startup(struct snd_pcm_substream *substream,
+					struct snd_soc_dai *dai)
+{
+	struct snd_soc_codec *codec;
+
+	codec = dai->codec;
+
+	/* I2S and TDM cannot co-exist. CPU DAI startup would
+	 * have already checked this case, by this time.
+	 */
+	if (!dai->active)
+		ipq4019_codec_i2c_write_defaults(codec);
+
+	return 0;
+}
+
+static int ipq4019_codec_audio_hw_params(struct snd_pcm_substream *substream,
+					struct snd_pcm_hw_params *params,
+					struct snd_soc_dai *dai)
+{
+	struct snd_soc_codec *codec;
+	int samp_rate = params_rate(params);
+	u32 bit_width = params_format(params);
+	int channels = params_channels(params);
+	int bit_act;
+	int dfs, cks, tdm_mode, dif;
+	uint32_t intf = dai->driver->id;
+	struct audio_hw_params curr_params;
+
+	bit_act = ipq4019_get_act_bit_width(bit_width);
+	if (bit_act == __BIT_INVAL)
+		return -EINVAL;
+
+	curr_params.freq = samp_rate;
+	curr_params.channels = channels;
+	curr_params.bit_width = bit_act;
+
+	codec = dai->codec;
+
+	/*
+	 * Since CLKS in the codec are shared by I2S TX and RX channels,
+	 * Rx and Tx when used simulatneoulsy will have to use the same channel,
+	 * sampling frequency and bit widths. So compare the settings and then
+	 * update the codec settings.
+	 */
+
+	if (dai->active > 1) {
+		if (ipq4019_compare_hw_params(&curr_params)) {
+			/* Playback and capture settings do not match */
+			pr_err("\nPlayback and capture settings do not match\n");
+			return -EINVAL;
+		}
+		/* Settings match, codec settings are already done*/
+		return 0;
+	}
+
+	audio_params.freq = samp_rate;
+	audio_params.channels = channels;
+	audio_params.bit_width = bit_act;
+
+	if (intf == I2S) {
+		/* default values */
+		dfs = NORMAL_SPEED;
+		cks = FS_512;
+		tdm_mode = STEREO;
+		dif = DIF_I2S_MODE;
+
+	} else if (intf == TDM) {
+		/* Codec settings for 8 channels */
+		dfs = DOUBLE_SPEED;
+		cks = FS_256;
+		tdm_mode = TDM_256;
+		dif = DIF_LR_MODE3;
+	} else {
+		pr_err("\n%s Invalid interface\n", __func__);
+		return -EINVAL;
+	}
+
+	ipq4019_codec_i2c_set_dfs(codec, dfs);
+	ipq4019_codec_i2c_set_cks(codec, cks, dfs);
+	ipq4019_codec_i2c_set_tdm_mode(codec, tdm_mode);
+	ipq4019_codec_i2c_set_dif(codec, dif);
+	udelay(10);
+
+	return 0;
+}
+
+static int ipq4019_codec_audio_prepare(struct snd_pcm_substream *substream,
+					struct snd_soc_dai *dai)
+{
+	dev_dbg(dai->dev, "%s:%d\n", __func__, __LINE__);
+	return 0;
+}
+
+static void ipq4019_codec_audio_shutdown(struct snd_pcm_substream *substream,
+					struct snd_soc_dai *dai)
+{
+	dev_dbg(dai->dev, "%s:%d\n", __func__, __LINE__);
+}
+
+static struct snd_soc_dai_ops ipq4019_codec_audio_ops = {
+	.startup	= ipq4019_codec_audio_startup,
+	.hw_params	= ipq4019_codec_audio_hw_params,
+	.prepare	= ipq4019_codec_audio_prepare,
+	.shutdown	= ipq4019_codec_audio_shutdown,
+};
+
+static struct snd_soc_dai_driver ipq4019_codec_dais[] = {
+	{
+		.name = "qca-i2s-codec-dai",
+		.playback = {
+			.stream_name = "qca-i2s-playback",
+			.channels_min = CH_STEREO,
+			.channels_max = CH_STEREO,
+			.rates = RATE_16000_96000,
+			.formats = SNDRV_PCM_FMTBIT_S16 |
+				SNDRV_PCM_FMTBIT_S32,
+		},
+		.capture = {
+			.stream_name = "qca-i2s-capture",
+			.channels_min = CH_STEREO,
+			.channels_max = CH_STEREO,
+			.rates = RATE_16000_96000,
+			.formats = SNDRV_PCM_FMTBIT_S16 |
+				SNDRV_PCM_FMTBIT_S32,
+		},
+		.ops = &ipq4019_codec_audio_ops,
+		.id = I2S,
+	},
+	{
+		.name = "qca-tdm-codec-dai",
+		.playback = {
+			.stream_name = "qca-tdm-playback",
+			.channels_min = CH_STEREO,
+			.channels_max = CH_7_1,
+			.rates = RATE_16000_96000,
+			.formats = SNDRV_PCM_FMTBIT_S16 |
+				SNDRV_PCM_FMTBIT_S32,
+		},
+		.capture = {
+			.stream_name = "qca-tdm-capture",
+			.channels_min = CH_STEREO,
+			.channels_max = CH_7_1,
+			.rates = RATE_16000_96000,
+			.formats = SNDRV_PCM_FMTBIT_S16 |
+				SNDRV_PCM_FMTBIT_S32,
+		},
+		.ops = &ipq4019_codec_audio_ops,
+		.id = TDM,
+	},
+	{
+		.name = "qca-i2s1-codec-dai",
+		.playback = {
+			.stream_name = "qca-i2s1-playback",
+			.channels_min = CH_STEREO,
+			.channels_max = CH_STEREO,
+			.rates = RATE_16000_96000,
+			.formats = SNDRV_PCM_FMTBIT_S16 |
+				SNDRV_PCM_FMTBIT_S32,
+		},
+	},
+	{
+		.name = "qca-i2s2-codec-dai",
+		.playback = {
+			.stream_name = "qca-i2s2-playback",
+			.channels_min = CH_STEREO,
+			.channels_max = CH_STEREO,
+			.rates = RATE_16000_96000,
+			.formats = SNDRV_PCM_FMTBIT_S16 |
+				SNDRV_PCM_FMTBIT_S32,
+		},
+	},
+	{
+		.name = "qca-spdif-codec-dai",
+		.playback = {
+			.stream_name = "qca-spdif-playback",
+			.channels_min = CH_STEREO,
+			.channels_max = CH_STEREO,
+			.rates = RATE_16000_96000,
+			.formats = SNDRV_PCM_FMTBIT_S16 |
+				SNDRV_PCM_FMTBIT_S24_3,
+		},
+		.capture = {
+			.stream_name = "qca-spdif-capture",
+			.channels_min = CH_STEREO,
+			.channels_max = CH_STEREO,
+			.rates = RATE_16000_96000,
+			.formats = SNDRV_PCM_FMTBIT_S16 |
+				SNDRV_PCM_FMTBIT_S24_3,
+		},
+	},
+};
+
+static int ipq4019_info(struct snd_kcontrol *kcontrol,
+			struct snd_ctl_elem_info *uinfo)
+{
+	return -ENOTSUPP;
+}
+
+static const struct snd_kcontrol_new vol_ctrl  = {
+	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+	.name = "playback volume",
+	.access = (SNDRV_CTL_ELEM_ACCESS_TLV_READ |
+		SNDRV_CTL_ELEM_ACCESS_READWRITE),
+	.info = ipq4019_info,
+};
+
+unsigned int ipq4019_codec_i2c_read(struct snd_soc_codec *codec,
+					unsigned int reg)
+{
+	int ret;
+
+	ret = i2c_smbus_read_byte_data(codec->control_data, (u8)(reg & 0xFF));
+	if (ret < 0)
+		pr_err("\ti2c read error %s(%d)\n", __func__, ret);
+
+	return ret;
+}
+
+static const struct snd_soc_codec_driver ipq4019_codec = {
+	.num_controls = 0,
+	.reg_cache_size = ARRAY_SIZE(akd4613_reg),
+	.reg_word_size = sizeof(u8),
+	.reg_cache_default = akd4613_reg,
+};
+
+static const struct of_device_id ipq4019_codec_id_table[] = {
+	{ .compatible = "qca,ipq4019-codec" },
+	{ /* Sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, ipq4019_codec_id_table);
+
+static int ipq4019_codec_i2c_probe(struct i2c_client *i2c,
+					const struct i2c_device_id *id)
+{
+	int ret;
+
+	ret = snd_soc_register_codec(&i2c->dev,
+			&ipq4019_codec, ipq4019_codec_dais,
+			ARRAY_SIZE(ipq4019_codec_dais));
+	if (ret < 0)
+		pr_err("\nsnd_soc_register_codec failed (%d)\n", ret);
+
+	return ret;
+}
+
+static int ipq4019_codec_i2c_remove(struct i2c_client *client)
+{
+	snd_soc_unregister_codec(&client->dev);
+	return 0;
+}
+
+static const struct of_device_id ipq4019_codec_of_match[] = {
+	{ .compatible = "qca,ipq4019-codec" },
+	{},
+};
+
+static const struct i2c_device_id ipq4019_codec_i2c_id[] = {
+	{ "qca_codec", 0 },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, ipq4019_codec_i2c_id);
+
+static struct i2c_driver ipq4019_codec_i2c_driver = {
+	.driver = {
+		.name = "qca_codec",
+		.owner = THIS_MODULE,
+		.of_match_table = ipq4019_codec_of_match,
+	},
+	.probe = ipq4019_codec_i2c_probe,
+	.remove = ipq4019_codec_i2c_remove,
+	.id_table = ipq4019_codec_i2c_id,
+};
+
+static int ipq4019_codec_init(void)
+{
+	int ret;
+
+	ret = i2c_add_driver(&ipq4019_codec_i2c_driver);
+	if (ret < 0)
+		pr_err("%s: %d: Failed to add I2C driver", __func__, __LINE__);
+
+	return ret;
+}
+module_init(ipq4019_codec_init);
+
+static void ipq4019_codec_exit(void)
+{
+	i2c_del_driver(&ipq4019_codec_i2c_driver);
+}
+module_exit(ipq4019_codec_exit);
+
+MODULE_LICENSE("Dual BSD/GPL");
+MODULE_DESCRIPTION("IPQ4019 Codec Driver");
diff --git a/sound/soc/qcom/ipq4019/ipq4019-codec.h b/sound/soc/qcom/ipq4019/ipq4019-codec.h
new file mode 100644
index 0000000..bf91c0f
--- /dev/null
+++ b/sound/soc/qcom/ipq4019/ipq4019-codec.h
@@ -0,0 +1,91 @@
+/*
+ * Copyright (c) 2015-2016, The Linux Foundation. All rights reserved.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ */
+
+#define AKD4613_00_PM1		0x00
+#define AKD4613_01_PM2		0x01
+#define AKD4613_02_PM3		0x02
+#define AKD4613_03_CTRL1	0x03
+#define AKD4613_04_CTRL2	0x04
+#define AKD4613_05_DE_EMP1	0x05
+#define AKD4613_06_DE_EMP2	0x06
+#define AKD4613_07_OVRFLW_DT	0x07
+#define AKD4613_08_ZERO_DT	0x08
+#define AKD4613_09_IP_CTRL	0x09
+#define AKD4613_0A_OP_CTRL	0x0A
+#define AKD4613_0B_LOUT1_CTRL	0x0B
+#define AKD4613_0C_ROUT1_CTRL	0x0C
+#define AKD4613_0D_LOUT2_CTRL	0x0D
+#define AKD4613_0E_ROUT2_CTRL	0x0E
+#define AKD4613_0F_LOUT3_CTRL	0x0F
+#define AKD4613_10_ROUT3_CTRL	0x10
+#define AKD4613_11_LOUT4_CTRL	0x11
+#define AKD4613_12_ROUT4_CTRL	0x12
+#define AKD4613_13_LOUT5_CTRL	0x13
+#define AKD4613_14_ROUT5_CTRL	0x14
+#define AKD4613_15_LOUT6_CTRL	0x15
+#define AKD4613_16_ROUT6_CTRL	0x16
+
+#define AK4613_MAX_REG		(AKD4613_16_ROUT6_CTRL + 1)
+
+/* AKD4613_03_CTRL1 */
+#define AKD4613_DIF_MASK		(7 << 3)
+#define AKD4613_DIF(x)			(x << 3)
+#define AKD4613_DIF_I2S_MODE		(4 << 3)
+#define AKD4613_TDM_MODE_MASK		(3 << 6)
+#define AKD4613_TDM_MODE(x)		(x << 6)
+
+/* AKD4613_04_CTRL2 */
+#define AKD4613_CKS_MASK		(0x3 << 4)
+#define AKD4613_CKS(x)			(x << 4)
+#define AKD4613_DFS_MASK		(0x3 << 2)
+#define AKD4613_DFS(x)			(x << 2)
+
+struct audio_hw_params {
+	uint8_t channels;
+	uint32_t freq;
+	uint8_t bit_width;
+};
+
+enum dfs {
+	NORMAL_SPEED,
+	DOUBLE_SPEED,
+	QUAD_SPEED,
+	NA
+};
+
+enum cks {
+	FS_128,
+	FS_256,
+	FS_384,
+	FS_512
+};
+
+enum tdm_mode {
+	STEREO,
+	TDM_512,
+	TDM_256,
+	TDM_128,
+	TDM_MAX
+};
+
+enum dif {
+	DIF_LR_MODE0,
+	DIF_LR_MODE1,
+	DIF_LR_MODE2,
+	DIF_LR_MODE3,
+	DIF_I2S_MODE
+};
diff --git a/sound/soc/qcom/ipq4019/ipq4019-cpu-dai.c b/sound/soc/qcom/ipq4019/ipq4019-cpu-dai.c
new file mode 100644
index 0000000..8f33e91
--- /dev/null
+++ b/sound/soc/qcom/ipq4019/ipq4019-cpu-dai.c
@@ -0,0 +1,687 @@
+/*
+ * Copyright (c) 2015-2016, The Linux Foundation. All rights reserved.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <linux/clk.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/soc.h>
+#include <sound/pcm_params.h>
+#include <linux/io.h>
+#include <linux/delay.h>
+#include <linux/of_device.h>
+#include <linux/clk-provider.h>
+#include <linux/clk.h>
+
+#include "ipq4019-mbox.h"
+#include "ipq4019-adss.h"
+
+struct dai_priv_st {
+	int stereo_tx;
+	int stereo_rx;
+	int mbox_tx;
+	int mbox_rx;
+	int tx_enabled;
+	int rx_enabled;
+	struct platform_device *pdev;
+};
+static struct dai_priv_st dai_priv[MAX_INTF];
+
+static struct clk *audio_tx_bclk;
+static struct clk *audio_tx_mclk;
+static struct clk *audio_rx_bclk;
+static struct clk *audio_rx_mclk;
+static struct clk *audio_spdif_src;
+static struct clk *audio_spdif_div2;
+static struct clk *audio_spdifinfast_src;
+
+/* Get Stereo channel ID based on I2S intf and direction */
+int ipq4019_get_stereo_id(struct snd_pcm_substream *substream, int intf)
+{
+	switch (substream->stream) {
+	case SNDRV_PCM_STREAM_PLAYBACK:
+		return dai_priv[intf].stereo_tx;
+	case SNDRV_PCM_STREAM_CAPTURE:
+		return dai_priv[intf].stereo_rx;
+	}
+	return -EINVAL;
+}
+EXPORT_SYMBOL(ipq4019_get_stereo_id);
+
+/* Get MBOX channel ID based on I2S/TDM/SPDIF intf and direction */
+int ipq4019_get_mbox_id(struct snd_pcm_substream *substream, int intf)
+{
+	switch (substream->stream) {
+	case SNDRV_PCM_STREAM_PLAYBACK:
+		return dai_priv[intf].mbox_tx;
+	case SNDRV_PCM_STREAM_CAPTURE:
+		return dai_priv[intf].mbox_rx;
+	}
+	return -EINVAL;
+}
+EXPORT_SYMBOL(ipq4019_get_mbox_id);
+
+u32 ipq4019_get_act_bit_width(u32 bit_width)
+{
+	switch (bit_width) {
+	case SNDRV_PCM_FORMAT_S8:
+	case SNDRV_PCM_FORMAT_U8:
+		return __BIT_8;
+	case SNDRV_PCM_FORMAT_S16_LE:
+	case SNDRV_PCM_FORMAT_S16_BE:
+	case SNDRV_PCM_FORMAT_U16_LE:
+	case SNDRV_PCM_FORMAT_U16_BE:
+		return __BIT_16;
+	case SNDRV_PCM_FORMAT_S24_3LE:
+	case SNDRV_PCM_FORMAT_S24_3BE:
+	case SNDRV_PCM_FORMAT_U24_3LE:
+	case SNDRV_PCM_FORMAT_U24_3BE:
+		return __BIT_32;
+	case SNDRV_PCM_FORMAT_S24_LE:
+	case SNDRV_PCM_FORMAT_S24_BE:
+	case SNDRV_PCM_FORMAT_U24_LE:
+	case SNDRV_PCM_FORMAT_U24_BE:
+		return __BIT_24;
+	case SNDRV_PCM_FORMAT_S32_LE:
+	case SNDRV_PCM_FORMAT_S32_BE:
+	case SNDRV_PCM_FORMAT_U32_LE:
+	case SNDRV_PCM_FORMAT_U32_BE:
+		return __BIT_32;
+	}
+	return __BIT_INVAL;
+}
+EXPORT_SYMBOL(ipq4019_get_act_bit_width);
+
+static int ipq4019_audio_clk_get(struct clk **clk, struct device *dev,
+					const char *id)
+{
+	*clk = devm_clk_get(dev, id);
+	if (IS_ERR(*clk)) {
+		dev_err(dev, "%s: Error in %s\n", __func__, id);
+		return PTR_ERR(*clk);
+	}
+
+	return 0;
+}
+
+static int ipq4019_audio_clk_set(struct clk *clk, struct device *dev,
+					u32 val)
+{
+	int ret;
+
+	ret = clk_set_rate(clk, val);
+	if (ret != 0) {
+		dev_err_ratelimited(dev, "Error in setting %s\n",
+						__clk_get_name(clk));
+		return ret;
+	}
+
+	ret = clk_prepare_enable(clk);
+	if (ret != 0) {
+		dev_err_ratelimited(dev, "Error in enable %s\n",
+					__clk_get_name(clk));
+		return ret;
+	}
+
+	return 0;
+}
+
+static void ipq4019_audio_clk_disable(struct clk **clk, struct device *dev)
+{
+	if (__clk_is_enabled(*clk))
+		clk_disable_unprepare(*clk);
+}
+
+static int ipq4019_audio_startup(struct snd_pcm_substream *substream,
+				struct snd_soc_dai *dai)
+{
+	u32 intf = dai->driver->id;
+
+	switch (substream->stream) {
+	case SNDRV_PCM_STREAM_PLAYBACK:
+		/* Check if the direction is enabled */
+		if (dai_priv[intf].tx_enabled != ENABLE)
+			return -EFAULT;
+
+		ipq4019_glb_tx_data_port_en(ENABLE);
+		ipq4019_glb_tx_framesync_port_en(ENABLE);
+		break;
+	case SNDRV_PCM_STREAM_CAPTURE:
+		/* Check if the direction is enabled */
+		if (dai_priv[intf].rx_enabled != ENABLE)
+			return -EFAULT;
+
+		ipq4019_glb_rx_data_port_en(ENABLE);
+		ipq4019_glb_rx_framesync_port_en(ENABLE);
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	if (intf == I2S || intf == I2S1 || intf == I2S2) {
+		/* Select I2S mode */
+		ipq4019_glb_audio_mode(I2S, substream->stream);
+	} else if (intf == TDM) {
+		/* Select TDM mode */
+		ipq4019_glb_audio_mode(TDM, substream->stream);
+
+		/* Set TDM Ctrl register */
+		ipq4019_glb_tdm_ctrl_sync_num(TDM_SYNC_NUM, substream->stream);
+		ipq4019_glb_tdm_ctrl_delay(TDM_DELAY, substream->stream);
+	}
+
+	return 0;
+}
+
+static int ipq4019_audio_hw_params(struct snd_pcm_substream *substream,
+					struct snd_pcm_hw_params *params,
+					struct snd_soc_dai *dai)
+{
+	u32 bit_width, channels, rate;
+	u32 intf = dai->driver->id;
+	u32 stereo_id = ipq4019_get_stereo_id(substream, intf);
+	u32 mbox_id = ipq4019_get_mbox_id(substream, intf);
+	u32 bit_act;
+	int ret;
+	u32 mclk, bclk;
+	struct device *dev = &(dai_priv[intf].pdev->dev);
+
+	bit_width = params_format(params);
+	channels = params_channels(params);
+	rate = params_rate(params);
+
+	bit_act = ipq4019_get_act_bit_width(bit_width);
+
+	if (intf == TDM) {
+		/* Set TDM number of channels */
+		ipq4019_glb_tdm_ctrl_ch_num((channels-1), substream->stream);
+		mclk = bclk = rate * bit_act * channels;
+	} else {
+		bclk = rate * bit_act * channels;
+		mclk = bclk * MCLK_MULTI;
+	}
+
+	ipq4019_glb_clk_enable_oe(substream->stream);
+
+	ipq4019_config_master(ENABLE, stereo_id);
+
+	ret = ipq4019_cfg_bit_width(bit_width, stereo_id);
+	if (ret) {
+		pr_err("BitWidth %d not supported ret: %d\n", bit_width, ret);
+		return ret;
+	}
+
+	ipq4019_stereo_config_enable(DISABLE, stereo_id);
+
+	ipq4019_stereo_config_reset(ENABLE, stereo_id);
+	ipq4019_stereo_config_mic_reset(ENABLE, stereo_id);
+
+	mdelay(5);
+
+	ret = ipq4019_mbox_fifo_reset(mbox_id);
+	if (ret) {
+		pr_err("%s: ret: %d Error in dma fifo reset\n",
+					__func__, ret);
+		return ret;
+	}
+
+	ipq4019_stereo_config_reset(DISABLE, stereo_id);
+	ipq4019_stereo_config_mic_reset(DISABLE, stereo_id);
+	ipq4019_stereo_config_enable(ENABLE, stereo_id);
+
+	switch (substream->stream) {
+	case SNDRV_PCM_STREAM_PLAYBACK:
+		ret = ipq4019_audio_clk_set(audio_tx_mclk, dev, mclk);
+		if (ret)
+			return ret;
+
+		ret = ipq4019_audio_clk_set(audio_tx_bclk, dev, bclk);
+		if (ret)
+			return ret;
+		break;
+
+	case SNDRV_PCM_STREAM_CAPTURE:
+		ret = ipq4019_audio_clk_set(audio_rx_mclk, dev, mclk);
+		if (ret)
+			return ret;
+
+		ret = ipq4019_audio_clk_set(audio_rx_bclk, dev, bclk);
+		if (ret)
+			return ret;
+		break;
+	}
+
+	return 0;
+}
+
+static void ipq4019_audio_shutdown(struct snd_pcm_substream *substream,
+					struct snd_soc_dai *dai)
+{
+	u32 intf = dai->driver->id;
+	struct device *dev = &(dai_priv[intf].pdev->dev);
+
+	switch (substream->stream) {
+	case SNDRV_PCM_STREAM_PLAYBACK:
+		ipq4019_glb_tx_data_port_en(DISABLE);
+		ipq4019_glb_tx_framesync_port_en(DISABLE);
+
+		/* Disable the clocks */
+		ipq4019_audio_clk_disable(&audio_tx_bclk, dev);
+		ipq4019_audio_clk_disable(&audio_tx_mclk, dev);
+		break;
+	case SNDRV_PCM_STREAM_CAPTURE:
+		ipq4019_glb_rx_data_port_en(DISABLE);
+		ipq4019_glb_rx_framesync_port_en(DISABLE);
+
+		/* Disable the clocks */
+		ipq4019_audio_clk_disable(&audio_rx_bclk, dev);
+		ipq4019_audio_clk_disable(&audio_rx_mclk, dev);
+		break;
+	}
+
+	/* Disable the I2S Stereo block */
+	ipq4019_stereo_config_enable(DISABLE,
+			ipq4019_get_stereo_id(substream, intf));
+}
+
+static struct snd_soc_dai_ops ipq4019_audio_ops = {
+	.startup	= ipq4019_audio_startup,
+	.hw_params	= ipq4019_audio_hw_params,
+	.shutdown	= ipq4019_audio_shutdown,
+};
+
+static int ipq4019_spdif_hw_params(struct snd_pcm_substream *substream,
+					struct snd_pcm_hw_params *params,
+					struct snd_soc_dai *dai)
+{
+	uint32_t bit_width, channels, rate, bit_act;
+	int ret;
+	uint32_t stereo_id = ipq4019_get_stereo_id(substream, SPDIF);
+	uint32_t mclk, bclk;
+	struct device *dev = &(dai_priv[SPDIF].pdev->dev);
+	uint32_t spdif_bclk;
+	uint32_t spdif_mclk;
+
+	bit_width = params_format(params);
+	channels = params_channels(params);
+	rate = params_rate(params);
+	bit_act = ipq4019_get_act_bit_width(bit_width);
+
+	bclk = rate * bit_act * channels;
+	mclk = bclk * MCLK_MULTI;
+
+	/* SPDIF subframe is always 32 bit and 2 channels */
+	spdif_bclk = rate * 32 * 2;
+	spdif_mclk = spdif_bclk * 2;
+
+	if (substream->stream == PLAYBACK) {
+		/* Set the clocks */
+		ret = ipq4019_audio_clk_set(audio_tx_mclk, dev, mclk);
+		if (ret)
+			return ret;
+
+		ret = ipq4019_audio_clk_set(audio_tx_bclk, dev, bclk);
+		if (ret)
+			return ret;
+
+		ret = ipq4019_audio_clk_set(audio_spdif_src, dev,
+						spdif_mclk);
+		if (ret)
+			return ret;
+
+		ret = ipq4019_audio_clk_set(audio_spdif_div2, dev,
+						spdif_bclk);
+		if (ret)
+			return ret;
+
+		ipq4019_glb_clk_enable_oe(substream->stream);
+
+		/* Set MASTER mode */
+		ipq4019_config_master(ENABLE, stereo_id);
+
+		/* Configure bit width */
+		ret = ipq4019_cfg_bit_width(bit_width, stereo_id);
+		if (ret) {
+			pr_err("%s: BitWidth %d not supported\n",
+				__func__, bit_width);
+			return ret;
+		}
+
+	} else if (substream->stream == CAPTURE) {
+		/* Set the clocks */
+		ret = ipq4019_audio_clk_set(audio_spdifinfast_src, dev,
+						AUDIO_SPDIFINFAST);
+		if (ret)
+			return ret;
+	}
+
+	return 0;
+}
+
+static int ipq4019_spdif_prepare(struct snd_pcm_substream *substream,
+					struct snd_soc_dai *dai)
+{
+	dev_dbg(dai->dev, "%s:%d\n", __func__, __LINE__);
+	return 0;
+}
+
+static int ipq4019_spdif_startup(struct snd_pcm_substream *substream,
+					struct snd_soc_dai *dai)
+{
+	int ret = 0;
+
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+		/* Check if the direction is enabled */
+		if (dai_priv[SPDIF].tx_enabled != ENABLE)
+			goto error;
+
+		ipq4019_glb_tx_data_port_en(ENABLE);
+		ipq4019_glb_tx_framesync_port_en(ENABLE);
+		ipq4019_glb_spdif_out_en(ENABLE);
+		/* Select I2S/TDM */
+		ipq4019_glb_audio_mode(I2S, substream->stream);
+	} else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
+		/* Check if the direction is enabled */
+		if (dai_priv[SPDIF].rx_enabled != ENABLE)
+			goto error;
+		ipq4019_spdifin_ctrl_spdif_en(DISABLE);
+
+		ipq4019_glb_rx_data_port_en(ENABLE);
+		ipq4019_glb_rx_framesync_port_en(ENABLE);
+		ipq4019_glb_audio_mode(I2S, substream->stream);
+		ipq4019_spdifin_cfg();
+	}
+
+	return ret;
+error:
+	pr_err("%s: Direction not enabled\n", __func__);
+	return -EFAULT;
+}
+
+static void ipq4019_spdif_shutdown(struct snd_pcm_substream *substream,
+					struct snd_soc_dai *dai)
+{
+	struct device *dev = &(dai_priv[SPDIF].pdev->dev);
+
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+		ipq4019_glb_tx_data_port_en(DISABLE);
+		ipq4019_glb_tx_framesync_port_en(DISABLE);
+
+		/* Disable the clocks */
+		ipq4019_audio_clk_disable(&audio_tx_bclk, dev);
+		ipq4019_audio_clk_disable(&audio_tx_mclk, dev);
+		ipq4019_audio_clk_disable(&audio_spdif_src, dev);
+		ipq4019_audio_clk_disable(&audio_spdif_div2, dev);
+
+	} else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
+		ipq4019_glb_rx_data_port_en(DISABLE);
+		ipq4019_glb_rx_framesync_port_en(DISABLE);
+
+		/* Disable the clocks */
+		ipq4019_audio_clk_disable(&audio_spdifinfast_src, dev);
+	}
+}
+
+static int ipq4019_spdif_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
+{
+	dev_dbg(dai->dev, "%s:%d\n", __func__, __LINE__);
+	return 0;
+}
+
+static struct snd_soc_dai_ops ipq4019_spdif_ops = {
+	.startup	= ipq4019_spdif_startup,
+	.prepare	= ipq4019_spdif_prepare,
+	.hw_params	= ipq4019_spdif_hw_params,
+	.shutdown	= ipq4019_spdif_shutdown,
+	.set_fmt	= ipq4019_spdif_set_fmt,
+};
+
+static struct snd_soc_dai_driver ipq4019_cpu_dais[] = {
+	{
+		.playback = {
+			.rates		= RATE_16000_96000,
+			.formats	= SNDRV_PCM_FMTBIT_S16 |
+					SNDRV_PCM_FMTBIT_S32,
+			.channels_min	= CH_STEREO,
+			.channels_max	= CH_STEREO,
+			.rate_min	= FREQ_16000,
+			.rate_max	= FREQ_96000,
+		},
+		.capture = {
+			.rates		= RATE_16000_96000,
+			.formats	= SNDRV_PCM_FMTBIT_S16 |
+					SNDRV_PCM_FMTBIT_S32,
+			.channels_min	= CH_STEREO,
+			.channels_max	= CH_STEREO,
+			.rate_min	= FREQ_16000,
+			.rate_max	= FREQ_96000,
+		},
+		.ops = &ipq4019_audio_ops,
+		.id = I2S,
+		.name = "qca-i2s-dai"
+	},
+	{
+		.playback = {
+			.rates		= RATE_16000_96000,
+			.formats	= SNDRV_PCM_FMTBIT_S16 |
+					SNDRV_PCM_FMTBIT_S32,
+			.channels_min	= CH_STEREO,
+			.channels_max	= CH_7_1,
+			.rate_min	= FREQ_16000,
+			.rate_max	= FREQ_96000,
+		},
+		.capture = {
+			.rates		= RATE_16000_96000,
+			.formats	= SNDRV_PCM_FMTBIT_S16 |
+					SNDRV_PCM_FMTBIT_S32,
+			.channels_min	= CH_STEREO,
+			.channels_max	= CH_7_1,
+			.rate_min	= FREQ_16000,
+			.rate_max	= FREQ_96000,
+		},
+		.ops = &ipq4019_audio_ops,
+		.id = TDM,
+		.name = "qca-tdm-dai"
+	},
+	{
+		.playback = {
+			.rates		= RATE_16000_96000,
+			.formats	= SNDRV_PCM_FMTBIT_S16 |
+					SNDRV_PCM_FMTBIT_S32,
+			.channels_min	= 2,
+			.channels_max	= 2,
+			.rate_min	= FREQ_16000,
+			.rate_max	= FREQ_96000,
+		},
+		.ops = &ipq4019_audio_ops,
+		.id = I2S1,
+		.name = "qca-i2s1-dai"
+	},
+	{
+		.playback = {
+			.rates		= RATE_16000_96000,
+			.formats	= SNDRV_PCM_FMTBIT_S16 |
+					SNDRV_PCM_FMTBIT_S32,
+			.channels_min	= 2,
+			.channels_max	= 2,
+			.rate_min	= FREQ_16000,
+			.rate_max	= FREQ_96000,
+		},
+		.ops = &ipq4019_audio_ops,
+		.id = I2S2,
+		.name = "qca-i2s2-dai"
+	},
+	{
+		.playback = {
+			.rates		= RATE_16000_96000,
+			.formats        = SNDRV_PCM_FMTBIT_S16 |
+					SNDRV_PCM_FMTBIT_S24_3,
+			.channels_min   = CH_STEREO,
+			.channels_max   = CH_STEREO,
+			.rate_min       = FREQ_16000,
+			.rate_max       = FREQ_96000,
+		},
+		.capture = {
+			.rates		= RATE_16000_96000,
+			.formats        = SNDRV_PCM_FMTBIT_S16 |
+					SNDRV_PCM_FMTBIT_S24_3,
+			.channels_min   = CH_STEREO,
+			.channels_max   = CH_STEREO,
+			.rate_min       = FREQ_16000,
+			.rate_max       = FREQ_96000,
+		},
+		.ops = &ipq4019_spdif_ops,
+		.id = SPDIF,
+		.name = "qca-spdif-dai"
+	},
+};
+
+static const struct snd_soc_component_driver ipq4019_i2s_component = {
+	.name           = "qca-cpu-dai",
+};
+
+static const struct of_device_id ipq4019_cpu_dai_id_table[] = {
+	{ .compatible = "qca,ipq4019-i2s", .data = (void *)I2S },
+	{ .compatible = "qca,ipq4019-tdm", .data = (void *)TDM},
+	{ .compatible = "qca,ipq4019-spdif", .data = (void *)SPDIF},
+	{ .compatible = "qca,ipq4019-i2s1", .data = (void *)I2S1},
+	{ .compatible = "qca,ipq4019-i2s2", .data = (void *)I2S2},
+	{},
+};
+MODULE_DEVICE_TABLE(of, ipq4019_cpu_dai_id_table);
+
+static int ipq4019_dai_probe(struct platform_device *pdev)
+{
+	const struct of_device_id *match;
+	struct device_node *np = pdev->dev.of_node;
+	int ret;
+	int intf;
+
+	match = of_match_device(ipq4019_cpu_dai_id_table, &pdev->dev);
+	if (!match)
+		return -ENODEV;
+
+	intf = (u32)match->data;
+
+	/* TX is enabled only when both DMA and Stereo TX channel
+	 * is specified in the DTSi
+	 */
+	if (!(of_property_read_u32(np, "dma-tx-channel",
+					&dai_priv[intf].mbox_tx)
+		|| of_property_read_u32(np, "stereo-tx-port",
+					&dai_priv[intf].stereo_tx))) {
+		dai_priv[intf].tx_enabled = ENABLE;
+	}
+
+	/* RX is enabled only when both DMA and Stereo RX channel
+	 * is specified in the DTSi.
+	 */
+	if (!(of_property_read_u32(np, "dma-rx-channel",
+					&dai_priv[intf].mbox_rx))) {
+		if (intf == SPDIF) {
+			dai_priv[intf].rx_enabled = ENABLE;
+			dai_priv[intf].stereo_rx = MAX_STEREO_ENTRIES;
+		} else if (!(of_property_read_u32(np, "stereo-rx-port",
+					&dai_priv[intf].stereo_rx))) {
+			dai_priv[intf].rx_enabled = ENABLE;
+		}
+	}
+
+	/* Either TX or Rx should have been enabled for a DMA/Stereo Channel */
+	if (!(dai_priv[intf].tx_enabled || dai_priv[intf].rx_enabled)) {
+		dev_err(&pdev->dev, "%s: error reading node properties\n",
+								np->name);
+		return -EFAULT;
+	}
+
+	/* Get Clks */
+	audio_tx_mclk = devm_clk_get(&pdev->dev, "audio_tx_mclk");
+
+	if (IS_ERR(audio_tx_mclk)) {
+		dev_err(&pdev->dev, "Could not get tx_mclk\n");
+		return PTR_ERR(audio_tx_mclk);
+	}
+
+	audio_tx_bclk = devm_clk_get(&pdev->dev, "audio_tx_bclk");
+
+	if (IS_ERR(audio_tx_bclk)) {
+		dev_err(&pdev->dev, "Could not get tx_bclk\n");
+		return PTR_ERR(audio_tx_bclk);
+	}
+
+	if (intf == SPDIF) {
+		ret = ipq4019_audio_clk_get(&audio_spdif_src, &pdev->dev,
+						"audio_spdif_src");
+		if (ret)
+			return ret;
+
+		ret = ipq4019_audio_clk_get(&audio_spdif_div2, &pdev->dev,
+						"audio_spdif_div2");
+		if (ret)
+			return ret;
+
+		ret = ipq4019_audio_clk_get(&audio_spdifinfast_src, &pdev->dev,
+						"audio_spdifinfast_src");
+		if (ret)
+			return ret;
+	} else {
+		audio_rx_mclk = devm_clk_get(&pdev->dev, "audio_rx_mclk");
+		if (IS_ERR(audio_rx_mclk)) {
+			dev_err(&pdev->dev, "Could not get rx_mclk\n");
+			return PTR_ERR(audio_rx_mclk);
+		}
+
+		audio_rx_bclk = devm_clk_get(&pdev->dev, "audio_rx_bclk");
+		if (IS_ERR(audio_rx_bclk)) {
+			dev_err(&pdev->dev, "Could not get rx_bclk\n");
+			return PTR_ERR(audio_rx_bclk);
+		}
+	}
+
+	dai_priv[intf].pdev = pdev;
+	ret = snd_soc_register_component(&pdev->dev, &ipq4019_i2s_component,
+			 ipq4019_cpu_dais, ARRAY_SIZE(ipq4019_cpu_dais));
+	if (ret)
+		dev_err(&pdev->dev,
+			"ret: %d error registering soc dais\n", ret);
+
+	return ret;
+}
+
+static int ipq4019_dai_remove(struct platform_device *pdev)
+{
+	snd_soc_unregister_component(&pdev->dev);
+	return 0;
+}
+
+static struct platform_driver ipq4019_dai_driver = {
+	.probe = ipq4019_dai_probe,
+	.remove = ipq4019_dai_remove,
+	.driver = {
+		.name = "qca-cpu-dai",
+		.of_match_table = ipq4019_cpu_dai_id_table,
+	},
+};
+
+module_platform_driver(ipq4019_dai_driver);
+
+MODULE_ALIAS("platform:qca-cpu-dai");
+MODULE_LICENSE("Dual BSD/GPL");
+MODULE_DESCRIPTION("IPQ4019 CPU DAI DRIVER");
diff --git a/sound/soc/qcom/ipq4019/ipq4019-mbox.c b/sound/soc/qcom/ipq4019/ipq4019-mbox.c
new file mode 100644
index 0000000..2a3bee9
--- /dev/null
+++ b/sound/soc/qcom/ipq4019/ipq4019-mbox.c
@@ -0,0 +1,825 @@
+/*
+ * Copyright (c) 2015-2016 The Linux Foundation. All rights reserved.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <linux/dma-mapping.h>
+#include <linux/types.h>
+#include <linux/module.h>
+#include <linux/mm.h>
+#include <linux/delay.h>
+#include <sound/soc.h>
+
+#include "ipq4019-mbox.h"
+
+/* When the mailbox operation is started, the mailbox would get one descriptor
+ * for the current data transfer and prefetch one more descriptor. When less
+ * than 3 descriptors are configured, then it is possible that before the CPU
+ * handles the interrupt, the mailbox could check the pre fetched descriptor
+ * and stop the DMA transfer.
+ * To handle this, the design is use multiple descriptors, but they would
+ * point to the same buffer address. This way  more number of descriptors
+ * would satisfy the mbox requirement, and reusing the buffer address would
+ * satisfy the upper layer's buffer requirement
+ *
+ * The value of 5 of repetition times was derived from trial and error testing
+ * for minimum number of repetitions that would result in MBOX operations
+ * without stopping.
+ */
+#define MBOX_MIN_DESC_NUM       3
+#define MBOX_DESC_REPEAT_NUM    5
+
+enum {
+	CHN_DISABLED = 0x00,
+	CHN_ENABLED = 0x01, /* from dtsi */
+	CHN_STARTED = 0x02, /* dma inited */
+	CHN_STATUS_DISABLE = 0xFF,
+};
+
+static struct ipq4019_mbox_rt_priv *mbox_rtime[ADSS_MBOX_NR_CHANNELS];
+
+struct ipq4019_mbox_desc
+	*ipq4019_mbox_get_last_played(unsigned int channel_id)
+{
+	struct ipq4019_mbox_desc *desc, *prev;
+	unsigned int ndescs, i;
+	uint32_t index;
+	uint32_t dir;
+
+	index = ipq4019_convert_id_to_channel(channel_id);
+	dir = ipq4019_convert_id_to_dir(channel_id);
+
+	if (!mbox_rtime[index])
+		return NULL;
+
+	ndescs = mbox_rtime[index]->dir_priv[dir].ndescs;
+	/* Point to the last desc */
+	prev = &mbox_rtime[index]->dir_priv[dir].dma_virt_head[ndescs - 1];
+
+	/* Point to the first desc */
+	desc = &mbox_rtime[index]->dir_priv[dir].dma_virt_head[0];
+
+	for (i = 0; i < ndescs; i++) {
+		if (desc->OWN == 1 && prev->OWN == 0)
+			return desc;
+		prev = desc;
+		desc += 1;
+	}
+
+	/* If we didn't find the last played buffer, return NULL */
+	return NULL;
+}
+EXPORT_SYMBOL(ipq4019_mbox_get_last_played);
+
+uint32_t ipq4019_mbox_get_elapsed_size(uint32_t channel_id)
+{
+	struct ipq4019_mbox_desc *desc;
+	unsigned int i, size_played = 0;
+	uint32_t index;
+	uint32_t dir;
+
+	index = ipq4019_convert_id_to_channel(channel_id);
+	dir = ipq4019_convert_id_to_dir(channel_id);
+
+	if (!mbox_rtime[index])
+		return size_played;
+
+	desc = mbox_rtime[index]->dir_priv[dir].dma_virt_head;
+
+	for (i = 0; i < mbox_rtime[index]->dir_priv[dir].ndescs; i++) {
+		if (desc->OWN == 0) {
+			desc->OWN = 1;
+			desc->ei = 1;
+			size_played += desc->size;
+		}
+		desc += 1;
+	}
+
+	return size_played;
+}
+EXPORT_SYMBOL(ipq4019_mbox_get_elapsed_size);
+
+static struct ipq4019_mbox_desc *get_next(
+					struct ipq4019_mbox_rt_dir_priv *rtdir,
+					struct ipq4019_mbox_desc *desc)
+{
+	struct ipq4019_mbox_desc *end;
+
+	end = rtdir->dma_virt_head + rtdir->ndescs;
+
+	desc++;
+
+	if (desc >= end)
+		desc = rtdir->dma_virt_head;
+
+	return desc;
+}
+
+void ipq4019_mbox_desc_own(u32 channel_id, int desc_no, int own)
+{
+	struct ipq4019_mbox_desc *desc;
+	struct ipq4019_mbox_rt_dir_priv *rtdir;
+	u32 chan;
+	u32 dir;
+
+	chan = ipq4019_convert_id_to_channel(channel_id);
+	dir = ipq4019_convert_id_to_dir(channel_id);
+
+	rtdir = &mbox_rtime[chan]->dir_priv[dir];
+
+	desc = rtdir->dma_virt_head;
+	desc += desc_no;
+
+	rtdir->write = desc_no;
+
+	desc->OWN = own;
+	desc->ei = 1;
+}
+EXPORT_SYMBOL(ipq4019_mbox_desc_own);
+
+u32 ipq4019_mbox_get_played_offset(u32 channel_id)
+{
+	struct ipq4019_mbox_desc *desc, *write;
+	struct ipq4019_mbox_rt_dir_priv *rtdir;
+	unsigned int i, size_played = 0;
+	u32 chan;
+	u32 dir;
+
+	chan = ipq4019_convert_id_to_channel(channel_id);
+	dir = ipq4019_convert_id_to_dir(channel_id);
+
+	rtdir = &mbox_rtime[chan]->dir_priv[dir];
+
+	desc = rtdir->dma_virt_head;
+	write = &rtdir->dma_virt_head[rtdir->write];
+
+	desc += rtdir->read;
+
+	for (i = 0; i < rtdir->ndescs; i++) {
+		if (desc->OWN == 0) {
+			size_played = desc->size;
+			rtdir->read = (rtdir->read + 1) % rtdir->ndescs;
+		} else {
+			break;
+		}
+
+		if (desc != write)
+			break;
+
+		desc = get_next(rtdir, desc);
+	}
+
+	return size_played * rtdir->read;
+}
+EXPORT_SYMBOL(ipq4019_mbox_get_played_offset);
+
+uint32_t ipq4019_mbox_get_played_offset_set_own(u32 channel_id)
+{
+	struct ipq4019_mbox_desc *desc, *last_played, *prev;
+	struct ipq4019_mbox_rt_dir_priv *rtdir;
+	unsigned int i, desc_own, size_played = 0;
+	u32 chan, dir;
+
+	chan = ipq4019_convert_id_to_channel(channel_id);
+	dir = ipq4019_convert_id_to_dir(channel_id);
+
+	rtdir = &mbox_rtime[chan]->dir_priv[dir];
+	last_played = NULL;
+
+	/* Point to the last desc */
+	prev = &rtdir->dma_virt_head[rtdir->ndescs - 1];
+	desc_own = prev->OWN;
+
+	/* point to first desc */
+	desc = &rtdir->dma_virt_head[0];
+
+	for (i = 0; i < rtdir->ndescs; i++) {
+		if (prev->OWN == 0) {
+			if (i == (rtdir->ndescs - 1)) {
+				if (desc_own == 1)
+					last_played = desc;
+			} else if (desc->OWN == 1) {
+				last_played = desc;
+			}
+			prev->OWN = 1;
+			prev->ei = 1;
+		}
+		prev = desc;
+		desc += 1;
+	}
+	if (last_played) {
+		desc = &rtdir->dma_virt_head[0];
+		size_played = last_played->BufPtr - desc->BufPtr;
+	} else {
+		pr_debug("%s last played buf not found\n", __func__);
+		rtdir->last_played_is_null++;
+	}
+
+	return size_played;
+}
+EXPORT_SYMBOL(ipq4019_mbox_get_played_offset_set_own);
+
+int ipq4019_mbox_fifo_reset(int channel_id)
+{
+	void __iomem *mbox_reg;
+	u32 chan, dir;
+
+	chan = ipq4019_convert_id_to_channel(channel_id);
+	dir = ipq4019_convert_id_to_dir(channel_id);
+
+	if (!mbox_rtime[chan])
+		return -EINVAL;
+
+	mbox_reg = mbox_rtime[chan]->mbox_reg_base;
+
+	switch (dir) {
+	case PLAYBACK:
+		writel(MBOX_FIFO_RESET_TX_INIT,
+			 mbox_reg + ADSS_MBOXn_MBOX_FIFO_RESET_REG);
+		break;
+	case CAPTURE:
+		writel(MBOX_FIFO_RESET_RX_INIT,
+			 mbox_reg + ADSS_MBOXn_MBOX_FIFO_RESET_REG);
+		break;
+	}
+
+	return 0;
+}
+EXPORT_SYMBOL(ipq4019_mbox_fifo_reset);
+
+int ipq4019_mbox_dma_start(int channel_id)
+{
+	void __iomem *mbox_reg;
+	u32 chan, dir;
+
+	chan = ipq4019_convert_id_to_channel(channel_id);
+	dir = ipq4019_convert_id_to_dir(channel_id);
+
+	if (!mbox_rtime[chan])
+		return -EINVAL;
+
+	mbox_reg = mbox_rtime[chan]->mbox_reg_base;
+	mbox_rtime[index]->mbox_started = 1;
+
+	switch (dir) {
+	case PLAYBACK:
+		writel(ADSS_MBOXn_DMA_RX_CONTROL_START,
+			mbox_reg + ADSS_MBOXn_MBOXn_DMA_RX_CONTROL_REG);
+		break;
+
+	case CAPTURE:
+		writel(ADSS_MBOXn_DMA_TX_CONTROL_START,
+			mbox_reg + ADSS_MBOXn_MBOXn_DMA_TX_CONTROL_REG);
+		break;
+	}
+
+	return 0;
+}
+EXPORT_SYMBOL(ipq4019_mbox_dma_start);
+
+int ipq4019_mbox_dma_resume(int channel_id)
+{
+	void __iomem *mbox_reg;
+	u32 chan, dir;
+
+	chan = ipq4019_convert_id_to_channel(channel_id);
+	dir = ipq4019_convert_id_to_dir(channel_id);
+
+	if (!mbox_rtime[chan])
+		return -EINVAL;
+
+	if (!mbox_rtime[index]->mbox_started)
+		return 0;
+
+	mbox_reg = mbox_rtime[chan]->mbox_reg_base;
+
+	switch (dir) {
+	case PLAYBACK:
+		writel(ADSS_MBOXn_DMA_RX_CONTROL_RESUME,
+			mbox_reg + ADSS_MBOXn_MBOXn_DMA_RX_CONTROL_REG);
+		break;
+
+	case CAPTURE:
+		writel(ADSS_MBOXn_DMA_TX_CONTROL_RESUME,
+			mbox_reg + ADSS_MBOXn_MBOXn_DMA_TX_CONTROL_REG);
+		break;
+	}
+
+	return 0;
+}
+EXPORT_SYMBOL(ipq4019_mbox_dma_resume);
+
+int ipq4019_mbox_dma_stop(int channel_id, u32 delay_in_ms)
+{
+	void __iomem *mbox_reg;
+	struct ipq4019_mbox_rt_dir_priv *mbox_cb;
+	u32 chan, dir;
+
+	chan = ipq4019_convert_id_to_channel(channel_id);
+	dir = ipq4019_convert_id_to_dir(channel_id);
+
+	if (!mbox_rtime[chan])
+		return -EINVAL;
+
+	mbox_reg = mbox_rtime[chan]->mbox_reg_base;
+	mbox_rtime[index]->mbox_started = 0;
+
+	switch (dir) {
+	case PLAYBACK:
+		writel(ADSS_MBOXn_DMA_RX_CONTROL_STOP,
+			mbox_reg + ADSS_MBOXn_MBOXn_DMA_RX_CONTROL_REG);
+		break;
+
+	case CAPTURE:
+		writel(ADSS_MBOXn_DMA_TX_CONTROL_STOP,
+			mbox_reg + ADSS_MBOXn_MBOXn_DMA_TX_CONTROL_REG);
+		break;
+	}
+
+	/*
+	 * Per the documentation:
+	 *	______________________________________________________
+	 *	Programming a one to this bit causes the DMA engine to
+	 *	stop transferring any more data from this descriptor
+	 *	chain.  If a transfer is already in progress DMA enters
+	 *	a stop state after completing the current descriptor
+	 *	______________________________________________________
+	 */
+	mdelay(delay_in_ms);
+
+	mbox_cb = &mbox_rtime[chan]->dir_priv[dir];
+	mbox_cb->read = 0;
+	mbox_cb->write = 0;
+
+	return 0;
+}
+EXPORT_SYMBOL(ipq4019_mbox_dma_stop);
+
+static bool ipq4019_is_other_chn_active(u32 chan, u32 dir)
+{
+	if (dir == PLAYBACK)
+		return (test_bit(CHN_STARTED,
+			&mbox_rtime[chan]->dir_priv[CAPTURE].status));
+	else
+		return (test_bit(CHN_STARTED,
+			&mbox_rtime[chan]->dir_priv[PLAYBACK].status));
+}
+
+int ipq4019_mbox_dma_reset_swap(int channel_id)
+{
+	unsigned int val;
+	void __iomem *mbox_reg;
+	u32 chan;
+
+	chan = ipq4019_convert_id_to_channel(channel_id);
+
+	if (!mbox_rtime[chan])
+		return -EINVAL;
+
+	mbox_reg = mbox_rtime[chan]->mbox_reg_base;
+
+	val = readl(mbox_reg + ADSS_MBOXn_MBOX_DMA_POLICY_REG);
+	val &= ~(MBOX_DMA_POLICY_RXD_END_SWAP | MBOX_DMA_POLICY_RXD_16BIT_SWAP);
+
+	writel(val, mbox_reg + ADSS_MBOXn_MBOX_DMA_POLICY_REG);
+
+	return 0;
+}
+EXPORT_SYMBOL(ipq4019_mbox_dma_reset_swap);
+
+int ipq4019_mbox_dma_swap(int channel_id, snd_pcm_format_t format)
+{
+	unsigned int val;
+	void __iomem *mbox_reg;
+	u32 chan;
+
+	chan = ipq4019_convert_id_to_channel(channel_id);
+
+	if (!mbox_rtime[chan])
+		return -EINVAL;
+
+	mbox_reg = mbox_rtime[chan]->mbox_reg_base;
+
+	val = readl(mbox_reg + ADSS_MBOXn_MBOX_DMA_POLICY_REG);
+	switch (format) {
+	case SNDRV_PCM_FORMAT_S16_LE:
+	case SNDRV_PCM_FORMAT_S16_BE:
+		val |= MBOX_DMA_POLICY_RXD_16BIT_SWAP;
+		break;
+	case SNDRV_PCM_FORMAT_S24_3LE:
+	case SNDRV_PCM_FORMAT_S24_3BE:
+		val |= MBOX_DMA_POLICY_RXD_END_SWAP;
+		break;
+	default:
+		/* Nothing to do */
+		break;
+	}
+	writel(val, mbox_reg + ADSS_MBOXn_MBOX_DMA_POLICY_REG);
+
+	return 0;
+}
+EXPORT_SYMBOL(ipq4019_mbox_dma_swap);
+
+static void ipq4019_mbox_intr_en(void __iomem *mbox_reg, unsigned int mask)
+{
+	unsigned int val;
+
+	val = readl(mbox_reg + ADSS_MBOXn_MBOX_INT_ENABLE_REG);
+	val |= mask;
+	writel(val, mbox_reg + ADSS_MBOXn_MBOX_INT_ENABLE_REG);
+}
+
+static void ipq4019_mbox_intr_disable(void __iomem *mbox_reg, unsigned int mask)
+{
+	unsigned int val;
+
+	val = readl(mbox_reg + ADSS_MBOXn_MBOX_INT_ENABLE_REG);
+	val &= ~mask;
+	writel(val, mbox_reg + ADSS_MBOXn_MBOX_INT_ENABLE_REG);
+}
+
+int ipq4019_mbox_dma_prepare(int channel_id)
+{
+	struct ipq4019_mbox_desc *desc;
+	unsigned int val;
+	void __iomem *mbox_reg;
+	dma_addr_t phys_addr;
+	u32 chan, dir;
+	struct ipq4019_mbox_rt_dir_priv *mbox_cb;
+
+	chan = ipq4019_convert_id_to_channel(channel_id);
+	dir = ipq4019_convert_id_to_dir(channel_id);
+
+	if (!mbox_rtime[chan])
+		return -EINVAL;
+
+	mbox_reg = mbox_rtime[chan]->mbox_reg_base;
+	mbox_cb = &mbox_rtime[chan]->dir_priv[dir];
+
+	/* do not reset DMA registers if the other direction is active */
+	if (!ipq4019_is_other_chn_active(chan, dir)) {
+
+		val = readl(mbox_reg + ADSS_MBOXn_MBOX_DMA_POLICY_REG);
+		val |= MBOX_DMA_POLICY_SW_RESET;
+		writel(val, mbox_reg + ADSS_MBOXn_MBOX_DMA_POLICY_REG);
+		val &= ~MBOX_DMA_POLICY_SW_RESET;
+		writel(val, mbox_reg + ADSS_MBOXn_MBOX_DMA_POLICY_REG);
+	}
+
+	desc = mbox_cb->dma_virt_head;
+	phys_addr = mbox_cb->dma_phys_head;
+	val = readl(mbox_reg + ADSS_MBOXn_MBOX_DMA_POLICY_REG);
+
+	if (dir == PLAYBACK) {
+		/* Request the DMA channel to the controller */
+		val |= MBOX_DMA_POLICY_RX_INT_TYPE;
+
+		/* The direction is indicated from the DMA engine perspective
+		 * i.e. we'll be using the RX registers for Playback and
+		 * the TX registers for capture
+		 */
+
+		val |= ADSS_MBOX_DMA_POLICY_SRAM_AC(phys_addr);
+		writel(val, mbox_reg + ADSS_MBOXn_MBOX_DMA_POLICY_REG);
+		writel(phys_addr & MBOX_DMA_MASK,
+			mbox_reg + ADSS_MBOXn_MBOXn_DMA_RX_DESCRIPTOR_BASE_REG);
+		ipq4019_mbox_intr_en(mbox_reg, MBOX_INT_ENABLE_RX_DMA_COMPLETE);
+	} else {
+
+		val |= MBOX_DMA_POLICY_TX_INT_TYPE |
+			ADSS_MBOX_DMA_POLICY_TX_FIFO_THRESHOLD(6);
+		val |= ADSS_MBOX_DMA_POLICY_SRAM_AC(phys_addr);
+		writel(val, mbox_reg + ADSS_MBOXn_MBOX_DMA_POLICY_REG);
+		writel(phys_addr & MBOX_DMA_MASK,
+			mbox_reg + ADSS_MBOXn_MBOXn_DMA_TX_DESCRIPTOR_BASE_REG);
+		ipq4019_mbox_intr_en(mbox_reg, MBOX_INT_ENABLE_TX_DMA_COMPLETE);
+	}
+
+	return 0;
+}
+EXPORT_SYMBOL(ipq4019_mbox_dma_prepare);
+
+void ipq4019_mbox_vuc_setup(int channel_id)
+{
+	uint32_t index, dir;
+	struct ipq4019_mbox_desc *desc;
+	int ndescs;
+	int i;
+
+	index = ipq4019_convert_id_to_channel(channel_id);
+	dir = ipq4019_convert_id_to_dir(channel_id);
+	ndescs = mbox_rtime[index]->dir_priv[dir].ndescs;
+	desc = mbox_rtime[index]->dir_priv[dir].dma_virt_head;
+
+	/* Copy VUC from previous descriptors */
+	for (i = 0; i < ndescs; i++) {
+		/* Setup V bits as 1, Acc to IEC 60958-3 Standard
+		 *    for non PCM data, we need to set invalid for
+		 *     both channels
+		 * There are 6 DWORDS (192 bits) for Channel A
+		 * and 6 DWORDS (192 bits) for channel B
+		 */
+		desc[i].vuc_dword[CHANNEL_A_VDWORD_1] = ADSS_MBOX_INVALID_PCM;
+		desc[i].vuc_dword[CHANNEL_A_VDWORD_2] = ADSS_MBOX_INVALID_PCM;
+		desc[i].vuc_dword[CHANNEL_A_VDWORD_3] = ADSS_MBOX_INVALID_PCM;
+		desc[i].vuc_dword[CHANNEL_A_VDWORD_4] = ADSS_MBOX_INVALID_PCM;
+		desc[i].vuc_dword[CHANNEL_A_VDWORD_5] = ADSS_MBOX_INVALID_PCM;
+		desc[i].vuc_dword[CHANNEL_A_VDWORD_6] = ADSS_MBOX_INVALID_PCM;
+		desc[i].vuc_dword[CHANNEL_B_VDWORD_1] = ADSS_MBOX_INVALID_PCM;
+		desc[i].vuc_dword[CHANNEL_B_VDWORD_2] = ADSS_MBOX_INVALID_PCM;
+		desc[i].vuc_dword[CHANNEL_B_VDWORD_3] = ADSS_MBOX_INVALID_PCM;
+		desc[i].vuc_dword[CHANNEL_B_VDWORD_4] = ADSS_MBOX_INVALID_PCM;
+		desc[i].vuc_dword[CHANNEL_B_VDWORD_5] = ADSS_MBOX_INVALID_PCM;
+		desc[i].vuc_dword[CHANNEL_B_VDWORD_6] = ADSS_MBOX_INVALID_PCM;
+
+		/* Now setup C bits, acc to IEC-60958-3 */
+		desc[i].vuc_dword[CHANNEL_A_CDWORD_1] = SPDIF_CONSUMER_COMPRESD;
+		desc[i].vuc_dword[CHANNEL_B_CDWORD_2] = SPDIF_CONSUMER_COMPRESD;
+	}
+}
+EXPORT_SYMBOL(ipq4019_mbox_vuc_setup);
+
+int ipq4019_mbox_form_ring(int channel_id, dma_addr_t baseaddr, u8 *area,
+			   int period_bytes, int bufsize, int own_bit)
+{
+	struct ipq4019_mbox_desc *desc, *_desc_p;
+	dma_addr_t desc_p, baseaddr_const;
+	unsigned int i, ndescs;
+	u32 chan, dir;
+	struct ipq4019_mbox_rt_dir_priv *mbox_cb;
+
+	chan = ipq4019_convert_id_to_channel(channel_id);
+	dir = ipq4019_convert_id_to_dir(channel_id);
+
+	if (!mbox_rtime[chan])
+		return -EINVAL;
+
+	mbox_cb = &mbox_rtime[chan]->dir_priv[dir];
+	ndescs = DIV_ROUND_UP(bufsize, period_bytes);
+
+	if (ndescs < MBOX_MIN_DESC_NUM)
+		ndescs *= MBOX_DESC_REPEAT_NUM;
+
+	desc = (struct ipq4019_mbox_desc *)(area + (ndescs * period_bytes));
+	desc_p = baseaddr + (ndescs * period_bytes);
+
+	memset(desc, 0, ndescs * sizeof(struct ipq4019_mbox_desc));
+
+	mbox_cb->read = 0;
+	mbox_cb->write = 0;
+	mbox_cb->ndescs = ndescs;
+	mbox_cb->dma_virt_head = desc;
+	mbox_cb->dma_phys_head = desc_p;
+	_desc_p = (struct ipq4019_mbox_desc *)desc_p;
+
+	baseaddr_const = baseaddr;
+
+	for (i = 0; i < ndescs; i++, desc++) {
+		desc->OWN = own_bit;
+		desc->ei = 1;
+		desc->BufPtr = baseaddr & MBOX_DMA_MASK;
+		desc->NextPtr = (unsigned long)&_desc_p[(i + 1) % ndescs];
+		desc->size = period_bytes;
+		desc->length = desc->size;
+		baseaddr += ALIGN(period_bytes, L1_CACHE_BYTES);
+		if (baseaddr >= (baseaddr_const + bufsize)) {
+			if (bufsize % period_bytes)
+				desc->size = bufsize % period_bytes;
+			else
+				desc->size = period_bytes;
+
+			baseaddr = baseaddr_const;
+		}
+	}
+
+	return 0;
+}
+EXPORT_SYMBOL(ipq4019_mbox_form_ring);
+
+int ipq4019_mbox_dma_release(int channel_id)
+{
+	u32 chan, dir;
+	struct ipq4019_mbox_rt_dir_priv *mbox_cb;
+
+	chan = ipq4019_convert_id_to_channel(channel_id);
+	dir = ipq4019_convert_id_to_dir(channel_id);
+	mbox_cb = &mbox_rtime[chan]->dir_priv[dir];
+
+	if (test_bit(CHN_STARTED, &mbox_cb->status)) {
+		ipq4019_mbox_intr_disable(mbox_rtime[chan]->mbox_reg_base,
+				(MBOX_INT_ENABLE_TX_DMA_COMPLETE |
+					MBOX_INT_ENABLE_RX_DMA_COMPLETE));
+		/*
+		 * ALSA framework calls ipq4019_mbox_dma_stop() before
+		 * calling close API.
+		 */
+		mbox_cb->dma_virt_head = NULL;
+
+		clear_bit(CHN_STARTED, &mbox_cb->status);
+		return 0;
+	}
+
+	return -ENXIO;
+}
+EXPORT_SYMBOL(ipq4019_mbox_dma_release);
+
+static void irq_proc_status(struct ipq4019_mbox_rt_dir_priv *priv, int irq,
+			    u32 status, int cb, int stats, u32 *mask, u32 bit)
+{
+	if (status & bit) {
+		*mask |= bit;
+		if (cb && priv->callback)
+			priv->callback(irq, priv->dai_priv);
+
+		if (stats)
+			priv->err_stats++;
+	}
+}
+
+static irqreturn_t ipq4019_mbox_dma_irq(int irq, void *dev_id)
+{
+	unsigned int status, mask = 0;
+	struct ipq4019_mbox_rt_priv *curr_rtime = dev_id;
+	void __iomem *mbox_reg = curr_rtime->mbox_reg_base;
+	struct ipq4019_mbox_rt_dir_priv *p = &curr_rtime->dir_priv[PLAYBACK];
+	struct ipq4019_mbox_rt_dir_priv *c = &curr_rtime->dir_priv[CAPTURE];
+
+	status = readl(mbox_reg + ADSS_MBOXn_MBOX_INT_STATUS_REG);
+
+	irq_proc_status(p, irq, status, 1, 0, &mask,
+					MBOX_INT_STATUS_RX_DMA_COMPLETE);
+	irq_proc_status(c, irq, status, 1, 0, &mask,
+					MBOX_INT_STATUS_TX_DMA_COMPLETE);
+	irq_proc_status(p, irq, status, 0, 1, &mask,
+					MBOX_INT_STATUS_RX_UNDERFLOW);
+	irq_proc_status(p, irq, status, 0, 1, &mask,
+					MBOX_INT_STATUS_RX_FIFO_UNDERFLOW);
+	irq_proc_status(c, irq, status, 0, 1, &mask,
+					MBOX_INT_STATUS_TX_OVERFLOW);
+	irq_proc_status(c, irq, status, 0, 1, &mask,
+					MBOX_INT_STATUS_TX_FIFO_OVERFLOW);
+
+	if (mask) {
+		writel(status & ~mask,
+				mbox_reg + ADSS_MBOXn_MBOX_INT_STATUS_REG);
+		return IRQ_HANDLED;
+	}
+
+	return IRQ_NONE;
+}
+
+int ipq4019_mbox_dma_deinit(u32 channel_id)
+{
+	u32 chan, dir;
+	struct ipq4019_mbox_rt_dir_priv *mbox_cb;
+
+	chan = ipq4019_convert_id_to_channel(channel_id);
+	dir = ipq4019_convert_id_to_dir(channel_id);
+
+	mbox_cb = &mbox_rtime[chan]->dir_priv[dir];
+	if (test_bit(CHN_STARTED, &mbox_cb->status))
+		clear_bit(CHN_STARTED, &mbox_cb->status);
+
+	mbox_cb->dai_priv = NULL;
+	mbox_cb->callback = NULL;
+	mbox_cb->dev = NULL;
+
+	return 0;
+}
+EXPORT_SYMBOL(ipq4019_mbox_dma_deinit);
+
+int ipq4019_mbox_dma_init(struct device *dev, int channel_id,
+			irq_handler_t callback, void *private_data)
+{
+	u32 chan;
+	u32 dir;
+	struct ipq4019_mbox_rt_dir_priv *mbox_cb;
+
+	chan = ipq4019_convert_id_to_channel(channel_id);
+	dir = ipq4019_convert_id_to_dir(channel_id);
+
+	if (chan  >= ADSS_MBOX_NR_CHANNELS)
+		return -EINVAL;
+
+	if (!mbox_rtime[chan])
+		return -EINVAL;
+
+	mbox_cb = &mbox_rtime[chan]->dir_priv[dir];
+
+	if (!(mbox_cb->status & CHN_ENABLED))
+		return -EINVAL;
+
+	if (test_and_set_bit(CHN_STARTED, &mbox_cb->status))
+		return -EBUSY;
+
+	mbox_cb->dai_priv = private_data;
+	mbox_cb->callback = callback;
+	mbox_cb->dev = dev;
+
+	return 0;
+}
+EXPORT_SYMBOL(ipq4019_mbox_dma_init);
+
+static int ipq4019_mbox_probe(struct platform_device *pdev)
+{
+	struct device_node *np;
+	int irq;
+	u32 tx_channel;
+	u32 rx_channel;
+	u32 id;
+	void __iomem *reg_base;
+	struct resource *res;
+	int rc;
+
+	np = pdev->dev.of_node;
+
+	if (of_property_read_u32(np, "dma-index", &id)) {
+		dev_err(&pdev->dev,
+			"unable to read (dma-index) from device node %s\n",
+			np->name);
+		return -EINVAL;
+	}
+
+	if (id >= ADSS_MBOX_NR_CHANNELS)
+		return -EINVAL;
+
+	if (of_property_read_u32(np, "tx-channel", &tx_channel))
+		tx_channel = CHN_STATUS_DISABLE;
+
+	if (of_property_read_u32(np, "rx-channel", &rx_channel))
+		rx_channel = CHN_STATUS_DISABLE;
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!res) {
+		dev_err(&pdev->dev, "%s: %d: Error getting mbox resource\n",
+						__func__, __LINE__);
+		return -EINVAL;
+	}
+
+	/*
+	 * Read interrupt and store
+	 */
+	irq = platform_get_irq(pdev, 0);
+	if (irq < 0) {
+		dev_err(&pdev->dev, "%s: MBOX %d IRQ %d is not provided\n",
+						__func__, id, irq);
+		return irq;
+	}
+
+	reg_base = devm_ioremap_resource(&pdev->dev, res);
+	if (IS_ERR(reg_base))
+		return PTR_ERR(reg_base);
+
+	mbox_rtime[id] = devm_kzalloc(&pdev->dev,
+			sizeof(struct ipq4019_mbox_rt_priv), GFP_KERNEL);
+	if (!mbox_rtime[id])
+		return -ENOMEM;
+
+	rc = devm_request_irq(&pdev->dev, irq, ipq4019_mbox_dma_irq, 0,
+				"ipq4019-mbox", mbox_rtime[id]);
+	if (rc) {
+		dev_err(&pdev->dev, "request_irq() failed with ret: %d\n", rc);
+		return rc;
+	}
+
+	mbox_rtime[id]->mbox_reg_base = reg_base;
+	mbox_rtime[id]->dir_priv[PLAYBACK].channel_id = tx_channel;
+	mbox_rtime[id]->dir_priv[CAPTURE].channel_id = rx_channel;
+	mbox_rtime[id]->dir_priv[PLAYBACK].status =
+		(tx_channel == CHN_STATUS_DISABLE) ? CHN_DISABLED : CHN_ENABLED;
+	mbox_rtime[id]->dir_priv[CAPTURE].status =
+		(rx_channel == CHN_STATUS_DISABLE) ? CHN_DISABLED : CHN_ENABLED;
+	mbox_rtime[id]->irq_no = irq;
+
+	return 0;
+}
+
+static const struct of_device_id ipq4019_mbox_table[] = {
+	{ .compatible = "qca,ipq4019-mbox" },
+	{},
+};
+
+static struct platform_driver ipq4019_mbox_driver = {
+	.probe = ipq4019_mbox_probe,
+	.driver = {
+		.name = "ipq4019-mbox",
+		.of_match_table = ipq4019_mbox_table,
+	},
+};
+
+module_platform_driver(ipq4019_mbox_driver);
+
+MODULE_ALIAS("platform:ipq4019-mbox");
+MODULE_LICENSE("Dual BSD/GPL");
+MODULE_DESCRIPTION("IPQ4019 MBOX DRIVER");
diff --git a/sound/soc/qcom/ipq4019/ipq4019-mbox.h b/sound/soc/qcom/ipq4019/ipq4019-mbox.h
new file mode 100644
index 0000000..f2e5ede
--- /dev/null
+++ b/sound/soc/qcom/ipq4019/ipq4019-mbox.h
@@ -0,0 +1,146 @@
+/*
+ * Copyright (c) 2015-2016 The Linux Foundation. All rights reserved.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef _IPQ4019_MBOX_H_
+#define _IPQ4019_MBOX_H_
+
+#include "ipq4019-adss.h"
+
+#define ADSS_MBOX_INVALID_PCM			(0xFFFFFFFF)
+#define ADSS_MBOX_REG_BASE			(0x7700000 + 0x6000)
+#define ADSS_MBOX_RANGE				(0xFA000)
+#define ADSS_MBOX_SPDIF_IRQ			(163 + 32)
+#define ADSS_MBOX0_IRQ				(156 + 32)
+#define ADSS_MBOX1_IRQ				(157 + 32)
+#define ADSS_MBOX2_IRQ				(158 + 32)
+#define ADSS_MBOX3_IRQ				(159 + 32)
+
+#define CHANNEL_A_VDWORD_START 0
+#define CHANNEL_B_VDWORD_START 18
+
+#define CHANNEL_A_VDWORD_1 (CHANNEL_A_VDWORD_START + 0)
+#define CHANNEL_A_VDWORD_2 (CHANNEL_A_VDWORD_START + 1)
+#define CHANNEL_A_VDWORD_3 (CHANNEL_A_VDWORD_START + 2)
+#define CHANNEL_A_VDWORD_4 (CHANNEL_A_VDWORD_START + 3)
+#define CHANNEL_A_VDWORD_5 (CHANNEL_A_VDWORD_START + 4)
+#define CHANNEL_A_VDWORD_6 (CHANNEL_A_VDWORD_START + 5)
+
+#define CHANNEL_B_VDWORD_1 (CHANNEL_B_VDWORD_START + 0)
+#define CHANNEL_B_VDWORD_2 (CHANNEL_B_VDWORD_START + 1)
+#define CHANNEL_B_VDWORD_3 (CHANNEL_B_VDWORD_START + 2)
+#define CHANNEL_B_VDWORD_4 (CHANNEL_B_VDWORD_START + 3)
+#define CHANNEL_B_VDWORD_5 (CHANNEL_B_VDWORD_START + 4)
+#define CHANNEL_B_VDWORD_6 (CHANNEL_B_VDWORD_START + 5)
+
+#define CHANNEL_A_CDWORD_START 12
+#define CHANNEL_B_CDWORD_START 30
+
+#define CHANNEL_A_CDWORD_1 (CHANNEL_A_CDWORD_START + 0)
+#define CHANNEL_B_CDWORD_2 (CHANNEL_B_CDWORD_START + 0)
+
+/* Acc to IEC 60958-3, bit 0.0 = 0 is consumer
+ *		       bit 0.1 = 1is compressed playback
+ *		       bit 3.0 = 1 is sampling freq No specified
+ */
+#define SPDIF_CONSUMER_COMPRESD 0x01000006
+#define MBOX_MIN_DESC_NUM	3
+#define MBOX_DESC_REPEAT_NUM	5
+
+enum {
+	ADSS_MBOX_NR_CHANNELS = 5,
+};
+
+struct ipq4019_mbox_desc {
+	unsigned int	length	: 12,	/* bit 11-00 */
+			size	: 12,	/* bit 23-12 */
+			vuc	: 1,	/* bit 24 */
+			ei	: 1,	/* bit 25 */
+			rsvd1	: 4,	/* bit 29-26 */
+			EOM	: 1,	/* bit 30 */
+			OWN	: 1,	/* bit 31 */
+			BufPtr	: 28,   /* bit 27-00 */
+			rsvd2	:  4,   /* bit 31-28 */
+			NextPtr	: 28,   /* bit 27-00 */
+			rsvd3	:  4;   /* bit 31-28 */
+
+	unsigned int vuc_dword[36];
+};
+
+#define MBOX_DMA_MASK		DMA_BIT_MASK(28)
+
+struct ipq4019_mbox_rt_dir_priv {
+	/* Desc array in virtual space */
+	struct ipq4019_mbox_desc *dma_virt_head;
+
+	/* Desc array for DMA */
+	dma_addr_t dma_phys_head;
+	struct device *dev;
+	unsigned int ndescs;
+	irq_handler_t callback;
+	void *dai_priv;
+	unsigned long status;
+	u32 channel_id;
+	u32 err_stats;
+	u32 last_played_is_null;
+	u32 write;
+	u32 read;
+};
+
+struct ipq4019_mbox_rt_priv {
+	int irq_no;
+	void __iomem *mbox_reg_base;
+	struct ipq4019_mbox_rt_dir_priv dir_priv[2];
+	int mbox_started;
+};
+
+/* Replaces struct ath_i2s_softc */
+struct ipq4019_pcm_pltfm_priv {
+	struct snd_pcm_substream *playback;
+	struct snd_pcm_substream *capture;
+};
+
+int ipq4019_mbox_fifo_reset(int channel_id);
+int ipq4019_mbox_dma_start(int channel_id);
+int ipq4019_mbox_dma_stop(int channel_id, u32 delay_in_ms);
+int ipq4019_mbox_dma_reset_swap(int channel_id);
+int ipq4019_mbox_dma_swap(int channel_id, snd_pcm_format_t format);
+int ipq4019_mbox_dma_prepare(int channel_id);
+int ipq4019_mbox_dma_resume(int channel_id);
+int ipq4019_mbox_form_ring(int channel_id, dma_addr_t baseaddr, u8 *base,
+				int period_bytes, int bufsize, int own_bit);
+int ipq4019_mbox_dma_release(int channel);
+int ipq4019_mbox_dma_init(struct device *dev, int channel_id,
+	irq_handler_t callback, void *private_data);
+void ipq4019_mbox_vuc_setup(int channel_id);
+u32 ipq4019_mbox_get_played_offset(u32 channel_id);
+int ipq4019_mbox_dma_deinit(u32 channel_id);
+void ipq4019_mbox_desc_own(u32 channel_id, int desc_no, int own);
+struct ipq4019_mbox_desc *ipq4019_mbox_get_last_played(unsigned int channel_id);
+uint32_t ipq4019_mbox_get_elapsed_size(uint32_t channel_id);
+void ipq4019_mbox_vuc_setup(int channel_id);
+uint32_t ipq4019_mbox_get_played_offset_set_own(u32 channel_id);
+
+static inline u32 ipq4019_convert_id_to_channel(u32 id)
+{
+	return (id / 2);
+}
+
+static inline u32 ipq4019_convert_id_to_dir(u32 id)
+{
+	return (id % 2);
+}
+
+#endif /* _IPQ40XX_MBOX_H_ */
diff --git a/sound/soc/qcom/ipq4019/ipq4019-pcm-i2s.c b/sound/soc/qcom/ipq4019/ipq4019-pcm-i2s.c
new file mode 100644
index 0000000..e93d999
--- /dev/null
+++ b/sound/soc/qcom/ipq4019/ipq4019-pcm-i2s.c
@@ -0,0 +1,609 @@
+/*
+ * Copyright (c) 2015-2016 The Linux Foundation. All rights reserved.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ */
+
+#include <linux/init.h>
+#include <linux/err.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/time.h>
+#include <linux/wait.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/dma-mapping.h>
+#include <asm/dma.h>
+#include <sound/core.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include <sound/pcm.h>
+#include <sound/initval.h>
+#include <sound/control.h>
+#include <sound/pcm_params.h>
+
+#include "ipq4019-adss.h"
+#include "ipq4019-pcm.h"
+
+static struct snd_pcm_hardware ipq4019_pcm_hardware_playback = {
+	.info			=	SNDRV_PCM_INFO_MMAP |
+					SNDRV_PCM_INFO_BLOCK_TRANSFER |
+					SNDRV_PCM_INFO_MMAP_VALID |
+					SNDRV_PCM_INFO_INTERLEAVED |
+					SNDRV_PCM_INFO_PAUSE |
+					SNDRV_PCM_INFO_RESUME,
+	.formats		=	SNDRV_PCM_FMTBIT_S16 |
+					SNDRV_PCM_FMTBIT_S32,
+	.rates			=	RATE_16000_96000,
+	.rate_min		=	FREQ_16000,
+	.rate_max		=	FREQ_96000,
+	.channels_min		=	CH_STEREO,
+	.channels_max		=	CH_STEREO,
+	.buffer_bytes_max	=	IPQ4019_I2S_BUFF_SIZE,
+	.period_bytes_max	=	IPQ4019_I2S_BUFF_SIZE / 2,
+	.period_bytes_min	=	IPQ4019_I2S_PERIOD_BYTES_MIN,
+	.periods_min		=	IPQ4019_I2S_NO_OF_PERIODS,
+	.periods_max		=	IPQ4019_I2S_NO_OF_PERIODS,
+	.fifo_size		=	0,
+};
+
+static struct snd_pcm_hardware ipq4019_pcm_hardware_capture = {
+	.info			=	SNDRV_PCM_INFO_MMAP |
+					SNDRV_PCM_INFO_BLOCK_TRANSFER |
+					SNDRV_PCM_INFO_MMAP_VALID |
+					SNDRV_PCM_INFO_INTERLEAVED,
+	.formats		=	SNDRV_PCM_FMTBIT_S16 |
+					SNDRV_PCM_FMTBIT_S32,
+	.rates			=	RATE_16000_96000,
+	.rate_min		=	FREQ_16000,
+	.rate_max		=	FREQ_96000,
+	.channels_min		=	CH_STEREO,
+	.channels_max		=	CH_STEREO,
+	.buffer_bytes_max	=	IPQ4019_I2S_BUFF_SIZE,
+	.period_bytes_max	=	IPQ4019_I2S_BUFF_SIZE / 2,
+	.period_bytes_min	=	IPQ4019_I2S_PERIOD_BYTES_MIN,
+	.periods_min		=	IPQ4019_I2S_NO_OF_PERIODS,
+	.periods_max		=	IPQ4019_I2S_NO_OF_PERIODS,
+	.fifo_size		=	0,
+};
+
+static size_t ip4019_dma_buffer_size(struct snd_pcm_hardware *pcm_hw)
+{
+	return (pcm_hw->buffer_bytes_max +
+		(pcm_hw->periods_min * sizeof(struct ipq4019_mbox_desc)));
+}
+
+static struct device *ss2dev(struct snd_pcm_substream *substream)
+{
+	return substream->pcm->card->dev;
+}
+
+/*
+ * The MBOX descriptors and buffers should lie within the same 256MB
+ * region. Because, the buffer address pointer (in the descriptor structure)
+ * and descriptor base address pointer register share the same MSB 4 bits
+ * which is configured in MBOX DMA Policy register.
+ *
+ * Hence ensure that the entire allocated region falls in a 256MB region.
+ */
+static int ipq4019_mbox_buf_is_aligned(void *c_ptr, ssize_t size)
+{
+	u32 ptr = (u32)c_ptr;
+
+	return (ptr & 0xF0000000) == ((ptr + size - 1) & 0xF0000000);
+}
+
+static int ipq4019_pcm_preallocate_dma_buffer(struct snd_pcm *pcm,
+						int stream)
+{
+	struct snd_pcm_substream *substream = pcm->streams[stream].substream;
+	struct snd_pcm_hardware *pcm_hw = NULL;
+	struct snd_dma_buffer *buf = &substream->dma_buffer;
+	size_t size;
+	u8 *area;
+	dma_addr_t addr;
+
+	switch (substream->stream) {
+	case SNDRV_PCM_STREAM_PLAYBACK:
+		pcm_hw = &ipq4019_pcm_hardware_playback;
+		break;
+	case SNDRV_PCM_STREAM_CAPTURE:
+		pcm_hw = &ipq4019_pcm_hardware_capture;
+		break;
+	default:
+		dev_err(ss2dev(substream), "Invalid stream: %d\n",
+							substream->stream);
+		return -EINVAL;
+	}
+
+	size = ip4019_dma_buffer_size(pcm_hw);
+	buf->dev.type = SNDRV_DMA_TYPE_DEV;
+	buf->dev.dev = pcm->card->dev;
+	buf->private_data = NULL;
+
+	/*
+	 * |<--   buffers             -->|<-- desc  -->|
+	 * +----+----+----+----+----+----+-+-+-+-+-+-+-+
+	 * |    |    |    |    |    |    | | | | | | | |
+	 * |    |    |    |    |    |    | | | | | | | |
+	 * |    |    |    |    |    |    | | | | | | | |
+	 * |    |    |    |    |    |    | | | | | | | |
+	 * |    |    |    |    |    |    | | | | | | | |
+	 * +----+----+----+----+----+----+-+-+-+-+-+-+-+
+	 * ^    ^                        | |  . . .
+	 * |    |                        | |
+	 * +----|------------------------+ |
+	 *	+--------------------------+
+	 */
+
+	/*
+	 * Currently payload uses uncached memory.
+	 * TODO: Eventually we will move to cached memory for payload
+	 * and dma_map_single() will be used for Invalidating/Flushing
+	 * the buffers.
+	 */
+
+	area = dma_alloc_coherent(pcm->card->dev, size, &addr, GFP_KERNEL);
+
+	if (!area) {
+		dev_info(ss2dev(substream), "Alloc coherent memory failed\n");
+		return -ENOMEM;
+	}
+
+	if (!ipq4019_mbox_buf_is_aligned(area, size)) {
+		dev_info(ss2dev(substream),
+			 "First allocation %p not within 256M region\n", area);
+
+		buf->area = dma_alloc_coherent(pcm->card->dev, size,
+						&buf->addr, GFP_KERNEL);
+		/*
+		 * If we are here, the previously allocated buffer is not
+		 * usable for the driver. Have to free it anyway regardless
+		 * of the success/failure of the second allocation.
+		 */
+		dma_free_coherent(pcm->card->dev, size, area, addr);
+		if (!buf->area) {
+			dev_info(ss2dev(substream),
+				 "Second Alloc coherent memory failed\n");
+			return -ENOMEM;
+		}
+	} else {
+		buf->area = area;
+		buf->addr = addr;
+	}
+
+	buf->bytes = pcm_hw->buffer_bytes_max;
+
+	return 0;
+}
+
+static void ipq4019_pcm_free_dma_buffer(struct snd_pcm *pcm, int stream)
+{
+	struct snd_pcm_substream *substream;
+	struct snd_pcm_hardware *pcm_hw = NULL;
+	struct snd_dma_buffer *buf;
+	size_t size;
+
+	substream = pcm->streams[stream].substream;
+	buf = &substream->dma_buffer;
+
+	switch (stream) {
+	case SNDRV_PCM_STREAM_PLAYBACK:
+		pcm_hw = &ipq4019_pcm_hardware_playback;
+		break;
+	case SNDRV_PCM_STREAM_CAPTURE:
+		pcm_hw = &ipq4019_pcm_hardware_capture;
+		break;
+	default:
+		dev_err(ss2dev(substream), "Invalid stream: %d\n",
+							substream->stream);
+		return;
+	}
+
+	size = ip4019_dma_buffer_size(pcm_hw);
+
+	dma_free_coherent(pcm->card->dev, size, buf->area, buf->addr);
+
+	buf->addr = 0;
+	buf->area = NULL;
+
+}
+
+static irqreturn_t ipq4019_pcm_irq(int intrsrc, void *data)
+{
+	struct snd_pcm_substream *substream = data;
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct ipq4019_pcm_rt_priv *pcm_rtpriv = runtime->private_data;
+
+	if (pcm_rtpriv->mmap_flag)
+		pcm_rtpriv->curr_pos =
+			ipq4019_mbox_get_played_offset_set_own(
+						pcm_rtpriv->channel);
+	else
+		pcm_rtpriv->curr_pos =
+			ipq4019_mbox_get_played_offset(pcm_rtpriv->channel);
+
+	snd_pcm_period_elapsed(substream);
+
+	return IRQ_HANDLED;
+}
+
+static snd_pcm_uframes_t ipq4019_pcm_i2s_pointer(
+				struct snd_pcm_substream *substream)
+{
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct ipq4019_pcm_rt_priv *pcm_rtpriv = runtime->private_data;
+
+	return bytes_to_frames(runtime, pcm_rtpriv->curr_pos);
+}
+
+static int ipq4019_pcm_i2s_copy(struct snd_pcm_substream *substream, int chan,
+				snd_pcm_uframes_t hwoff, void __user *ubuf,
+				snd_pcm_uframes_t frames)
+{
+	struct snd_dma_buffer *buf = &substream->dma_buffer;
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct ipq4019_pcm_rt_priv *pcm_rtpriv = runtime->private_data;
+	char *hwbuf;
+	u32 offset, size;
+
+	offset = frames_to_bytes(runtime, hwoff);
+	size = frames_to_bytes(runtime, frames);
+
+	hwbuf = buf->area + offset;
+
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+		if (copy_from_user(hwbuf, ubuf, size))
+			return -EFAULT;
+	} else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
+		if (copy_to_user(ubuf, hwbuf, size))
+			return -EFAULT;
+	}
+
+	ipq4019_mbox_desc_own(pcm_rtpriv->channel, offset / size, 1);
+
+	ipq4019_mbox_dma_resume(pcm_rtpriv->channel);
+
+	return 0;
+}
+
+static int ipq4019_pcm_i2s_mmap(struct snd_pcm_substream *substream,
+				struct vm_area_struct *vma)
+{
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct ipq4019_pcm_rt_priv *pcm_rtpriv = runtime->private_data;
+
+	pcm_rtpriv->mmap_flag = 1;
+
+	return dma_mmap_coherent(substream->pcm->card->dev, vma,
+		runtime->dma_area, runtime->dma_addr, runtime->dma_bytes);
+}
+
+static int ipq4019_pcm_hw_free(struct snd_pcm_substream *substream)
+{
+	snd_pcm_set_runtime_buffer(substream, NULL);
+	return 0;
+}
+
+
+static int ipq4019_pcm_i2s_prepare(struct snd_pcm_substream *substream)
+{
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct ipq4019_pcm_rt_priv *pcm_rtpriv = runtime->private_data;
+	u32 ret;
+
+	ret = ipq4019_mbox_dma_prepare(pcm_rtpriv->channel);
+	if (ret) {
+		dev_err(ss2dev(substream),
+			"Error in dma prepare: channel: %d ret: %d\n",
+			pcm_rtpriv->channel, ret);
+		return ret;
+	}
+
+	pcm_rtpriv->last_played = NULL;
+
+	return 0;
+}
+
+static int ipq4019_pcm_i2s_close(struct snd_pcm_substream *substream)
+{
+	struct ipq4019_pcm_rt_priv *pcm_rtpriv =
+				substream->runtime->private_data;
+	u32 ret;
+
+	pcm_rtpriv->mmap_flag = 0;
+
+	ret = ipq4019_mbox_dma_release(pcm_rtpriv->channel);
+	if (ret)
+		dev_err(ss2dev(substream),
+			"Error in dma release. ret: %d\n", ret);
+
+	kfree(pcm_rtpriv);
+
+	return 0;
+}
+
+static int ipq4019_pcm_i2s_trigger(struct snd_pcm_substream *substream, int cmd)
+{
+	int ret;
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct ipq4019_pcm_rt_priv *pcm_rtpriv = runtime->private_data;
+	u32 desc_duration;
+
+	switch (cmd) {
+	case SNDRV_PCM_TRIGGER_START:
+	case SNDRV_PCM_TRIGGER_RESUME:
+		ret = ipq4019_mbox_dma_start(pcm_rtpriv->channel);
+		if (ret) {
+			dev_err(ss2dev(substream),
+				"Error in dma start. ret: %d\n", ret);
+		}
+		break;
+	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+		ret = ipq4019_mbox_dma_resume(pcm_rtpriv->channel);
+		if (ret) {
+			dev_err(ss2dev(substream),
+				"Error in dma resume. ret: %d\n", ret);
+		}
+		break;
+	case SNDRV_PCM_TRIGGER_STOP:
+	case SNDRV_PCM_TRIGGER_SUSPEND:
+	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+		/*
+		 * For e.g. the number of bytes needed to represent 1 second
+		 * worth of audio data for sampling frequency, bit width, stereo
+		 * combination of 16KHz, 32-bits and stereo, the calculation is
+		 * as follows
+		 *
+		 * For 1 second,
+		 *	16KHz * 32 bits * 2 (left & right channel of stereo)
+		 *	= 16000 * 4 bytes * 2
+		 *	= 128000 bytes
+		 *
+		 * Hence the duration will be
+		 *	desc_buffer_size_in_bytes / 128000 * 1 sec
+		 */
+		desc_duration =
+			frames_to_bytes(runtime, runtime->period_size) * 1000 /
+				(runtime->rate *
+				 DIV_ROUND_UP(runtime->sample_bits, 8) *
+				 runtime->channels);
+
+		dev_dbg(ss2dev(substream),
+			"period_size:%u rate:%u sample_bits:%u channels:%u desc_delay:%u\n",
+			frames_to_bytes(runtime, runtime->period_size),
+			runtime->rate, runtime->sample_bits, runtime->channels,
+			desc_duration);
+
+		ret = ipq4019_mbox_dma_stop(pcm_rtpriv->channel, desc_duration);
+		if (ret) {
+			dev_err(ss2dev(substream),
+				"Error in dma stop. ret: %d\n", ret);
+		}
+		break;
+	default:
+		ret = -EINVAL;
+		break;
+	}
+	return ret;
+}
+
+static int ipq4019_pcm_i2s_hw_params(struct snd_pcm_substream *substream,
+				struct snd_pcm_hw_params *hw_params)
+{
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct ipq4019_pcm_rt_priv *pcm_rtpriv = runtime->private_data;
+	int ret;
+	unsigned int period_size, sample_size, sample_rate, frames, channels;
+
+	ret = ipq4019_mbox_form_ring(pcm_rtpriv->channel,
+			substream->dma_buffer.addr,
+			substream->dma_buffer.area,
+			params_period_bytes(hw_params),
+			params_buffer_bytes(hw_params),
+			(substream->stream == SNDRV_PCM_STREAM_CAPTURE));
+	if (ret) {
+		dev_dbg(ss2dev(substream),
+			"Error dma form ring ret: %d\n", ret);
+		return ret;
+	}
+
+	period_size = params_period_bytes(hw_params);
+	sample_size = snd_pcm_format_size(params_format(hw_params), 1);
+	sample_rate = params_rate(hw_params);
+	channels = params_channels(hw_params);
+	frames = period_size / (sample_size * channels);
+
+	pcm_rtpriv->period_size = params_period_bytes(hw_params);
+
+	snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer);
+
+	runtime->dma_bytes = params_buffer_bytes(hw_params);
+	return 0;
+}
+
+static int ipq4019_pcm_i2s_open(struct snd_pcm_substream *substream)
+{
+	int ret;
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct ipq4019_pcm_rt_priv *pcm_rtpriv;
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct snd_soc_dai *dai = rtd->cpu_dai;
+	u32 intf = dai->driver->id;
+
+	pcm_rtpriv = kmalloc(sizeof(struct ipq4019_pcm_rt_priv), GFP_KERNEL);
+	if (!pcm_rtpriv)
+		return -ENOMEM;
+
+	dev_dbg(ss2dev(substream), "%s: 0x%xB allocated at 0x%08x\n",
+			__func__, sizeof(*pcm_rtpriv), (u32) pcm_rtpriv);
+	pcm_rtpriv->last_played = NULL;
+	pcm_rtpriv->dev = substream->pcm->card->dev;
+	pcm_rtpriv->channel = ipq4019_get_mbox_id(substream, intf);
+	pcm_rtpriv->curr_pos = 0;
+	pcm_rtpriv->mmap_flag = 0;
+	substream->runtime->private_data = pcm_rtpriv;
+
+	switch (substream->stream) {
+	case SNDRV_PCM_STREAM_PLAYBACK:
+		runtime->dma_bytes =
+			ipq4019_pcm_hardware_playback.buffer_bytes_max;
+		snd_soc_set_runtime_hwparams(substream,
+				&ipq4019_pcm_hardware_playback);
+		break;
+	case SNDRV_PCM_STREAM_CAPTURE:
+		runtime->dma_bytes =
+				ipq4019_pcm_hardware_capture.buffer_bytes_max;
+		snd_soc_set_runtime_hwparams(substream,
+					&ipq4019_pcm_hardware_capture);
+		break;
+	default:
+		dev_err(ss2dev(substream), "Invalid stream: %d\n",
+			substream->stream);
+		ret = -EINVAL;
+		goto error;
+	}
+
+	ret = ipq4019_mbox_dma_init(pcm_rtpriv->dev,
+		pcm_rtpriv->channel, ipq4019_pcm_irq, substream);
+	if (ret) {
+		dev_err(ss2dev(substream),
+			"Error initializing dma. ret: %d\n", ret);
+		goto error;
+	}
+
+	ret = snd_pcm_hw_constraint_integer(runtime,
+			SNDRV_PCM_HW_PARAM_PERIODS);
+	if (ret < 0) {
+		dev_err(ss2dev(substream),
+			"snd_pcm_hw_constraint_integer failed ret: %d\n",
+			ret);
+		goto error_hw_const;
+	}
+
+	return 0;
+error_hw_const:
+	ipq4019_mbox_dma_deinit(pcm_rtpriv->channel);
+error:
+	kfree(pcm_rtpriv);
+	return ret;
+}
+
+static struct snd_pcm_ops ipq4019_asoc_pcm_i2s_ops = {
+	.open		= ipq4019_pcm_i2s_open,
+	.hw_params	= ipq4019_pcm_i2s_hw_params,
+	.hw_free	= ipq4019_pcm_hw_free,
+	.trigger	= ipq4019_pcm_i2s_trigger,
+	.ioctl		= snd_pcm_lib_ioctl,
+	.close		= ipq4019_pcm_i2s_close,
+	.prepare	= ipq4019_pcm_i2s_prepare,
+	.mmap		= ipq4019_pcm_i2s_mmap,
+	.pointer	= ipq4019_pcm_i2s_pointer,
+	.copy		= ipq4019_pcm_i2s_copy,
+};
+
+static void ipq4019_asoc_pcm_i2s_free(struct snd_pcm *pcm)
+{
+	ipq4019_pcm_free_dma_buffer(pcm, SNDRV_PCM_STREAM_PLAYBACK);
+	ipq4019_pcm_free_dma_buffer(pcm, SNDRV_PCM_STREAM_CAPTURE);
+}
+
+static int ipq4019_asoc_pcm_i2s_new(struct snd_soc_pcm_runtime *prtd)
+{
+	struct snd_card *card = prtd->card->snd_card;
+	struct snd_pcm *pcm = prtd->pcm;
+	int ret = 0, pback = 0;
+
+	if (!card->dev->coherent_dma_mask)
+		card->dev->coherent_dma_mask = DMA_BIT_MASK(32);
+
+	if (!card->dev->dma_mask)
+		card->dev->dma_mask = &card->dev->coherent_dma_mask;
+
+	if (pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream) {
+		ret = ipq4019_pcm_preallocate_dma_buffer(pcm,
+				SNDRV_PCM_STREAM_PLAYBACK);
+		if (ret) {
+			dev_err(card->dev,
+				"Error allocating playback dma. ret: %d\n",
+									ret);
+			return -ENOMEM;
+		}
+		pback = 1;
+	}
+
+	if (pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream) {
+		ret = ipq4019_pcm_preallocate_dma_buffer(pcm,
+				SNDRV_PCM_STREAM_CAPTURE);
+		if (ret) {
+			dev_err(card->dev,
+				"Error allocating capture dma buf. ret: %d\n",
+									ret);
+			if (pback)
+				ipq4019_pcm_free_dma_buffer(pcm,
+						SNDRV_PCM_STREAM_PLAYBACK);
+			return -ENOMEM;
+		}
+	}
+
+	return ret;
+}
+
+static struct snd_soc_platform_driver ipq4019_asoc_pcm_i2s_platform = {
+	.ops		= &ipq4019_asoc_pcm_i2s_ops,
+	.pcm_new	= ipq4019_asoc_pcm_i2s_new,
+	.pcm_free	= ipq4019_asoc_pcm_i2s_free,
+};
+
+static const struct of_device_id ipq4019_pcm_i2s_id_table[] = {
+	{ .compatible = "qca,ipq4019-pcm-i2s" },
+	{ .compatible = "qca,ipq4019-pcm-i2s1" },
+	{ .compatible = "qca,ipq4019-pcm-i2s2" },
+	{ /* Sentinel */ },
+};
+MODULE_DEVICE_TABLE(of, ipq4019_pcm_i2s_id_table);
+
+static int ipq4019_pcm_i2s_driver_probe(struct platform_device *pdev)
+{
+	int ret;
+
+	ret = snd_soc_register_platform(&pdev->dev,
+			&ipq4019_asoc_pcm_i2s_platform);
+	if (ret)
+		dev_err(&pdev->dev,
+			"Failed to register i2s pcm device ret: %d\n", ret);
+	return ret;
+}
+
+static int ipq4019_pcm_i2s_driver_remove(struct platform_device *pdev)
+{
+	snd_soc_unregister_platform(&pdev->dev);
+	return 0;
+}
+
+static struct platform_driver ipq4019_pcm_i2s_driver = {
+	.probe = ipq4019_pcm_i2s_driver_probe,
+	.remove = ipq4019_pcm_i2s_driver_remove,
+	.driver = {
+		.name = "qca-pcm-i2s",
+		.owner = THIS_MODULE,
+		.of_match_table = ipq4019_pcm_i2s_id_table,
+	},
+};
+
+module_platform_driver(ipq4019_pcm_i2s_driver);
+
+MODULE_ALIAS("platform:qca-pcm-i2s");
+MODULE_LICENSE("Dual BSD/GPL");
+MODULE_DESCRIPTION("IPQ4019 PCM I2S Platform Driver");
diff --git a/sound/soc/qcom/ipq4019/ipq4019-pcm-spdif.c b/sound/soc/qcom/ipq4019/ipq4019-pcm-spdif.c
new file mode 100644
index 0000000..08dac4a
--- /dev/null
+++ b/sound/soc/qcom/ipq4019/ipq4019-pcm-spdif.c
@@ -0,0 +1,664 @@
+/*
+ * Copyright (c) 2015-2016 The Linux Foundation. All rights reserved.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ */
+
+#include <linux/init.h>
+#include <linux/err.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/time.h>
+#include <linux/wait.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/dma-mapping.h>
+#include <asm/dma.h>
+#include <sound/core.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include <sound/pcm.h>
+#include <sound/initval.h>
+#include <sound/control.h>
+#include <sound/pcm_params.h>
+
+#include "ipq4019-pcm.h"
+#include "ipq4019-adss.h"
+
+static struct snd_pcm_hardware ipq4019_pcm_hardware_playback = {
+	.info			=	SNDRV_PCM_INFO_MMAP |
+					SNDRV_PCM_INFO_BLOCK_TRANSFER |
+					SNDRV_PCM_INFO_MMAP_VALID |
+					SNDRV_PCM_INFO_INTERLEAVED |
+					SNDRV_PCM_INFO_PAUSE |
+					SNDRV_PCM_INFO_RESUME,
+	.formats		=	SNDRV_PCM_FMTBIT_S16 |
+					SNDRV_PCM_FMTBIT_S24_3,
+	.rates			=	RATE_16000_96000,
+	.rate_min		=	FREQ_16000,
+	.rate_max		=	FREQ_96000,
+	.channels_min		=	CH_STEREO,
+	.channels_max		=	CH_STEREO,
+	.buffer_bytes_max	=	IPQ4019_I2S_BUFF_SIZE,
+	.period_bytes_max	=	IPQ4019_I2S_BUFF_SIZE / 2,
+	.period_bytes_min	=	IPQ4019_I2S_PERIOD_BYTES_MIN,
+	.periods_min		=	IPQ4019_I2S_NO_OF_PERIODS,
+	.periods_max		=	IPQ4019_I2S_NO_OF_PERIODS,
+	.fifo_size		=	0,
+};
+
+static struct snd_pcm_hardware ipq4019_pcm_hardware_capture = {
+	.info			=	SNDRV_PCM_INFO_MMAP |
+					SNDRV_PCM_INFO_BLOCK_TRANSFER |
+					SNDRV_PCM_INFO_MMAP_VALID |
+					SNDRV_PCM_INFO_INTERLEAVED,
+	.formats		=	SNDRV_PCM_FMTBIT_S16 |
+					SNDRV_PCM_FMTBIT_S24_3,
+	.rates			=	RATE_16000_96000,
+	.rate_min		=	FREQ_16000,
+	.rate_max		=	FREQ_96000,
+	.channels_min		=	CH_STEREO,
+	.channels_max		=	CH_STEREO,
+	.buffer_bytes_max	=	IPQ4019_I2S_BUFF_SIZE,
+	.period_bytes_max	=	IPQ4019_I2S_BUFF_SIZE / 2,
+	.period_bytes_min	=	IPQ4019_I2S_PERIOD_BYTES_MIN,
+	.periods_min		=	IPQ4019_I2S_NO_OF_PERIODS,
+	.periods_max		=	IPQ4019_I2S_NO_OF_PERIODS,
+	.fifo_size		=	0,
+};
+
+static size_t ip4019_dma_buffer_size(struct snd_pcm_hardware *pcm_hw)
+{
+	return pcm_hw->buffer_bytes_max +
+		(pcm_hw->periods_min * sizeof(struct ipq4019_mbox_desc));
+}
+
+/*
+ * The MBOX descriptors and buffers should lie within the same 256MB
+ * region. Because, the buffer address pointer (in the descriptor structure)
+ * and descriptor base address pointer register share the same MSB 4 bits
+ * which is configured in MBOX DMA Policy register.
+ *
+ * Hence ensure that the entire allocated region falls in a 256MB region.
+ */
+static int ipq4019_mbox_buf_is_aligned(void *c_ptr, ssize_t size)
+{
+	u32 ptr = (u32)c_ptr;
+
+	return (ptr & 0xF0000000) == ((ptr + size - 1) & 0xF0000000);
+}
+
+static struct device *ss2dev(struct snd_pcm_substream *substream)
+{
+	return substream->pcm->card->dev;
+}
+
+static int ipq4019_pcm_preallocate_dma_buffer(struct snd_pcm *pcm,
+						int stream)
+{
+	struct snd_pcm_substream *substream = pcm->streams[stream].substream;
+	struct snd_dma_buffer *buf = &substream->dma_buffer;
+	struct snd_pcm_hardware *pcm_hw = NULL;
+	size_t size;
+	u8 *area;
+	dma_addr_t addr;
+
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+		pcm_hw = &ipq4019_pcm_hardware_playback;
+	else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
+		pcm_hw = &ipq4019_pcm_hardware_capture;
+	else
+		return -EINVAL;
+
+	size = ip4019_dma_buffer_size(pcm_hw);
+	buf->dev.type = SNDRV_DMA_TYPE_DEV;
+	buf->dev.dev = pcm->card->dev;
+	buf->private_data = NULL;
+
+	area = dma_alloc_coherent(pcm->card->dev, size, &addr, GFP_KERNEL);
+	if (!area) {
+		dev_info(ss2dev(substream), "Alloc coherent memory failed\n");
+		return -ENOMEM;
+	}
+
+	if (!ipq4019_mbox_buf_is_aligned(area, size)) {
+		dev_info(ss2dev(substream),
+			 "First allocation %p not within 256M region\n", area);
+
+		buf->area = dma_alloc_coherent(pcm->card->dev, size,
+						&buf->addr, GFP_KERNEL);
+		/*
+		 * If we are here, the previously allocated buffer is not
+		 * usable for the driver. Have to free it anyway regardless
+		 * of the success/failure of the second allocation.
+		 */
+		dma_free_coherent(pcm->card->dev, size, area, addr);
+		if (!buf->area) {
+			dev_info(ss2dev(substream),
+				 "Second Alloc coherent memory failed\n");
+			return -ENOMEM;
+		}
+	} else {
+		buf->area = area;
+		buf->addr = addr;
+	}
+
+	buf->bytes = pcm_hw->buffer_bytes_max;
+
+	return 0;
+}
+
+static void ipq4019_pcm_free_dma_buffer(struct snd_pcm *pcm, int stream)
+{
+	struct snd_pcm_substream *substream;
+	struct snd_pcm_hardware *pcm_hw = NULL;
+	struct snd_dma_buffer *buf;
+	size_t size;
+
+	substream = pcm->streams[stream].substream;
+	buf = &substream->dma_buffer;
+
+	switch (stream) {
+	case SNDRV_PCM_STREAM_PLAYBACK:
+		pcm_hw = &ipq4019_pcm_hardware_playback;
+		break;
+	case SNDRV_PCM_STREAM_CAPTURE:
+		pcm_hw = &ipq4019_pcm_hardware_capture;
+		break;
+	}
+
+	size = ip4019_dma_buffer_size(pcm_hw);
+
+	dma_free_coherent(pcm->card->dev, size, buf->area, buf->addr);
+
+	buf->area = NULL;
+}
+
+static irqreturn_t ipq4019_pcm_irq(int intrsrc, void *data)
+{
+	uint32_t processed_size;
+	int offset;
+	uint32_t *ptr;
+
+	struct snd_pcm_substream *substream = data;
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct ipq4019_pcm_rt_priv *pcm_rtpriv =
+		(struct ipq4019_pcm_rt_priv *)runtime->private_data;
+
+	/* Store the last played buffer in the runtime priv struct */
+	pcm_rtpriv->last_played =
+		ipq4019_mbox_get_last_played(pcm_rtpriv->channel);
+
+	/* Set the OWN bits */
+	processed_size = ipq4019_mbox_get_elapsed_size(pcm_rtpriv->channel);
+	pcm_rtpriv->processed_size = processed_size;
+
+	if (processed_size > pcm_rtpriv->period_size)
+		snd_printd("Processed more than one period bytes : %d\n",
+						processed_size);
+
+	/* Need to extract the data part alone in case of Rx */
+	if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
+		if (pcm_rtpriv->last_played == NULL)
+			offset = 0;
+		else
+			offset = (pcm_rtpriv->last_played->BufPtr -
+					(runtime->dma_addr & 0xFFFFFFF));
+
+		if (offset > 0) {
+			ptr = (uint32_t *)((char *)runtime->dma_area + offset -
+						processed_size);
+
+			if (ptr < (uint32_t *)runtime->dma_area)
+				goto ack;
+		}
+	}
+
+	snd_pcm_period_elapsed(substream);
+
+	if (pcm_rtpriv->last_played == NULL) {
+		snd_printd("BUG: ISR called but no played buf found\n");
+		goto ack;
+	}
+
+ack:
+	return IRQ_HANDLED;
+}
+
+static snd_pcm_uframes_t ipq4019_pcm_spdif_pointer(
+				struct snd_pcm_substream *substream)
+{
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct ipq4019_pcm_rt_priv *pcm_rtpriv;
+	snd_pcm_uframes_t ret;
+
+	pcm_rtpriv = runtime->private_data;
+
+	if (pcm_rtpriv->last_played == NULL)
+		ret = 0;
+	else
+		ret = (pcm_rtpriv->last_played->BufPtr -
+				(runtime->dma_addr & 0xFFFFFFF));
+	ret = bytes_to_frames(runtime, ret);
+	return ret;
+}
+
+static int ipq4019_pcm_spdif_copy(struct snd_pcm_substream *substream, int chan,
+				snd_pcm_uframes_t hwoff, void __user *ubuf,
+				snd_pcm_uframes_t frames)
+{
+	struct snd_dma_buffer *buf = &substream->dma_buffer;
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct ipq4019_pcm_rt_priv *pcm_rtpriv = runtime->private_data;
+	char *hwbuf;
+	u32 offset, size;
+
+	offset = frames_to_bytes(runtime, hwoff);
+	size = frames_to_bytes(runtime, frames);
+
+	hwbuf = buf->area + offset;
+
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+		if (copy_from_user(hwbuf, ubuf, size))
+			return -EFAULT;
+	} else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
+		if (copy_to_user(ubuf, hwbuf, size))
+			return -EFAULT;
+	}
+
+	ipq4019_mbox_desc_own(pcm_rtpriv->channel, offset / size, 1);
+
+	ipq4019_mbox_dma_resume(pcm_rtpriv->channel);
+
+	return 0;
+}
+
+static int ipq4019_pcm_spdif_mmap(struct snd_pcm_substream *substream,
+				struct vm_area_struct *vma)
+{
+	struct snd_pcm_runtime *runtime = substream->runtime;
+
+	return dma_mmap_coherent(substream->pcm->card->dev, vma,
+		runtime->dma_area, runtime->dma_addr, runtime->dma_bytes);
+}
+
+static int ipq4019_pcm_hw_free(struct snd_pcm_substream *substream)
+{
+	snd_pcm_set_runtime_buffer(substream, NULL);
+	return 0;
+}
+
+
+static int ipq4019_pcm_spdif_prepare(struct snd_pcm_substream *substream)
+{
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct ipq4019_pcm_rt_priv *pcm_rtpriv;
+
+	uint32_t ret;
+
+	pcm_rtpriv = runtime->private_data;
+
+	ret = ipq4019_mbox_dma_prepare(pcm_rtpriv->channel);
+	if (ret) {
+		pr_err("%s: %d: Error in dma prepare : channel : %d\n",
+				__func__, __LINE__, pcm_rtpriv->channel);
+		ipq4019_mbox_dma_release(pcm_rtpriv->channel);
+		return ret;
+	}
+
+	/* Set to swap the words */
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+		ret = ipq4019_mbox_dma_swap(pcm_rtpriv->channel,
+			runtime->format);
+		if (ret) {
+			pr_err("%s: %d: Error in dma swap : channel : %d\n",
+				__func__, __LINE__, pcm_rtpriv->channel);
+			ipq4019_mbox_dma_release(pcm_rtpriv->channel);
+			return ret;
+		}
+
+		/* SWAP at PCM level for 24 bit samples */
+		if ((substream->runtime->format == SNDRV_PCM_FORMAT_S24_3LE) ||
+		    (substream->runtime->format == SNDRV_PCM_FORMAT_S24_3BE))
+			ipq4019_stereo_spdif_pcmswap(ENABLE,
+				ipq4019_get_stereo_id(substream, SPDIF));
+	}
+
+	/* Set the ownership bits */
+	ipq4019_mbox_get_elapsed_size(pcm_rtpriv->channel);
+
+	pcm_rtpriv->last_played = NULL;
+
+	return ret;
+}
+
+static int ipq4019_pcm_spdif_close(struct snd_pcm_substream *substream)
+{
+	struct ipq4019_pcm_rt_priv *pcm_rtpriv;
+	uint32_t ret;
+
+	pcm_rtpriv = substream->runtime->private_data;
+	ret = ipq4019_mbox_dma_release(pcm_rtpriv->channel);
+	if (ret) {
+		pr_err("%s: %d: Error in dma release\n",
+					__func__, __LINE__);
+	}
+
+	/* Reset the swap */
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+		ret = ipq4019_mbox_dma_reset_swap(pcm_rtpriv->channel);
+		if (ret) {
+			pr_err("%s: %d: Error in dma release\n",
+				__func__, __LINE__);
+		}
+
+		if ((substream->runtime->format == SNDRV_PCM_FORMAT_S24_3LE) ||
+		    (substream->runtime->format == SNDRV_PCM_FORMAT_S24_3BE))
+			ipq4019_stereo_spdif_pcmswap(DISABLE,
+				ipq4019_get_stereo_id(substream, SPDIF));
+	}
+
+	kfree(pcm_rtpriv);
+
+	return ret;
+}
+
+static int ipq4019_pcm_spdif_trigger(struct snd_pcm_substream *substream,
+					int cmd)
+{
+	int ret;
+	u32 desc_duration;
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct ipq4019_pcm_rt_priv *pcm_rtpriv =
+				substream->runtime->private_data;
+
+	switch (cmd) {
+	case SNDRV_PCM_TRIGGER_START:
+	case SNDRV_PCM_TRIGGER_RESUME:
+		/* Enable the SPDIF Stereo block for operation */
+		if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+			ipq4019_stereo_spdif_enable(ENABLE,
+					ipq4019_get_stereo_id(substream,
+								SPDIF));
+		else
+			ipq4019_spdifin_ctrl_spdif_en(ENABLE);
+
+		ret = ipq4019_mbox_dma_start(pcm_rtpriv->channel);
+		if (ret) {
+			pr_err("%s: %d: Error in dma start\n",
+				__func__, __LINE__);
+			ipq4019_mbox_dma_release(pcm_rtpriv->channel);
+		}
+		break;
+	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+		ret = ipq4019_mbox_dma_resume(pcm_rtpriv->channel);
+		if (ret) {
+			pr_err("%s: %d: Error in dma resume\n",
+				__func__, __LINE__);
+			ipq4019_mbox_dma_release(pcm_rtpriv->channel);
+		}
+		break;
+	case SNDRV_PCM_TRIGGER_STOP:
+	case SNDRV_PCM_TRIGGER_SUSPEND:
+		/* Disable the SPDIF Stereo block */
+		if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+			ipq4019_stereo_spdif_enable(DISABLE,
+					ipq4019_get_stereo_id(substream,
+								SPDIF));
+		else
+			ipq4019_spdifin_ctrl_spdif_en(DISABLE);
+
+	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+		/*
+		 * For e.g. the number of bytes needed to represent 1 second
+		 * worth of audio data for sampling frequency, bit width, stereo
+		 * combination of 16KHz, 32-bits and stereo, the calculation is
+		 * as follows
+		 *
+		 * For 1 second,
+		 *	16KHz * 32 bits * 2 (left & right channel of stereo)
+		 *	= 16000 * 4 bytes * 2
+		 *	= 128000 bytes
+		 *
+		 * Hence the duration will be
+		 *	desc_buffer_size_in_bytes / 128000 * 1 sec
+		 */
+		desc_duration =
+			frames_to_bytes(runtime, runtime->period_size) * 1000 /
+				(runtime->rate *
+				 DIV_ROUND_UP(runtime->sample_bits, 8) *
+				 runtime->channels);
+
+		ret = ipq4019_mbox_dma_stop(pcm_rtpriv->channel, desc_duration);
+		if (ret) {
+			pr_err("%s: %d: Error in dma stop\n",
+				__func__, __LINE__);
+			ipq4019_mbox_dma_release(pcm_rtpriv->channel);
+		}
+		break;
+	default:
+		ret = -EINVAL;
+		break;
+	}
+	return ret;
+}
+
+static int ipq4019_pcm_spdif_hw_params(struct snd_pcm_substream *substream,
+				struct snd_pcm_hw_params *hw_params)
+{
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct ipq4019_pcm_rt_priv *pcm_rtpriv;
+	int ret;
+	unsigned int period_size, sample_size, sample_rate, frames, channels;
+
+	pr_debug("%s %d\n", __func__, __LINE__);
+
+	pcm_rtpriv = runtime->private_data;
+	ret = ipq4019_mbox_form_ring(pcm_rtpriv->channel,
+			substream->dma_buffer.addr,
+			substream->dma_buffer.area,
+			params_period_bytes(hw_params),
+			params_buffer_bytes(hw_params),
+			(substream->stream == SNDRV_PCM_STREAM_CAPTURE));
+	if (ret) {
+		pr_err("%s: %d: Error dma form ring\n",	__func__, __LINE__);
+		ipq4019_mbox_dma_release(pcm_rtpriv->channel);
+		return ret;
+	}
+
+	period_size = params_period_bytes(hw_params);
+	sample_size = snd_pcm_format_size(params_format(hw_params), 1);
+	sample_rate = params_rate(hw_params);
+	channels = params_channels(hw_params);
+	frames = period_size / (sample_size * channels);
+
+	pcm_rtpriv->period_size = params_period_bytes(hw_params);
+
+	/* Check whether this is a compressed play or not
+	 * if its a compressed play set VUC
+	 */
+	if (hw_params->reserved[0])
+		ipq4019_mbox_vuc_setup(pcm_rtpriv->channel);
+
+	snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer);
+
+	runtime->dma_bytes = params_buffer_bytes(hw_params);
+	return ret;
+}
+
+static int ipq4019_pcm_spdif_open(struct snd_pcm_substream *substream)
+{
+	int ret;
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct ipq4019_pcm_rt_priv *pcm_rtpriv;
+
+	pr_debug("%s %d\n", __func__, __LINE__);
+
+	pcm_rtpriv = kmalloc(sizeof(struct ipq4019_pcm_rt_priv), GFP_KERNEL);
+	if (!pcm_rtpriv)
+		return -ENOMEM;
+
+	snd_printd("%s: 0x%xB allocated at 0x%08x\n",
+			__func__, sizeof(*pcm_rtpriv), (u32) pcm_rtpriv);
+	pcm_rtpriv->last_played = NULL;
+	pcm_rtpriv->dev = substream->pcm->card->dev;
+	pcm_rtpriv->channel = ipq4019_get_mbox_id(substream, SPDIF);
+	pcm_rtpriv->curr_pos = 0;
+	pcm_rtpriv->mmap_flag = 0;
+	substream->runtime->private_data = pcm_rtpriv;
+
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+		runtime->dma_bytes =
+			ipq4019_pcm_hardware_playback.buffer_bytes_max;
+		snd_soc_set_runtime_hwparams(substream,
+				&ipq4019_pcm_hardware_playback);
+	} else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
+		runtime->dma_bytes =
+				ipq4019_pcm_hardware_capture.buffer_bytes_max;
+		snd_soc_set_runtime_hwparams(substream,
+					&ipq4019_pcm_hardware_capture);
+
+	} else {
+		pr_err("%s: Invalid stream\n", __func__);
+		ret = -EINVAL;
+		goto error;
+	}
+	ret = ipq4019_mbox_dma_init(pcm_rtpriv->dev,
+		pcm_rtpriv->channel, ipq4019_pcm_irq, substream);
+	if (ret) {
+		pr_err("%s: %d: Error initializing dma\n",
+					__func__, __LINE__);
+		goto error;
+	}
+
+	ret = snd_pcm_hw_constraint_integer(runtime,
+			SNDRV_PCM_HW_PARAM_PERIODS);
+	if (ret < 0) {
+		pr_err("%s: snd_pcm_hw_constraint_integer failed\n", __func__);
+		ipq4019_mbox_dma_release(pcm_rtpriv->channel);
+		goto error;
+	}
+
+	return 0;
+error:
+	kfree(pcm_rtpriv);
+	return ret;
+}
+
+static struct snd_pcm_ops ipq4019_asoc_pcm_spdif_ops = {
+	.open		= ipq4019_pcm_spdif_open,
+	.hw_params	= ipq4019_pcm_spdif_hw_params,
+	.hw_free	= ipq4019_pcm_hw_free,
+	.trigger	= ipq4019_pcm_spdif_trigger,
+	.ioctl		= snd_pcm_lib_ioctl,
+	.close		= ipq4019_pcm_spdif_close,
+	.prepare	= ipq4019_pcm_spdif_prepare,
+	.mmap		= ipq4019_pcm_spdif_mmap,
+	.pointer	= ipq4019_pcm_spdif_pointer,
+	.copy		= ipq4019_pcm_spdif_copy,
+};
+
+static void ipq4019_asoc_pcm_spdif_free(struct snd_pcm *pcm)
+{
+	ipq4019_pcm_free_dma_buffer(pcm, SNDRV_PCM_STREAM_PLAYBACK);
+	ipq4019_pcm_free_dma_buffer(pcm, SNDRV_PCM_STREAM_CAPTURE);
+}
+
+static int ipq4019_asoc_pcm_spdif_new(struct snd_soc_pcm_runtime *prtd)
+{
+	struct snd_card *card = prtd->card->snd_card;
+	struct snd_pcm *pcm = prtd->pcm;
+
+	int ret = 0;
+
+	if (!card->dev->coherent_dma_mask)
+		card->dev->coherent_dma_mask = DMA_BIT_MASK(32);
+
+	if (!card->dev->dma_mask)
+		card->dev->dma_mask = &card->dev->coherent_dma_mask;
+
+	if (pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream) {
+		ret = ipq4019_pcm_preallocate_dma_buffer(pcm,
+				SNDRV_PCM_STREAM_PLAYBACK);
+
+		if (ret) {
+			pr_err("%s: %d: Error allocating dma buf\n",
+						__func__, __LINE__);
+			return -ENOMEM;
+		}
+	}
+
+	if (pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream) {
+		ret = ipq4019_pcm_preallocate_dma_buffer(pcm,
+				SNDRV_PCM_STREAM_CAPTURE);
+		if (ret) {
+			pr_err("%s: %d: Error allocating dma buf\n",
+						__func__, __LINE__);
+			ipq4019_pcm_free_dma_buffer(pcm,
+					SNDRV_PCM_STREAM_PLAYBACK);
+			return -ENOMEM;
+		}
+	}
+
+	return ret;
+}
+
+static struct snd_soc_platform_driver ipq4019_asoc_pcm_spdif_platform = {
+	.ops		= &ipq4019_asoc_pcm_spdif_ops,
+	.pcm_new	= ipq4019_asoc_pcm_spdif_new,
+	.pcm_free	= ipq4019_asoc_pcm_spdif_free,
+};
+
+static const struct of_device_id ipq4019_pcm_spdif_id_table[] = {
+	{ .compatible = "qca,ipq4019-pcm-spdif" },
+	{ /* Sentinel */ },
+};
+MODULE_DEVICE_TABLE(of, ipq4019_pcm_spdif_id_table);
+
+static int ipq4019_pcm_spdif_driver_probe(struct platform_device *pdev)
+{
+	int ret;
+
+	pr_debug("%s %d\n", __func__, __LINE__);
+	ret = snd_soc_register_platform(&pdev->dev,
+			&ipq4019_asoc_pcm_spdif_platform);
+	if (ret)
+		dev_err(&pdev->dev, "%s: Failed to register spdif pcm device\n",
+								__func__);
+	return ret;
+}
+
+static int ipq4019_pcm_spdif_driver_remove(struct platform_device *pdev)
+{
+	pr_debug("%s %d\n", __func__, __LINE__);
+	snd_soc_unregister_platform(&pdev->dev);
+
+	return 0;
+}
+
+static struct platform_driver ipq4019_pcm_spdif_driver = {
+	.probe = ipq4019_pcm_spdif_driver_probe,
+	.remove = ipq4019_pcm_spdif_driver_remove,
+	.driver = {
+		.name = "qca-pcm-spdif",
+		.owner = THIS_MODULE,
+		.of_match_table = ipq4019_pcm_spdif_id_table,
+	},
+};
+
+module_platform_driver(ipq4019_pcm_spdif_driver);
+
+MODULE_ALIAS("platform:qca-pcm-spdif");
+MODULE_LICENSE("Dual BSD/GPL");
+MODULE_DESCRIPTION("IPQ4019 PCM SPDIF Platform Driver");
diff --git a/sound/soc/qcom/ipq4019/ipq4019-pcm-tdm.c b/sound/soc/qcom/ipq4019/ipq4019-pcm-tdm.c
new file mode 100644
index 0000000..657a4a6
--- /dev/null
+++ b/sound/soc/qcom/ipq4019/ipq4019-pcm-tdm.c
@@ -0,0 +1,609 @@
+/*
+ * Copyright (c) 2015-2016, The Linux Foundation. All rights reserved.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ */
+
+#include <linux/init.h>
+#include <linux/err.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/time.h>
+#include <linux/wait.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/dma-mapping.h>
+#include <asm/dma.h>
+#include <sound/core.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include <sound/pcm.h>
+#include <sound/initval.h>
+#include <sound/control.h>
+#include <sound/pcm_params.h>
+
+#include "ipq4019-pcm.h"
+#include "ipq4019-adss.h"
+
+static struct snd_pcm_hardware ipq4019_pcm_hardware_playback = {
+	.info			=	SNDRV_PCM_INFO_MMAP |
+					SNDRV_PCM_INFO_BLOCK_TRANSFER |
+					SNDRV_PCM_INFO_MMAP_VALID |
+					SNDRV_PCM_INFO_INTERLEAVED |
+					SNDRV_PCM_INFO_PAUSE |
+					SNDRV_PCM_INFO_RESUME,
+	.formats		=	SNDRV_PCM_FMTBIT_S16 |
+					SNDRV_PCM_FMTBIT_S32,
+	.rates			=	RATE_16000_96000,
+	.rate_min		=	FREQ_16000,
+	.rate_max		=	FREQ_96000,
+	.channels_min		=	CH_STEREO,
+	.channels_max		=	CH_7_1,
+	.buffer_bytes_max	=	IPQ4019_TDM_BUFF_SIZE,
+	.period_bytes_max	=	IPQ4019_TDM_BUFF_SIZE / 2,
+	.period_bytes_min	=	IPQ4019_TDM_PERIOD_BYTES_MIN,
+	.periods_min		=	IPQ4019_TDM_NO_OF_PERIODS,
+	.periods_max		=	IPQ4019_TDM_NO_OF_PERIODS,
+	.fifo_size		=	0,
+};
+
+static struct snd_pcm_hardware ipq4019_pcm_hardware_capture = {
+	.info			=	SNDRV_PCM_INFO_MMAP |
+					SNDRV_PCM_INFO_BLOCK_TRANSFER |
+					SNDRV_PCM_INFO_MMAP_VALID |
+					SNDRV_PCM_INFO_INTERLEAVED,
+	.formats		=	SNDRV_PCM_FMTBIT_S16 |
+					SNDRV_PCM_FMTBIT_S32,
+	.rates			=	RATE_16000_96000,
+	.rate_min		=	FREQ_16000,
+	.rate_max		=	FREQ_96000,
+	.channels_min		=	CH_STEREO,
+	.channels_max		=	CH_7_1,
+	.buffer_bytes_max	=	IPQ4019_TDM_BUFF_SIZE,
+	.period_bytes_max	=	IPQ4019_TDM_BUFF_SIZE / 2,
+	.period_bytes_min	=	IPQ4019_TDM_PERIOD_BYTES_MIN,
+	.periods_min		=	IPQ4019_TDM_NO_OF_PERIODS,
+	.periods_max		=	IPQ4019_TDM_NO_OF_PERIODS,
+	.fifo_size		=	0,
+};
+
+static size_t ip4019_dma_buffer_size(struct snd_pcm_hardware *pcm_hw)
+{
+	return (pcm_hw->buffer_bytes_max +
+		(pcm_hw->periods_min * sizeof(struct ipq4019_mbox_desc)));
+}
+
+static struct device *ss2dev(struct snd_pcm_substream *substream)
+{
+	return substream->pcm->card->dev;
+}
+
+/*
+ * The MBOX descriptors and buffers should lie within the same 256MB
+ * region. Because, the buffer address pointer (in the descriptor structure)
+ * and descriptor base address pointer register share the same MSB 4 bits
+ * which is configured in MBOX DMA Policy register.
+ *
+ * Hence ensure that the entire allocated region falls in a 256MB region.
+ */
+static int ipq4019_mbox_buf_is_aligned(void *c_ptr, ssize_t size)
+{
+	u32 ptr = (u32)c_ptr;
+
+	return (ptr & 0xF0000000) == ((ptr + size - 1) & 0xF0000000);
+}
+
+static int ipq4019_pcm_preallocate_dma_buffer(struct snd_pcm *pcm,
+						int stream)
+{
+	struct snd_pcm_substream *substream = pcm->streams[stream].substream;
+	struct snd_pcm_hardware *pcm_hw = NULL;
+	struct snd_dma_buffer *buf = &substream->dma_buffer;
+	size_t size;
+	u8 *area;
+	dma_addr_t addr;
+
+	switch (substream->stream) {
+	case SNDRV_PCM_STREAM_PLAYBACK:
+		pcm_hw = &ipq4019_pcm_hardware_playback;
+		break;
+	case SNDRV_PCM_STREAM_CAPTURE:
+		pcm_hw = &ipq4019_pcm_hardware_capture;
+		break;
+	default:
+		dev_err(ss2dev(substream), "Invalid stream: %d\n",
+							substream->stream);
+		return -EINVAL;
+	}
+
+	size = ip4019_dma_buffer_size(pcm_hw);
+	buf->dev.type = SNDRV_DMA_TYPE_DEV;
+	buf->dev.dev = pcm->card->dev;
+	buf->private_data = NULL;
+
+	/*
+	 * |<--   buffers             -->|<-- desc  -->|
+	 * +----+----+----+----+----+----+-+-+-+-+-+-+-+
+	 * |    |    |    |    |    |    | | | | | | | |
+	 * |    |    |    |    |    |    | | | | | | | |
+	 * |    |    |    |    |    |    | | | | | | | |
+	 * |    |    |    |    |    |    | | | | | | | |
+	 * |    |    |    |    |    |    | | | | | | | |
+	 * +----+----+----+----+----+----+-+-+-+-+-+-+-+
+	 * ^    ^                        | |  . . .
+	 * |    |                        | |
+	 * +----|------------------------+ |
+	 *	+--------------------------+
+	 */
+
+	/*
+	 * Currently payload uses uncached memory.
+	 * TODO: Eventually we will move to cached memory for payload
+	 * and dma_map_single() will be used for Invalidating/Flushing
+	 * the buffers.
+	 */
+
+	area = dma_alloc_coherent(pcm->card->dev, size, &addr, GFP_KERNEL);
+
+	if (!area) {
+		dev_info(ss2dev(substream), "Alloc coherent memory failed\n");
+		return -ENOMEM;
+	}
+
+	if (!ipq4019_mbox_buf_is_aligned(area, size)) {
+		dev_info(ss2dev(substream),
+			 "First allocation %p not within 256M region\n", area);
+
+		buf->area = dma_alloc_coherent(pcm->card->dev, size,
+						&buf->addr, GFP_KERNEL);
+		/*
+		 * If we are here, the previously allocated buffer is not
+		 * usable for the driver. Have to free it anyway regardless
+		 * of the success/failure of the second allocation.
+		 */
+		dma_free_coherent(pcm->card->dev, size, area, addr);
+		if (!buf->area) {
+			dev_info(ss2dev(substream),
+				 "Second Alloc coherent memory failed\n");
+			return -ENOMEM;
+		}
+	} else {
+		buf->area = area;
+		buf->addr = addr;
+	}
+
+	buf->bytes = pcm_hw->buffer_bytes_max;
+
+	return 0;
+}
+
+static void ipq4019_pcm_free_dma_buffer(struct snd_pcm *pcm, int stream)
+{
+	struct snd_pcm_substream *substream;
+	struct snd_pcm_hardware *pcm_hw = NULL;
+	struct snd_dma_buffer *buf;
+	size_t size;
+
+	substream = pcm->streams[stream].substream;
+	buf = &substream->dma_buffer;
+
+	switch (stream) {
+	case SNDRV_PCM_STREAM_PLAYBACK:
+		pcm_hw = &ipq4019_pcm_hardware_playback;
+		break;
+	case SNDRV_PCM_STREAM_CAPTURE:
+		pcm_hw = &ipq4019_pcm_hardware_capture;
+		break;
+	}
+
+	size = ip4019_dma_buffer_size(pcm_hw);
+
+	dma_free_coherent(pcm->card->dev, size, buf->area, buf->addr);
+
+	buf->addr = 0;
+	buf->area = NULL;
+}
+
+static irqreturn_t ipq4019_pcm_irq(int intrsrc, void *data)
+{
+	struct snd_pcm_substream *substream = data;
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct ipq4019_pcm_rt_priv *pcm_rtpriv =
+		(struct ipq4019_pcm_rt_priv *)runtime->private_data;
+
+	pcm_rtpriv->curr_pos =
+		ipq4019_mbox_get_played_offset(pcm_rtpriv->channel);
+
+	snd_pcm_period_elapsed(substream);
+
+	return IRQ_HANDLED;
+}
+
+static snd_pcm_uframes_t ipq4019_pcm_tdm_pointer(
+				struct snd_pcm_substream *substream)
+{
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct ipq4019_pcm_rt_priv *pcm_rtpriv;
+	snd_pcm_uframes_t ret;
+
+	pcm_rtpriv = runtime->private_data;
+
+	ret = bytes_to_frames(runtime, pcm_rtpriv->curr_pos);
+	return ret;
+}
+
+static int ipq4019_pcm_tdm_copy(struct snd_pcm_substream *substream, int chan,
+				snd_pcm_uframes_t hwoff, void __user *ubuf,
+				snd_pcm_uframes_t frames)
+{
+	struct snd_dma_buffer *buf = &substream->dma_buffer;
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct ipq4019_pcm_rt_priv *pcm_rtpriv = runtime->private_data;
+	char *hwbuf;
+	u32 offset, size;
+
+	offset = frames_to_bytes(runtime, hwoff);
+	size = frames_to_bytes(runtime, frames);
+
+	hwbuf = buf->area + offset;
+
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+		if (copy_from_user(hwbuf, ubuf, size))
+			return -EFAULT;
+	} else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
+		if (copy_to_user(ubuf, hwbuf, size))
+			return -EFAULT;
+	}
+
+	ipq4019_mbox_desc_own(pcm_rtpriv->channel, offset / size, 1);
+
+	ipq4019_mbox_dma_resume(pcm_rtpriv->channel);
+
+	return 0;
+}
+
+static int ipq4019_pcm_tdm_mmap(struct snd_pcm_substream *substream,
+				struct vm_area_struct *vma)
+{
+	struct snd_pcm_runtime *runtime = substream->runtime;
+
+	return dma_mmap_coherent(substream->pcm->card->dev, vma,
+		runtime->dma_area, runtime->dma_addr, runtime->dma_bytes);
+}
+
+static int ipq4019_pcm_hw_free(struct snd_pcm_substream *substream)
+{
+	snd_pcm_set_runtime_buffer(substream, NULL);
+	return 0;
+}
+
+
+static int ipq4019_pcm_tdm_prepare(struct snd_pcm_substream *substream)
+{
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct ipq4019_pcm_rt_priv *pcm_rtpriv;
+
+	uint32_t ret;
+
+	pcm_rtpriv = runtime->private_data;
+	ret = ipq4019_mbox_dma_prepare(pcm_rtpriv->channel);
+	if (ret) {
+		pr_err("%s: %d: Error in dma prepare : channel : %d\n",
+				__func__, __LINE__, pcm_rtpriv->channel);
+		ipq4019_mbox_dma_release(pcm_rtpriv->channel);
+		return ret;
+	}
+
+	/* Set the ownership bits */
+	ipq4019_mbox_get_elapsed_size(pcm_rtpriv->channel);
+
+	pcm_rtpriv->last_played = NULL;
+
+	return ret;
+}
+
+static int ipq4019_pcm_tdm_close(struct snd_pcm_substream *substream)
+{
+	struct ipq4019_pcm_rt_priv *pcm_rtpriv;
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct snd_soc_dai *dai = rtd->cpu_dai;
+	u32 intf = dai->driver->id;
+	uint32_t ret;
+
+	ipq4019_stereo_config_enable(DISABLE,
+				ipq4019_get_stereo_id(substream, intf));
+
+	pcm_rtpriv = substream->runtime->private_data;
+	if (!pcm_rtpriv)
+		return -EINVAL;
+
+	ret = ipq4019_mbox_dma_release(pcm_rtpriv->channel);
+	if (ret) {
+		pr_err("%s: %d: Error in dma release\n",
+					__func__, __LINE__);
+	}
+
+	kfree(pcm_rtpriv);
+
+	return 0;
+}
+
+static int ipq4019_pcm_tdm_trigger(struct snd_pcm_substream *substream, int cmd)
+{
+	int ret;
+	u32 desc_duration;
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct ipq4019_pcm_rt_priv *pcm_rtpriv =
+				substream->runtime->private_data;
+
+	switch (cmd) {
+	case SNDRV_PCM_TRIGGER_START:
+	case SNDRV_PCM_TRIGGER_RESUME:
+
+		ret = ipq4019_mbox_dma_start(pcm_rtpriv->channel);
+		if (ret) {
+			pr_err("%s: %d: Error in dma start\n",
+				__func__, __LINE__);
+			ipq4019_mbox_dma_release(pcm_rtpriv->channel);
+		}
+		break;
+	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+		ret = ipq4019_mbox_dma_resume(pcm_rtpriv->channel);
+		if (ret) {
+			pr_err("%s: %d: Error in dma resume\n",
+				__func__, __LINE__);
+			ipq4019_mbox_dma_release(pcm_rtpriv->channel);
+		}
+		break;
+	case SNDRV_PCM_TRIGGER_STOP:
+	case SNDRV_PCM_TRIGGER_SUSPEND:
+	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+		/*
+		 * For e.g. the number of bytes needed to represent 1 second
+		 * worth of audio data for sampling frequency, bit width, stereo
+		 * combination of 16KHz, 32-bits and stereo, the calculation is
+		 * as follows
+		 *
+		 * For 1 second,
+		 *	16KHz * 32 bits * 2 (left & right channel of stereo)
+		 *	= 16000 * 4 bytes * 2
+		 *	= 128000 bytes
+		 *
+		 * Hence the duration will be
+		 *	desc_buffer_size_in_bytes / 128000 * 1 sec
+		 */
+		desc_duration =
+			frames_to_bytes(runtime, runtime->period_size) * 1000 /
+				(runtime->rate *
+				 DIV_ROUND_UP(runtime->sample_bits, 8) *
+				 runtime->channels);
+
+		ret = ipq4019_mbox_dma_stop(pcm_rtpriv->channel, desc_duration);
+		if (ret) {
+			pr_err("%s: %d: Error in dma stop\n",
+				__func__, __LINE__);
+			ipq4019_mbox_dma_release(pcm_rtpriv->channel);
+		}
+		break;
+	default:
+		ret = -EINVAL;
+		break;
+	}
+	return ret;
+}
+
+static int ipq4019_pcm_tdm_hw_params(struct snd_pcm_substream *substream,
+				struct snd_pcm_hw_params *hw_params)
+{
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct ipq4019_pcm_rt_priv *pcm_rtpriv;
+	int ret;
+	unsigned int period_size, sample_size, sample_rate, frames, channels;
+
+	pr_debug("%s %d\n", __func__, __LINE__);
+
+	pcm_rtpriv = runtime->private_data;
+
+	ret = ipq4019_mbox_form_ring(pcm_rtpriv->channel,
+			substream->dma_buffer.addr,
+			substream->dma_buffer.area,
+			params_period_bytes(hw_params),
+			params_buffer_bytes(hw_params),
+			(substream->stream == SNDRV_PCM_STREAM_CAPTURE));
+	if (ret) {
+		pr_err("%s: %d: Error dma form ring\n", __func__, __LINE__);
+		ipq4019_mbox_dma_release(pcm_rtpriv->channel);
+		return ret;
+	}
+
+	period_size = params_period_bytes(hw_params);
+	sample_size = snd_pcm_format_size(params_format(hw_params), 1);
+	sample_rate = params_rate(hw_params);
+	channels = params_channels(hw_params);
+	frames = period_size / (sample_size * channels);
+
+	pcm_rtpriv->period_size = params_period_bytes(hw_params);
+
+	snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer);
+
+	runtime->dma_bytes = params_buffer_bytes(hw_params);
+	return ret;
+}
+
+static int ipq4019_pcm_tdm_open(struct snd_pcm_substream *substream)
+{
+	int ret;
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct ipq4019_pcm_rt_priv *pcm_rtpriv;
+
+	pr_debug("%s %d\n", __func__, __LINE__);
+
+	pcm_rtpriv = kmalloc(sizeof(struct ipq4019_pcm_rt_priv), GFP_KERNEL);
+
+	if (!pcm_rtpriv)
+		return -ENOMEM;
+
+	snd_printd("%s: 0x%xB allocated at 0x%08x\n",
+			__func__, sizeof(*pcm_rtpriv), (u32) pcm_rtpriv);
+	pcm_rtpriv->last_played = NULL;
+	pcm_rtpriv->dev = substream->pcm->card->dev;
+	pcm_rtpriv->channel = ipq4019_get_mbox_id(substream, TDM);
+	pcm_rtpriv->curr_pos = 0;
+	pcm_rtpriv->mmap_flag = 0;
+	substream->runtime->private_data = pcm_rtpriv;
+
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+		runtime->dma_bytes =
+			ipq4019_pcm_hardware_playback.buffer_bytes_max;
+		snd_soc_set_runtime_hwparams(substream,
+				&ipq4019_pcm_hardware_playback);
+	} else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
+		runtime->dma_bytes =
+				ipq4019_pcm_hardware_capture.buffer_bytes_max;
+		snd_soc_set_runtime_hwparams(substream,
+					&ipq4019_pcm_hardware_capture);
+
+	} else {
+		pr_err("%s: Invalid stream\n", __func__);
+		ret = -EINVAL;
+		goto error;
+	}
+	ret = ipq4019_mbox_dma_init(pcm_rtpriv->dev,
+		pcm_rtpriv->channel, ipq4019_pcm_irq, substream);
+	if (ret) {
+		pr_err("%s: %d: Error initializing dma\n",
+					__func__, __LINE__);
+		goto error;
+	}
+
+	ret = snd_pcm_hw_constraint_integer(runtime,
+			SNDRV_PCM_HW_PARAM_PERIODS);
+	if (ret < 0) {
+		pr_err("%s: snd_pcm_hw_constraint_integer failed\n", __func__);
+		ipq4019_mbox_dma_release(pcm_rtpriv->channel);
+		goto error;
+	}
+
+	return 0;
+error:
+	kfree(pcm_rtpriv);
+	return ret;
+}
+
+static struct snd_pcm_ops ipq4019_asoc_pcm_tdm_ops = {
+	.open		= ipq4019_pcm_tdm_open,
+	.hw_params	= ipq4019_pcm_tdm_hw_params,
+	.hw_free	= ipq4019_pcm_hw_free,
+	.trigger	= ipq4019_pcm_tdm_trigger,
+	.ioctl		= snd_pcm_lib_ioctl,
+	.close		= ipq4019_pcm_tdm_close,
+	.prepare	= ipq4019_pcm_tdm_prepare,
+	.mmap		= ipq4019_pcm_tdm_mmap,
+	.pointer	= ipq4019_pcm_tdm_pointer,
+	.copy		= ipq4019_pcm_tdm_copy,
+};
+
+static void ipq4019_asoc_pcm_tdm_free(struct snd_pcm *pcm)
+{
+	ipq4019_pcm_free_dma_buffer(pcm, SNDRV_PCM_STREAM_PLAYBACK);
+	ipq4019_pcm_free_dma_buffer(pcm, SNDRV_PCM_STREAM_CAPTURE);
+}
+
+static int ipq4019_asoc_pcm_tdm_new(struct snd_soc_pcm_runtime *prtd)
+{
+	struct snd_card *card = prtd->card->snd_card;
+	struct snd_pcm *pcm = prtd->pcm;
+
+	int ret = 0;
+
+	if (!card->dev->coherent_dma_mask)
+		card->dev->coherent_dma_mask = DMA_BIT_MASK(32);
+
+	if (!card->dev->dma_mask)
+		card->dev->dma_mask = &card->dev->coherent_dma_mask;
+
+	if (pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream) {
+		ret = ipq4019_pcm_preallocate_dma_buffer(pcm,
+				SNDRV_PCM_STREAM_PLAYBACK);
+
+		if (ret) {
+			pr_err("%s: %d: Error allocating dma buf\n",
+						__func__, __LINE__);
+			return -ENOMEM;
+		}
+	}
+
+	if (pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream) {
+		ret = ipq4019_pcm_preallocate_dma_buffer(pcm,
+				SNDRV_PCM_STREAM_CAPTURE);
+		if (ret) {
+			pr_err("%s: %d: Error allocating dma buf\n",
+						__func__, __LINE__);
+			ipq4019_pcm_free_dma_buffer(pcm,
+					SNDRV_PCM_STREAM_PLAYBACK);
+			return -ENOMEM;
+		}
+	}
+
+	return ret;
+}
+
+static struct snd_soc_platform_driver ipq4019_asoc_pcm_tdm_platform = {
+	.ops		= &ipq4019_asoc_pcm_tdm_ops,
+	.pcm_new	= ipq4019_asoc_pcm_tdm_new,
+	.pcm_free	= ipq4019_asoc_pcm_tdm_free,
+};
+
+static const struct of_device_id ipq4019_pcm_tdm_id_table[] = {
+	{ .compatible = "qca,ipq4019-pcm-tdm" },
+	{ /* Sentinel */ },
+};
+MODULE_DEVICE_TABLE(of, ipq4019_pcm_tdm_id_table);
+
+static int ipq4019_pcm_tdm_driver_probe(struct platform_device *pdev)
+{
+	int ret;
+
+	pr_debug("%s %d\n", __func__, __LINE__);
+	ret = snd_soc_register_platform(&pdev->dev,
+			&ipq4019_asoc_pcm_tdm_platform);
+	if (ret)
+		dev_err(&pdev->dev, "%s: Failed to register tdm pcm device\n",
+								__func__);
+	return ret;
+}
+
+static int ipq4019_pcm_tdm_driver_remove(struct platform_device *pdev)
+{
+	pr_debug("%s %d\n", __func__, __LINE__);
+	snd_soc_unregister_platform(&pdev->dev);
+
+	return 0;
+}
+
+static struct platform_driver ipq4019_pcm_tdm_driver = {
+	.probe = ipq4019_pcm_tdm_driver_probe,
+	.remove = ipq4019_pcm_tdm_driver_remove,
+	.driver = {
+		.name = "qca-pcm-tdm",
+		.owner = THIS_MODULE,
+		.of_match_table = ipq4019_pcm_tdm_id_table,
+	},
+};
+
+module_platform_driver(ipq4019_pcm_tdm_driver);
+
+MODULE_ALIAS("platform:qca-pcm-tdm");
+MODULE_LICENSE("Dual BSD/GPL");
+MODULE_DESCRIPTION("IPQ4019 PCM TDM Platform Driver");
diff --git a/sound/soc/qcom/ipq4019/ipq4019-pcm.h b/sound/soc/qcom/ipq4019/ipq4019-pcm.h
new file mode 100644
index 0000000..0c467d6
--- /dev/null
+++ b/sound/soc/qcom/ipq4019/ipq4019-pcm.h
@@ -0,0 +1,37 @@
+/*
+ * Copyright (c) 2015, The Linux Foundation. All rights reserved.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef _IPQ40XX_PCM_H_
+#define _IPQ40XX_PCM_H_
+
+#include <linux/sound.h>
+#include <linux/list.h>
+#include <linux/spinlock.h>
+#include <linux/interrupt.h>
+
+#include "ipq4019-mbox.h"
+
+struct ipq4019_pcm_rt_priv {
+	int channel;
+	struct device *dev;
+	struct ipq4019_mbox_desc *last_played;
+	unsigned int processed_size;
+	uint32_t period_size;
+	uint32_t curr_pos;
+	int mmap_flag;
+};
+
+#endif /* _IPQ40XX_PCM_H_ */
diff --git a/sound/soc/qcom/ipq4019/ipq4019-stereo.c b/sound/soc/qcom/ipq4019/ipq4019-stereo.c
new file mode 100644
index 0000000..52e0c29
--- /dev/null
+++ b/sound/soc/qcom/ipq4019/ipq4019-stereo.c
@@ -0,0 +1,313 @@
+/*
+ * Copyright (c) 2015-2016, The Linux Foundation. All rights reserved.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ */
+
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/soc.h>
+#include <sound/pcm_params.h>
+#include <linux/delay.h>
+#include <linux/spinlock.h>
+
+#include "ipq4019-adss.h"
+
+struct stereo_priv_data {
+	void __iomem *stereo_base;
+	spinlock_t stereo_lock;
+};
+
+static struct stereo_priv_data stereo_priv[MAX_STEREO_ENTRIES];
+
+/*
+ *
+ * Stereo buffers and I2S state reset
+ */
+void ipq4019_stereo_config_reset(u32 reset, u32 stereo_id)
+{
+	u32 cfg;
+	unsigned long flags;
+
+	spin_lock_irqsave(&stereo_priv[stereo_id].stereo_lock, flags);
+	cfg = readl(stereo_priv[stereo_id].stereo_base
+			+ ADSS_STEREOn_STEREO0_CONFIG_REG);
+	cfg &= ~STEREOn_CONFIG_RESET;
+	if (reset)
+		cfg |= STEREOn_CONFIG_RESET;
+	writel(cfg, stereo_priv[stereo_id].stereo_base
+			+ ADSS_STEREOn_STEREO0_CONFIG_REG);
+	spin_unlock_irqrestore(&stereo_priv[stereo_id].stereo_lock, flags);
+}
+EXPORT_SYMBOL(ipq4019_stereo_config_reset);
+
+/*
+ * MIC buffers reset
+ */
+void ipq4019_stereo_config_mic_reset(u32 reset, u32 stereo_id)
+{
+	u32 cfg;
+	unsigned long flags;
+
+	spin_lock_irqsave(&stereo_priv[stereo_id].stereo_lock, flags);
+	cfg = readl(stereo_priv[stereo_id].stereo_base
+			+ ADSS_STEREOn_STEREO0_CONFIG_REG);
+	cfg &= ~STEREOn_CONFIG_MIC_RESET;
+	if (reset)
+		cfg |= STEREOn_CONFIG_MIC_RESET;
+	writel(cfg, stereo_priv[stereo_id].stereo_base
+			+ ADSS_STEREOn_STEREO0_CONFIG_REG);
+	spin_unlock_irqrestore(&stereo_priv[stereo_id].stereo_lock, flags);
+}
+EXPORT_SYMBOL(ipq4019_stereo_config_mic_reset);
+
+/*
+ * Enable the I2S Stereo block for operation
+ */
+void ipq4019_stereo_config_enable(u32 enable, u32 stereo_id)
+{
+	u32 cfg;
+	unsigned long flags;
+
+	spin_lock_irqsave(&stereo_priv[stereo_id].stereo_lock, flags);
+	cfg = readl(stereo_priv[stereo_id].stereo_base
+			+ ADSS_STEREOn_STEREO0_CONFIG_REG);
+	cfg &= ~STEREOn_CONFIG_ENABLE;
+	if (enable)
+		cfg |= STEREOn_CONFIG_ENABLE;
+	writel(cfg, stereo_priv[stereo_id].stereo_base
+			+ ADSS_STEREOn_STEREO0_CONFIG_REG);
+	spin_unlock_irqrestore(&stereo_priv[stereo_id].stereo_lock, flags);
+}
+EXPORT_SYMBOL(ipq4019_stereo_config_enable);
+
+/*
+ * Enable the SPDIF Stereo block for operation
+ */
+void ipq4019_stereo_spdif_enable(uint32_t enable, uint32_t stereo_id)
+{
+	uint32_t cfg;
+
+	cfg = readl(stereo_priv[stereo_id].stereo_base
+			+ ADSS_STEREOn_STEREO0_CONFIG_REG);
+	cfg &= ~(STEREOn_CONFIG_SPDIF_ENABLE);
+	if (enable)
+		cfg |= STEREOn_CONFIG_SPDIF_ENABLE;
+	writel(cfg, stereo_priv[stereo_id].stereo_base
+			+ ADSS_STEREOn_STEREO0_CONFIG_REG);
+}
+EXPORT_SYMBOL(ipq4019_stereo_spdif_enable);
+
+/*
+ * Enable/disable the swap within PCM sample
+ */
+void ipq4019_stereo_spdif_pcmswap(uint32_t enable, uint32_t stereo_id)
+{
+	uint32_t cfg;
+
+	cfg = readl(stereo_priv[stereo_id].stereo_base
+		+ ADSS_STEREOn_STEREO0_CONFIG_REG);
+
+	cfg &= ~(STEREOn_CONFIG_PCM_SWAP);
+	if (enable)
+		cfg |= STEREOn_CONFIG_PCM_SWAP;
+
+	writel(cfg, stereo_priv[stereo_id].stereo_base
+		+ ADSS_STEREOn_STEREO0_CONFIG_REG);
+}
+EXPORT_SYMBOL(ipq4019_stereo_spdif_pcmswap);
+
+/* Configure
+ * Data word size : Word size loaded into the PCM
+ *			register from the MBOX FIFO.
+ * I2S word size : Word size sent to the external I2S DAC.
+ *			When set to 32 bit words the PCM data
+ *			will be left justified in the I2S word.
+ */
+int ipq4019_cfg_bit_width(u32 bit_width, u32 stereo_id)
+{
+	u32 cfg, mask = 0;
+	unsigned long flags;
+
+	switch (bit_width) {
+	case SNDRV_PCM_FORMAT_S16_LE:
+	case SNDRV_PCM_FORMAT_S16_BE:
+		mask |= (STEREOn_CONFIG_DATA_WORD_SIZE(1) |
+			STEREOn_CONFIG_I2S_WORD_SIZE_16 |
+			STEREOn_CONFIG_MIC_WORD_SIZE_16);
+		break;
+	case SNDRV_PCM_FORMAT_S24_3LE:
+	case SNDRV_PCM_FORMAT_S24_3BE:
+		mask |= (STEREOn_CONFIG_DATA_WORD_SIZE(2) |
+			STEREOn_CONFIG_I2S_WORD_SIZE_32 |
+			STEREOn_CONFIG_MIC_WORD_SIZE_16);
+		break;
+	case SNDRV_PCM_FORMAT_S32_LE:
+	case SNDRV_PCM_FORMAT_S32_BE:
+		mask |= (STEREOn_CONFIG_DATA_WORD_SIZE(3) |
+			STEREOn_CONFIG_I2S_WORD_SIZE_32 |
+			STEREOn_CONFIG_MIC_WORD_SIZE_32);
+		break;
+	default:
+		return -ENOTSUPP;
+	}
+
+	spin_lock_irqsave(&stereo_priv[stereo_id].stereo_lock, flags);
+	cfg = readl(stereo_priv[stereo_id].stereo_base
+			+ ADSS_STEREOn_STEREO0_CONFIG_REG);
+	cfg &= ~STEREOn_CONFIG_DATA_WORD_SIZE_MASK;
+	cfg &= ~STEREOn_CONFIG_I2S_WORD_SIZE_32;
+	cfg &= ~STEREOn_CONFIG_MIC_WORD_SIZE_32;
+	cfg |= mask;
+	writel(cfg, stereo_priv[stereo_id].stereo_base
+			+ ADSS_STEREOn_STEREO0_CONFIG_REG);
+	spin_unlock_irqrestore(&stereo_priv[stereo_id].stereo_lock, flags);
+
+	return 0;
+}
+EXPORT_SYMBOL(ipq4019_cfg_bit_width);
+
+/*
+ * Configure stereo/mono mode
+ */
+void ipq4019_config_stereo_mode(u32 mode, u32 stereo_id)
+{
+	u32 cfg;
+	unsigned long flags;
+
+	spin_lock_irqsave(&stereo_priv[stereo_id].stereo_lock, flags);
+	cfg = readl(stereo_priv[stereo_id].stereo_base
+			+ ADSS_STEREOn_STEREO0_CONFIG_REG);
+	cfg &= ~STEREOn_CONFIG_STEREO_MONO_MASK;
+	if (mode == CH_STEREO)
+		cfg |= STEREOn_CONFIG_STEREO_MODE;
+	writel(cfg, stereo_priv[stereo_id].stereo_base
+			+ ADSS_STEREOn_STEREO0_CONFIG_REG);
+	spin_unlock_irqrestore(&stereo_priv[stereo_id].stereo_lock, flags);
+}
+EXPORT_SYMBOL(ipq4019_config_stereo_mode);
+
+/*
+ * Configure master mode
+ */
+void ipq4019_config_master(u32 enable, u32 stereo_id)
+{
+	u32 cfg;
+	unsigned long flags;
+
+	spin_lock_irqsave(&stereo_priv[stereo_id].stereo_lock, flags);
+	cfg = readl(stereo_priv[stereo_id].stereo_base
+			+ ADSS_STEREOn_STEREO0_CONFIG_REG);
+	cfg &= ~STEREOn_CONFIG_MASTER;
+	if (enable)
+		cfg |= STEREOn_CONFIG_MASTER;
+	writel(cfg, stereo_priv[stereo_id].stereo_base
+			+ ADSS_STEREOn_STEREO0_CONFIG_REG);
+	spin_unlock_irqrestore(&stereo_priv[stereo_id].stereo_lock, flags);
+}
+EXPORT_SYMBOL(ipq4019_config_master);
+
+/* Selects the raw clock source between
+ * divided audio clock and input master clock
+ * Val 0: Raw master clock is divided audio PLL clock
+ * Val 1: Raw master clock is MCLK IN
+ */
+void ipq4019_config_mclk_sel(u32 stereo_id, u32 val)
+{
+	u32 cfg;
+	unsigned long flags;
+
+	spin_lock_irqsave(&stereo_priv[stereo_id].stereo_lock, flags);
+	cfg = readl(stereo_priv[stereo_id].stereo_base
+			+ ADSS_STEREOn_STEREO0_CONFIG_REG);
+	cfg &= ~STEREOn_CONFIG_MCK_SEL;
+	cfg |= val;
+	writel(cfg, stereo_priv[stereo_id].stereo_base
+			+ ADSS_STEREOn_STEREO0_CONFIG_REG);
+	spin_unlock_irqrestore(&stereo_priv[stereo_id].stereo_lock, flags);
+
+}
+EXPORT_SYMBOL(ipq4019_config_mclk_sel);
+
+/*
+ * Strategy to clear the sample counter TX and RX registers
+ */
+void ipq4019_config_sample_cnt_clear_type(u32 stereo_id)
+{
+	u32 cfg;
+	unsigned long flags;
+
+	spin_lock_irqsave(&stereo_priv[stereo_id].stereo_lock, flags);
+	cfg = readl(stereo_priv[stereo_id].stereo_base
+			+ ADSS_STEREOn_STEREO0_CONFIG_REG);
+	/* 0 - write an explicit zero data through software
+	 *	to the TX and RX sample counter registers
+	 * 1 - software read of the TX and RX sample counter
+	 *	registers clears the counter registers
+	 */
+	cfg |= STEREOn_CONFIG_SAMPLE_CNT_CLEAR_TYPE; /* Write 1 */
+	writel(cfg, stereo_priv[stereo_id].stereo_base
+			+ ADSS_STEREOn_STEREO0_CONFIG_REG);
+	spin_unlock_irqrestore(&stereo_priv[stereo_id].stereo_lock, flags);
+}
+EXPORT_SYMBOL(ipq4019_config_sample_cnt_clear_type);
+
+static const struct of_device_id ipq4019_audio_stereo_id_table[] = {
+	{ .compatible = "qca,ipq4019-stereo" },
+	{},
+};
+MODULE_DEVICE_TABLE(of, ipq4019_audio_stereo_id_table);
+
+static int ipq4019_audio_stereo_probe(struct platform_device *pdev)
+{
+	struct resource *res;
+	struct stereo_priv_data *spd;
+	struct device_node *np = pdev->dev.of_node;
+	u32 stereo_port_id = 0;
+
+	if (of_property_read_u32(np, "stereo-index", &stereo_port_id)) {
+		dev_err(&pdev->dev, "Error reading stereo-index\n");
+		return -EINVAL;
+	}
+	if (stereo_port_id >= MAX_STEREO_ENTRIES)
+		return -ENODEV;
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	spd = &stereo_priv[stereo_port_id];
+	spd->stereo_base = devm_ioremap_resource(&pdev->dev, res);
+	if (IS_ERR(spd->stereo_base))
+		return PTR_ERR(spd->stereo_base);
+
+	spin_lock_init(&spd->stereo_lock);
+	return 0;
+}
+
+static struct platform_driver ipq4019_audio_stereo_driver = {
+	.probe = ipq4019_audio_stereo_probe,
+	.driver = {
+		.name = "ipq4019-stereo",
+		.of_match_table = ipq4019_audio_stereo_id_table,
+	},
+};
+
+module_platform_driver(ipq4019_audio_stereo_driver);
+
+MODULE_ALIAS("platform:ipq4019-stereo");
+MODULE_LICENSE("Dual BSD/GPL");
+MODULE_DESCRIPTION("IPQ4019 AUDIO Stereo driver");
diff --git a/sound/soc/qcom/ipq4019/ipq4019.c b/sound/soc/qcom/ipq4019/ipq4019.c
new file mode 100644
index 0000000..a08fa5e6
--- /dev/null
+++ b/sound/soc/qcom/ipq4019/ipq4019.c
@@ -0,0 +1,121 @@
+/*
+ * Copyright (c) 2015-2016, The Linux Foundation. All rights reserved.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ */
+
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/module.h>
+#include <linux/gpio.h>
+#include <linux/platform_device.h>
+#include <linux/of_platform.h>
+#include <linux/gpio.h>
+#include <linux/slab.h>
+#include <sound/core.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include <sound/pcm.h>
+#include <sound/jack.h>
+#include <linux/io.h>
+
+static struct snd_soc_dai_link ipq4019_snd_dai[] = {
+	{
+		.name		= "IPQ4019 Media1",
+		.stream_name	= "I2S",
+		/* CPU DAI Name */
+		.cpu_dai_name	= "qca-i2s-dai",
+		/* Platform Driver Name */
+		.platform_name	= "7709000.qca-pcm-i2s",
+		/* Codec DAI Name */
+		.codec_dai_name	= "qca-i2s-codec-dai",
+		/*Codec Driver Name */
+		.codec_name	= "qca_codec.0-0012",
+		.dai_fmt = (SND_SOC_DAIFMT_I2S |
+				SND_SOC_DAIFMT_NB_NF |
+				SND_SOC_DAIFMT_CBS_CFS),
+	},
+	{
+		.name		= "IPQ4019 Media2",
+		.stream_name	= "TDM",
+		.cpu_dai_name	= "qca-tdm-dai",
+		.platform_name	= "7709000.qca-pcm-tdm",
+		.codec_dai_name	= "qca-tdm-codec-dai",
+		.codec_name	= "qca_codec.0-0012",
+	},
+	{
+		.name		= "IPQ4019 Media3",
+		.stream_name	= "I2S1",
+		.cpu_dai_name	= "qca-i2s1-dai",
+		.platform_name	= "770b000.qca-pcm-i2s1",
+		.codec_dai_name	= "qca-i2s1-codec-dai",
+		.codec_name	= "qca_codec.0-0012",
+	},
+	{
+		.name		= "IPQ4019 Media4",
+		.stream_name	= "I2S2",
+		.cpu_dai_name	= "qca-i2s2-dai",
+		.platform_name	= "770d000.qca-pcm-i2s2",
+		.codec_dai_name	= "qca-i2s2-codec-dai",
+		.codec_name	= "qca_codec.0-0012",
+	},
+	{
+		.name           = "IPQ4019 Media5",
+		.stream_name    = "SPDIF",
+		.cpu_dai_name	= "qca-spdif-dai",
+		.platform_name  = "7707000.qca-pcm-spdif",
+		.codec_dai_name = "qca-spdif-codec-dai",
+		.codec_name	= "qca_codec.0-0012",
+	},
+};
+
+static struct snd_soc_card snd_soc_card_qca = {
+	.name		= "ipq4019_snd_card",
+	.dai_link	= ipq4019_snd_dai,
+	.num_links	= ARRAY_SIZE(ipq4019_snd_dai),
+};
+
+static const struct of_device_id ipq4019_audio_id_table[] = {
+	{ .compatible = "qca,ipq4019-audio" },
+	{},
+};
+MODULE_DEVICE_TABLE(of, ipq4019_audio_id_table);
+
+static int ipq4019_audio_probe(struct platform_device *pdev)
+{
+	int ret;
+	struct snd_soc_card *card = &snd_soc_card_qca;
+
+	card->dev = &pdev->dev;
+
+	ret = devm_snd_soc_register_card(&pdev->dev, card);
+	if (ret)
+		dev_err(&pdev->dev, "snd_soc_register_card() failed:%d\n", ret);
+
+	return ret;
+}
+
+static struct platform_driver ipq4019_audio_driver = {
+	.driver = {
+		.name = "ipq4019_audio",
+		.of_match_table = ipq4019_audio_id_table,
+	},
+	.probe = ipq4019_audio_probe,
+};
+
+module_platform_driver(ipq4019_audio_driver);
+
+MODULE_ALIAS("platform:ipq4019_audio");
+MODULE_LICENSE("Dual BSD/GPL");
+MODULE_DESCRIPTION("ALSA SoC IPQ4019 Machine Driver");
-- 
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
a Linux Foundation Collaborative Project


^ permalink raw reply related	[flat|nested] 24+ messages in thread

* Re: [PATCH 4/4] qcom: ipq4019: Add ASoC driver modules
  2016-07-15  7:07 ` [PATCH 4/4] qcom: ipq4019: Add ASoC driver modules njaigane
@ 2016-07-15 12:52     ` Mark Brown
  0 siblings, 0 replies; 24+ messages in thread
From: Mark Brown @ 2016-07-15 12:52 UTC (permalink / raw)
  To: njaigane
  Cc: linux-arm-msm, linux, devicetree, linux-kernel, linux-soc,
	linux-arm-kernel, twp, andy.gross, david.brown, robh+dt,
	pawel.moll, mark.rutland, ijc+devicetree, galak, linux,
	mturquette, sboyd, linus.walleij, plai, bgoswami, lgirdwood,
	perex, tiwai, bjorn.andersson, varada, pradeepb, snlakshm,
	linux-clk, linux-gpio, alsa-devel, bselvara

[-- Attachment #1: Type: text/plain, Size: 1307 bytes --]

On Fri, Jul 15, 2016 at 12:37:06PM +0530, njaigane@codeaurora.org wrote:

>  sound/soc/qcom/Kconfig                     |  47 ++
>  sound/soc/qcom/Makefile                    |   1 +
>  sound/soc/qcom/ipq4019/Makefile            |  16 +
>  sound/soc/qcom/ipq4019/ipq4019-adss.c      | 407 ++++++++++++++
>  sound/soc/qcom/ipq4019/ipq4019-adss.h      | 432 +++++++++++++++
>  sound/soc/qcom/ipq4019/ipq4019-codec.c     | 475 +++++++++++++++++
>  sound/soc/qcom/ipq4019/ipq4019-codec.h     |  91 ++++
>  sound/soc/qcom/ipq4019/ipq4019-cpu-dai.c   | 687 ++++++++++++++++++++++++
>  sound/soc/qcom/ipq4019/ipq4019-mbox.c      | 825 +++++++++++++++++++++++++++++
>  sound/soc/qcom/ipq4019/ipq4019-mbox.h      | 146 +++++
>  sound/soc/qcom/ipq4019/ipq4019-pcm-i2s.c   | 609 +++++++++++++++++++++
>  sound/soc/qcom/ipq4019/ipq4019-pcm-spdif.c | 664 +++++++++++++++++++++++
>  sound/soc/qcom/ipq4019/ipq4019-pcm-tdm.c   | 609 +++++++++++++++++++++
>  sound/soc/qcom/ipq4019/ipq4019-pcm.h       |  37 ++
>  sound/soc/qcom/ipq4019/ipq4019-stereo.c    | 313 +++++++++++
>  sound/soc/qcom/ipq4019/ipq4019.c           | 121 +++++

This is *far* too big to be a single patch.  Please at the very least
split this up into one patch per driver, look at the git history of
other drivers for examples of splitting things up.

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 473 bytes --]

^ permalink raw reply	[flat|nested] 24+ messages in thread

* [PATCH 4/4] qcom: ipq4019: Add ASoC driver modules
@ 2016-07-15 12:52     ` Mark Brown
  0 siblings, 0 replies; 24+ messages in thread
From: Mark Brown @ 2016-07-15 12:52 UTC (permalink / raw)
  To: linux-arm-kernel

On Fri, Jul 15, 2016 at 12:37:06PM +0530, njaigane at codeaurora.org wrote:

>  sound/soc/qcom/Kconfig                     |  47 ++
>  sound/soc/qcom/Makefile                    |   1 +
>  sound/soc/qcom/ipq4019/Makefile            |  16 +
>  sound/soc/qcom/ipq4019/ipq4019-adss.c      | 407 ++++++++++++++
>  sound/soc/qcom/ipq4019/ipq4019-adss.h      | 432 +++++++++++++++
>  sound/soc/qcom/ipq4019/ipq4019-codec.c     | 475 +++++++++++++++++
>  sound/soc/qcom/ipq4019/ipq4019-codec.h     |  91 ++++
>  sound/soc/qcom/ipq4019/ipq4019-cpu-dai.c   | 687 ++++++++++++++++++++++++
>  sound/soc/qcom/ipq4019/ipq4019-mbox.c      | 825 +++++++++++++++++++++++++++++
>  sound/soc/qcom/ipq4019/ipq4019-mbox.h      | 146 +++++
>  sound/soc/qcom/ipq4019/ipq4019-pcm-i2s.c   | 609 +++++++++++++++++++++
>  sound/soc/qcom/ipq4019/ipq4019-pcm-spdif.c | 664 +++++++++++++++++++++++
>  sound/soc/qcom/ipq4019/ipq4019-pcm-tdm.c   | 609 +++++++++++++++++++++
>  sound/soc/qcom/ipq4019/ipq4019-pcm.h       |  37 ++
>  sound/soc/qcom/ipq4019/ipq4019-stereo.c    | 313 +++++++++++
>  sound/soc/qcom/ipq4019/ipq4019.c           | 121 +++++

This is *far* too big to be a single patch.  Please at the very least
split this up into one patch per driver, look at the git history of
other drivers for examples of splitting things up.
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 473 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20160715/c7400e9e/attachment.sig>

^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: [PATCH 0/4] Qualcomm IPQ4019 Audio driver addition
  2016-07-15  7:07 ` njaigane
  (?)
@ 2016-07-15 12:56     ` Mark Brown
  -1 siblings, 0 replies; 24+ messages in thread
From: Mark Brown @ 2016-07-15 12:56 UTC (permalink / raw)
  To: njaigane-sgV2jX0FEOL9JmXXK+q4OQ
  Cc: linux-arm-msm-u79uwXL29TY76Z2rM5mHXA,
	linux-A+ZNKFmMK5xy9aJCnZT0Uw, devicetree-u79uwXL29TY76Z2rM5mHXA,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	linux-soc-u79uwXL29TY76Z2rM5mHXA,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	twp-sgV2jX0FEOL9JmXXK+q4OQ, andy.gross-QSEj5FYQhm4dnm+yROfE0A,
	david.brown-QSEj5FYQhm4dnm+yROfE0A,
	robh+dt-DgEjT+Ai2ygdnm+yROfE0A, pawel.moll-5wv7dgnIgG8,
	mark.rutland-5wv7dgnIgG8, ijc+devicetree-KcIKpvwj1kUDXYZnReoRVg,
	galak-sgV2jX0FEOL9JmXXK+q4OQ, linux-I+IVW8TIWO2tmTQ+vhA3Yw,
	mturquette-rdvid1DuHRBWk0Htik3J/w, sboyd-sgV2jX0FEOL9JmXXK+q4OQ,
	linus.walleij-QSEj5FYQhm4dnm+yROfE0A,
	plai-sgV2jX0FEOL9JmXXK+q4OQ, bgoswami-sgV2jX0FEOL9JmXXK+q4OQ,
	lgirdwood-Re5JQEeQqe8AvxtiuMwx3w, perex-/Fr2/VpizcU,
	tiwai-IBi9RG/b67k, bjorn.andersson-QSEj5FYQhm4dnm+yROfE0A,
	varada-sgV2jX0FEOL9JmXXK+q4OQ, pradeepb-sgV2jX0FEOL9JmXXK+q4OQ,
	snlakshm-sgV2jX0FEOL9JmXXK+q4OQ,
	linux-clk-u79uwXL29TY76Z2rM5mHXA,
	linux-gpio-u79uwXL29TY76Z2rM5mHXA,
	alsa-devel-K7yf7f+aM1XWsZ/bQMPhNw,
	bselvara-sgV2jX0FEOL9JmXXK+q4OQ

[-- Attachment #1: Type: text/plain, Size: 920 bytes --]

On Fri, Jul 15, 2016 at 12:37:02PM +0530, njaigane-sgV2jX0FEOL9JmXXK+q4OQ@public.gmane.org wrote:
> From: Jaiganesh Narayanan <njaigane-sgV2jX0FEOL9JmXXK+q4OQ@public.gmane.org>
> 
> These patches add the support for Qualcomm IPQ4019 ASoC
> with the ALSA based audio drivers. The patches are broken
> 
> 1. Device Tree support
> 2. Audio clock driver support
> 3. TLMM / Pinctrl support
> 4. ALSA based audio drivers

You need to completely rework how you're posting this so it can be
reviewed, probably splitting it into separate patch serieses - please
see SubmittingPatches for an overview of what people are expecting, and
as I said in reply to one of the patches looking at git can also be
helpful.  I'd suggest sending the drivers for each subsystem as a
separate patch series, there will be some interdependency in terms of
getting things running but not in terms of getting the patches applied.

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 473 bytes --]

^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: [PATCH 0/4] Qualcomm IPQ4019 Audio driver addition
@ 2016-07-15 12:56     ` Mark Brown
  0 siblings, 0 replies; 24+ messages in thread
From: Mark Brown @ 2016-07-15 12:56 UTC (permalink / raw)
  To: njaigane
  Cc: linux-arm-msm, linux, devicetree, linux-kernel, linux-soc,
	linux-arm-kernel, twp, andy.gross, david.brown, robh+dt,
	pawel.moll, mark.rutland, ijc+devicetree, galak, linux,
	mturquette, sboyd, linus.walleij, plai, bgoswami, lgirdwood,
	perex, tiwai, bjorn.andersson, varada, pradeepb, snlakshm,
	linux-clk, linux-gpio, alsa-devel, bselvara

[-- Attachment #1: Type: text/plain, Size: 870 bytes --]

On Fri, Jul 15, 2016 at 12:37:02PM +0530, njaigane@codeaurora.org wrote:
> From: Jaiganesh Narayanan <njaigane@codeaurora.org>
> 
> These patches add the support for Qualcomm IPQ4019 ASoC
> with the ALSA based audio drivers. The patches are broken
> 
> 1. Device Tree support
> 2. Audio clock driver support
> 3. TLMM / Pinctrl support
> 4. ALSA based audio drivers

You need to completely rework how you're posting this so it can be
reviewed, probably splitting it into separate patch serieses - please
see SubmittingPatches for an overview of what people are expecting, and
as I said in reply to one of the patches looking at git can also be
helpful.  I'd suggest sending the drivers for each subsystem as a
separate patch series, there will be some interdependency in terms of
getting things running but not in terms of getting the patches applied.

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 473 bytes --]

^ permalink raw reply	[flat|nested] 24+ messages in thread

* [PATCH 0/4] Qualcomm IPQ4019 Audio driver addition
@ 2016-07-15 12:56     ` Mark Brown
  0 siblings, 0 replies; 24+ messages in thread
From: Mark Brown @ 2016-07-15 12:56 UTC (permalink / raw)
  To: linux-arm-kernel

On Fri, Jul 15, 2016 at 12:37:02PM +0530, njaigane at codeaurora.org wrote:
> From: Jaiganesh Narayanan <njaigane@codeaurora.org>
> 
> These patches add the support for Qualcomm IPQ4019 ASoC
> with the ALSA based audio drivers. The patches are broken
> 
> 1. Device Tree support
> 2. Audio clock driver support
> 3. TLMM / Pinctrl support
> 4. ALSA based audio drivers

You need to completely rework how you're posting this so it can be
reviewed, probably splitting it into separate patch serieses - please
see SubmittingPatches for an overview of what people are expecting, and
as I said in reply to one of the patches looking at git can also be
helpful.  I'd suggest sending the drivers for each subsystem as a
separate patch series, there will be some interdependency in terms of
getting things running but not in terms of getting the patches applied.
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 473 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20160715/d217733d/attachment-0001.sig>

^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: [PATCH 3/4] qcom: ipq4019: ASoC tlmm/pinctrl support
  2016-07-15  7:07   ` njaigane at codeaurora.org
  (?)
@ 2016-07-15 19:15       ` Bjorn Andersson
  -1 siblings, 0 replies; 24+ messages in thread
From: Bjorn Andersson @ 2016-07-15 19:15 UTC (permalink / raw)
  To: njaigane-sgV2jX0FEOL9JmXXK+q4OQ
  Cc: linux-arm-msm-u79uwXL29TY76Z2rM5mHXA,
	linux-A+ZNKFmMK5xy9aJCnZT0Uw, devicetree-u79uwXL29TY76Z2rM5mHXA,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	linux-soc-u79uwXL29TY76Z2rM5mHXA,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	twp-sgV2jX0FEOL9JmXXK+q4OQ, andy.gross-QSEj5FYQhm4dnm+yROfE0A,
	david.brown-QSEj5FYQhm4dnm+yROfE0A,
	robh+dt-DgEjT+Ai2ygdnm+yROfE0A, pawel.moll-5wv7dgnIgG8,
	mark.rutland-5wv7dgnIgG8, ijc+devicetree-KcIKpvwj1kUDXYZnReoRVg,
	galak-sgV2jX0FEOL9JmXXK+q4OQ, linux-I+IVW8TIWO2tmTQ+vhA3Yw,
	mturquette-rdvid1DuHRBWk0Htik3J/w, sboyd-sgV2jX0FEOL9JmXXK+q4OQ,
	linus.walleij-QSEj5FYQhm4dnm+yROfE0A,
	plai-sgV2jX0FEOL9JmXXK+q4OQ, bgoswami-sgV2jX0FEOL9JmXXK+q4OQ,
	lgirdwood-Re5JQEeQqe8AvxtiuMwx3w, broonie-DgEjT+Ai2ygdnm+yROfE0A,
	perex-/Fr2/VpizcU, tiwai-IBi9RG/b67k,
	varada-sgV2jX0FEOL9JmXXK+q4OQ, pradeepb-sgV2jX0FEOL9JmXXK+q4OQ,
	snlakshm-sgV2jX0FEOL9JmXXK+q4OQ,
	linux-clk-u79uwXL29TY76Z2rM5mHXA,
	linux-gpio-u79uwXL29TY76Z2rM5mHXA,
	alsa-devel-K7yf7f+aM1XWsZ/bQMPhNw,
	bselvara-sgV2jX0FEOL9JmXXK+q4OQ

On Fri 15 Jul 00:07 PDT 2016, njaigane-sgV2jX0FEOL9JmXXK+q4OQ@public.gmane.org wrote:

> From: Jaiganesh Narayanan <njaigane-sgV2jX0FEOL9JmXXK+q4OQ@public.gmane.org>
> 
> This patch adds the tlmm/pinctrl support for IPQ4019 ASoC.
> 
> Signed-off-by: Jaiganesh Narayanan <njaigane-sgV2jX0FEOL9JmXXK+q4OQ@public.gmane.org>
> ---
>  drivers/pinctrl/qcom/pinctrl-ipq4019.c | 116 +++++++++++++++++++++++++--------
>  1 file changed, 88 insertions(+), 28 deletions(-)
> 
> diff --git a/drivers/pinctrl/qcom/pinctrl-ipq4019.c b/drivers/pinctrl/qcom/pinctrl-ipq4019.c
[..]
> +	qca_mux_i2s_rx_mclk,
> +	qca_mux_i2s_rx_bclk,
> +	qca_mux_i2s_rx_fsync,
> +	qca_mux_i2s_rxd,
> +	qca_mux_i2s_tx_mclk,
> +	qca_mux_i2s_tx_bclk,
> +	qca_mux_i2s_tx_fsync,
> +	qca_mux_i2s_txd1,
> +	qca_mux_i2s_txd2,
> +	qca_mux_i2s_txd3,
> +	qca_mux_i2s_spdif_out,
> +	qca_mux_i2s_spdif_in,

I would recommend reducing this to "i2s_rx", "i2s_tx", "spdif_rx"
and "spdif_tx", as this will make the dts cleaner.

Regards,
Bjorn
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: [PATCH 3/4] qcom: ipq4019: ASoC tlmm/pinctrl support
@ 2016-07-15 19:15       ` Bjorn Andersson
  0 siblings, 0 replies; 24+ messages in thread
From: Bjorn Andersson @ 2016-07-15 19:15 UTC (permalink / raw)
  To: njaigane
  Cc: linux-arm-msm, linux, devicetree, linux-kernel, linux-soc,
	linux-arm-kernel, twp, andy.gross, david.brown, robh+dt,
	pawel.moll, mark.rutland, ijc+devicetree, galak, linux,
	mturquette, sboyd, linus.walleij, plai, bgoswami, lgirdwood,
	broonie, perex, tiwai, varada, pradeepb, snlakshm, linux-clk,
	linux-gpio, alsa-devel, bselvara

On Fri 15 Jul 00:07 PDT 2016, njaigane@codeaurora.org wrote:

> From: Jaiganesh Narayanan <njaigane@codeaurora.org>
> 
> This patch adds the tlmm/pinctrl support for IPQ4019 ASoC.
> 
> Signed-off-by: Jaiganesh Narayanan <njaigane@codeaurora.org>
> ---
>  drivers/pinctrl/qcom/pinctrl-ipq4019.c | 116 +++++++++++++++++++++++++--------
>  1 file changed, 88 insertions(+), 28 deletions(-)
> 
> diff --git a/drivers/pinctrl/qcom/pinctrl-ipq4019.c b/drivers/pinctrl/qcom/pinctrl-ipq4019.c
[..]
> +	qca_mux_i2s_rx_mclk,
> +	qca_mux_i2s_rx_bclk,
> +	qca_mux_i2s_rx_fsync,
> +	qca_mux_i2s_rxd,
> +	qca_mux_i2s_tx_mclk,
> +	qca_mux_i2s_tx_bclk,
> +	qca_mux_i2s_tx_fsync,
> +	qca_mux_i2s_txd1,
> +	qca_mux_i2s_txd2,
> +	qca_mux_i2s_txd3,
> +	qca_mux_i2s_spdif_out,
> +	qca_mux_i2s_spdif_in,

I would recommend reducing this to "i2s_rx", "i2s_tx", "spdif_rx"
and "spdif_tx", as this will make the dts cleaner.

Regards,
Bjorn

^ permalink raw reply	[flat|nested] 24+ messages in thread

* [PATCH 3/4] qcom: ipq4019: ASoC tlmm/pinctrl support
@ 2016-07-15 19:15       ` Bjorn Andersson
  0 siblings, 0 replies; 24+ messages in thread
From: Bjorn Andersson @ 2016-07-15 19:15 UTC (permalink / raw)
  To: linux-arm-kernel

On Fri 15 Jul 00:07 PDT 2016, njaigane at codeaurora.org wrote:

> From: Jaiganesh Narayanan <njaigane@codeaurora.org>
> 
> This patch adds the tlmm/pinctrl support for IPQ4019 ASoC.
> 
> Signed-off-by: Jaiganesh Narayanan <njaigane@codeaurora.org>
> ---
>  drivers/pinctrl/qcom/pinctrl-ipq4019.c | 116 +++++++++++++++++++++++++--------
>  1 file changed, 88 insertions(+), 28 deletions(-)
> 
> diff --git a/drivers/pinctrl/qcom/pinctrl-ipq4019.c b/drivers/pinctrl/qcom/pinctrl-ipq4019.c
[..]
> +	qca_mux_i2s_rx_mclk,
> +	qca_mux_i2s_rx_bclk,
> +	qca_mux_i2s_rx_fsync,
> +	qca_mux_i2s_rxd,
> +	qca_mux_i2s_tx_mclk,
> +	qca_mux_i2s_tx_bclk,
> +	qca_mux_i2s_tx_fsync,
> +	qca_mux_i2s_txd1,
> +	qca_mux_i2s_txd2,
> +	qca_mux_i2s_txd3,
> +	qca_mux_i2s_spdif_out,
> +	qca_mux_i2s_spdif_in,

I would recommend reducing this to "i2s_rx", "i2s_tx", "spdif_rx"
and "spdif_tx", as this will make the dts cleaner.

Regards,
Bjorn

^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: [PATCH 3/4] qcom: ipq4019: ASoC tlmm/pinctrl support
  2016-07-15  7:07   ` njaigane at codeaurora.org
@ 2016-07-15 20:23     ` Andy Gross
  -1 siblings, 0 replies; 24+ messages in thread
From: Andy Gross @ 2016-07-15 20:23 UTC (permalink / raw)
  To: njaigane
  Cc: linux-arm-msm, linux, devicetree, linux-kernel, linux-soc,
	linux-arm-kernel, twp, david.brown, robh+dt, pawel.moll,
	mark.rutland, ijc+devicetree, galak, linux, mturquette, sboyd,
	linus.walleij, plai, bgoswami, lgirdwood, broonie, perex, tiwai,
	bjorn.andersson, varada, pradeepb, snlakshm, linux-clk,
	linux-gpio, alsa-devel, bselvara

On Fri, Jul 15, 2016 at 12:37:05PM +0530, njaigane@codeaurora.org wrote:
> From: Jaiganesh Narayanan <njaigane@codeaurora.org>
> 
> This patch adds the tlmm/pinctrl support for IPQ4019 ASoC.
> 
> Signed-off-by: Jaiganesh Narayanan <njaigane@codeaurora.org>
> ---
>  drivers/pinctrl/qcom/pinctrl-ipq4019.c | 116 +++++++++++++++++++++++++--------
>  1 file changed, 88 insertions(+), 28 deletions(-)
> 
> diff --git a/drivers/pinctrl/qcom/pinctrl-ipq4019.c b/drivers/pinctrl/qcom/pinctrl-ipq4019.c
> index b68ae42..bc22597 100644
> --- a/drivers/pinctrl/qcom/pinctrl-ipq4019.c
> +++ b/drivers/pinctrl/qcom/pinctrl-ipq4019.c
> @@ -1,5 +1,5 @@
>  /*
> - * Copyright (c) 2015, The Linux Foundation. All rights reserved.
> + * Copyright (c) 2015-2016, The Linux Foundation. All rights reserved.
>   *
>   * This program is free software; you can redistribute it and/or modify
>   * it under the terms of the GNU General Public License version 2 and
> @@ -283,6 +283,18 @@ enum ipq4019_functions {
>  	qca_mux_blsp_uart0,
>  	qca_mux_blsp_spi1,
>  	qca_mux_blsp_spi0,
> +	qca_mux_i2s_rx_mclk,
> +	qca_mux_i2s_rx_bclk,
> +	qca_mux_i2s_rx_fsync,
> +	qca_mux_i2s_rxd,
> +	qca_mux_i2s_tx_mclk,
> +	qca_mux_i2s_tx_bclk,
> +	qca_mux_i2s_tx_fsync,
> +	qca_mux_i2s_txd1,
> +	qca_mux_i2s_txd2,
> +	qca_mux_i2s_txd3,
> +	qca_mux_i2s_spdif_out,
> +	qca_mux_i2s_spdif_in,

You'll also need to add all of these to the
Documentation/devicetree/bindings/pinctrl/qcom,ipq4019-pinctrl.txt

I was also going to suggest just using qca_i2s and having a single function, but
it seems like there is at least 1 pin that supports more than one i2s mode.

Regards,
Andy

^ permalink raw reply	[flat|nested] 24+ messages in thread

* [PATCH 3/4] qcom: ipq4019: ASoC tlmm/pinctrl support
@ 2016-07-15 20:23     ` Andy Gross
  0 siblings, 0 replies; 24+ messages in thread
From: Andy Gross @ 2016-07-15 20:23 UTC (permalink / raw)
  To: linux-arm-kernel

On Fri, Jul 15, 2016 at 12:37:05PM +0530, njaigane at codeaurora.org wrote:
> From: Jaiganesh Narayanan <njaigane@codeaurora.org>
> 
> This patch adds the tlmm/pinctrl support for IPQ4019 ASoC.
> 
> Signed-off-by: Jaiganesh Narayanan <njaigane@codeaurora.org>
> ---
>  drivers/pinctrl/qcom/pinctrl-ipq4019.c | 116 +++++++++++++++++++++++++--------
>  1 file changed, 88 insertions(+), 28 deletions(-)
> 
> diff --git a/drivers/pinctrl/qcom/pinctrl-ipq4019.c b/drivers/pinctrl/qcom/pinctrl-ipq4019.c
> index b68ae42..bc22597 100644
> --- a/drivers/pinctrl/qcom/pinctrl-ipq4019.c
> +++ b/drivers/pinctrl/qcom/pinctrl-ipq4019.c
> @@ -1,5 +1,5 @@
>  /*
> - * Copyright (c) 2015, The Linux Foundation. All rights reserved.
> + * Copyright (c) 2015-2016, The Linux Foundation. All rights reserved.
>   *
>   * This program is free software; you can redistribute it and/or modify
>   * it under the terms of the GNU General Public License version 2 and
> @@ -283,6 +283,18 @@ enum ipq4019_functions {
>  	qca_mux_blsp_uart0,
>  	qca_mux_blsp_spi1,
>  	qca_mux_blsp_spi0,
> +	qca_mux_i2s_rx_mclk,
> +	qca_mux_i2s_rx_bclk,
> +	qca_mux_i2s_rx_fsync,
> +	qca_mux_i2s_rxd,
> +	qca_mux_i2s_tx_mclk,
> +	qca_mux_i2s_tx_bclk,
> +	qca_mux_i2s_tx_fsync,
> +	qca_mux_i2s_txd1,
> +	qca_mux_i2s_txd2,
> +	qca_mux_i2s_txd3,
> +	qca_mux_i2s_spdif_out,
> +	qca_mux_i2s_spdif_in,

You'll also need to add all of these to the
Documentation/devicetree/bindings/pinctrl/qcom,ipq4019-pinctrl.txt

I was also going to suggest just using qca_i2s and having a single function, but
it seems like there is at least 1 pin that supports more than one i2s mode.

Regards,
Andy

^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: [PATCH 1/4] qcom: ipq4019: Add ipq4019 ASoC device tree changes
  2016-07-15  7:07   ` njaigane at codeaurora.org
@ 2016-07-17 20:03     ` Rob Herring
  -1 siblings, 0 replies; 24+ messages in thread
From: Rob Herring @ 2016-07-17 20:03 UTC (permalink / raw)
  To: njaigane
  Cc: linux-arm-msm, linux, devicetree, linux-kernel, linux-soc,
	linux-arm-kernel, twp, andy.gross, david.brown, pawel.moll,
	mark.rutland, ijc+devicetree, galak, linux, mturquette, sboyd,
	linus.walleij, plai, bgoswami, lgirdwood, broonie, perex, tiwai,
	bjorn.andersson, varada, pradeepb, snlakshm, linux-clk,
	linux-gpio, alsa-devel, bselvara

On Fri, Jul 15, 2016 at 12:37:03PM +0530, njaigane@codeaurora.org wrote:
> From: Jaiganesh Narayanan <njaigane@codeaurora.org>
> 
> This patch adds the ipq4019 ASoC device tree changes and the
> binding documentation for pcm, spdif, tdm, stereo, codec, mbox,
> adss modules
> 
> Signed-off-by: Jaiganesh Narayanan <njaigane@codeaurora.org>
> ---
>  .../bindings/sound/qca,ipq4019-audio-adss.txt      |  20 ++
>  .../bindings/sound/qca,ipq4019-audio.txt           |  13 ++
>  .../bindings/sound/qca,ipq4019-codec.txt           |  15 ++
>  .../devicetree/bindings/sound/qca,ipq4019-i2s.txt  |  33 +++
>  .../devicetree/bindings/sound/qca,ipq4019-i2s1.txt |  29 +++
>  .../devicetree/bindings/sound/qca,ipq4019-i2s2.txt |  29 +++
>  .../devicetree/bindings/sound/qca,ipq4019-mbox.txt |  23 ++
>  .../bindings/sound/qca,ipq4019-pcm-i2s.txt         |  15 ++
>  .../bindings/sound/qca,ipq4019-pcm-i2s1.txt        |  15 ++
>  .../bindings/sound/qca,ipq4019-pcm-i2s2.txt        |  15 ++
>  .../bindings/sound/qca,ipq4019-pcm-spdif.txt       |  15 ++
>  .../bindings/sound/qca,ipq4019-pcm-tdm.txt         |  15 ++
>  .../bindings/sound/qca,ipq4019-spdif.txt           |  35 +++
>  .../bindings/sound/qca,ipq4019-stereo.txt          |  17 ++
>  .../devicetree/bindings/sound/qca,ipq4019-tdm.txt  |  33 +++
>  arch/arm/boot/dts/qcom-ipq4019-ap.dk01.1.dtsi      | 195 ++++++++++++++--
>  arch/arm/boot/dts/qcom-ipq4019.dtsi                | 247 ++++++++++++++++++++-
>  17 files changed, 742 insertions(+), 22 deletions(-)
>  create mode 100644 Documentation/devicetree/bindings/sound/qca,ipq4019-audio-adss.txt
>  create mode 100644 Documentation/devicetree/bindings/sound/qca,ipq4019-audio.txt
>  create mode 100644 Documentation/devicetree/bindings/sound/qca,ipq4019-codec.txt
>  create mode 100644 Documentation/devicetree/bindings/sound/qca,ipq4019-i2s.txt
>  create mode 100644 Documentation/devicetree/bindings/sound/qca,ipq4019-i2s1.txt
>  create mode 100644 Documentation/devicetree/bindings/sound/qca,ipq4019-i2s2.txt
>  create mode 100644 Documentation/devicetree/bindings/sound/qca,ipq4019-mbox.txt
>  create mode 100644 Documentation/devicetree/bindings/sound/qca,ipq4019-pcm-i2s.txt
>  create mode 100644 Documentation/devicetree/bindings/sound/qca,ipq4019-pcm-i2s1.txt
>  create mode 100644 Documentation/devicetree/bindings/sound/qca,ipq4019-pcm-i2s2.txt
>  create mode 100644 Documentation/devicetree/bindings/sound/qca,ipq4019-pcm-spdif.txt
>  create mode 100644 Documentation/devicetree/bindings/sound/qca,ipq4019-pcm-tdm.txt
>  create mode 100644 Documentation/devicetree/bindings/sound/qca,ipq4019-spdif.txt
>  create mode 100644 Documentation/devicetree/bindings/sound/qca,ipq4019-stereo.txt
>  create mode 100644 Documentation/devicetree/bindings/sound/qca,ipq4019-tdm.txt
> 
> diff --git a/Documentation/devicetree/bindings/sound/qca,ipq4019-audio-adss.txt b/Documentation/devicetree/bindings/sound/qca,ipq4019-audio-adss.txt
> new file mode 100644
> index 0000000..5ba2b9d
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/sound/qca,ipq4019-audio-adss.txt
> @@ -0,0 +1,20 @@
> +* Qualcomm Technologies IPQ4019 ASoC audio subsystem driver
> +
> +This node models the Qualcomm Technologies IPQ4019 ASoC audio subsystem driver
> +
> +Required properties:
> +
> +- compatible	: "qca,ipq4019-audio-adss"
> +- reg		: should have the stereo register address, length
> +- resets	: references to the reset controllers
> +- reset-names	: should be "blk_rst"
> +
> +
> +Example:
> +audio: audio@7700000 {
> +	compatible = "qca,ipq4019-audio-adss";
> +	reg = <0x7700000 0x34>;
> +	resets = <&gcc AUDIO_BLK_ARES>;
> +	reset-names = "blk_rst";
> +	status = "disabled";
> +};
> diff --git a/Documentation/devicetree/bindings/sound/qca,ipq4019-audio.txt b/Documentation/devicetree/bindings/sound/qca,ipq4019-audio.txt
> new file mode 100644
> index 0000000..fde039f
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/sound/qca,ipq4019-audio.txt
> @@ -0,0 +1,13 @@
> +* Qualcomm Technologies IPQ4019 ASoC machine driver
> +
> +This node models the Qualcomm Technologies IPQ4019 ASoC machine driver

ASoC machine driver is a Linuxism.

> +
> +Required properties:
> +
> +- compatible		: "qca,ipq4019-audio"
> +
> +Example:
> +
> +sound: sound {
> +	compatible = "qca,ipq4019-audio";

I'd expect something else in here like phandle links to sub blocks. This 
alone just for purposes of instantiating a driver is not acceptible.

> +};
> diff --git a/Documentation/devicetree/bindings/sound/qca,ipq4019-codec.txt b/Documentation/devicetree/bindings/sound/qca,ipq4019-codec.txt
> new file mode 100644
> index 0000000..3df7742d
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/sound/qca,ipq4019-codec.txt
> @@ -0,0 +1,15 @@
> +* Qualcomm Technologies IPQ4019 ASoC Codec driver
> +
> +This node models the Qualcomm Technologies IPQ4019 ASoC Codec driver
> +
> +Required properties:
> +
> +- compatible	: "qca,ipq4019-codec"
> +- reg		: should have the stereo i2c register address
> +
> +Example:
> +qca_codec: qca_codec@12 {

Don't use '_' in node names, just 'codec@...'.

> +	compatible = "qca,ipq4019-codec";
> +	reg = <0x12>;
> +	status = "disabled";
> +};
> diff --git a/Documentation/devicetree/bindings/sound/qca,ipq4019-i2s.txt b/Documentation/devicetree/bindings/sound/qca,ipq4019-i2s.txt
> new file mode 100644
> index 0000000..af9b63e
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/sound/qca,ipq4019-i2s.txt
> @@ -0,0 +1,33 @@
> +* Qualcomm Technologies IPQ4019 ASoC PCM driver

Bindings describe h/w, not ASoC or drivers.

> +
> +This node models the Qualcomm Technologies IPQ4019 ASoC I2S PCM driver
> +
> +Required properties:
> +
> +- compatible	 : "qca,ipq4019-i2s"
> +- dma-tx-channel : should have the mbox tx channel id
> +- dma-rx-channel : should have the mbox rx channel id
> +- stereo-tx-port : should have the stereo tx id
> +- stereo-rx-port : should have the stereo rx id
> +- clocks	 : should have the audio tx bit clock, tx master clock,
> +		   rx bit clock, rx master clock id
> +- clock-names	 : should be "audio_tx_bclk", "audio_tx_mclk", "audio_rx_bclk",
> +		   "audio_rx_mclk"
> +
> +Example:
> +i2s: ipq4019-pcm-i2s@0 {

Just i2s@... Though 0 here is not valid without a reg property. There's 
no registers?

> +	compatible = "qca,ipq4019-i2s";
> +	dma-tx-channel = <MBOX0_TX_ID>;
> +	dma-rx-channel = <MBOX3_RX_ID>;
> +	stereo-tx-port = <STEREO0_ID>;
> +	stereo-rx-port = <STEREO3_ID>;
> +	clocks = <&adcc ADCC_TXB_CLK_SRC>,
> +		<&adcc ADCC_TXM_CLK_SRC>,
> +		<&adcc ADCC_RXB_CLK_SRC>,
> +		<&adcc ADCC_RXM_CLK_SRC>;
> +	clock-names = "audio_tx_bclk",
> +		"audio_tx_mclk",
> +		"audio_rx_bclk",
> +		"audio_rx_mclk";
> +	status = "disabled";
> +};
> diff --git a/Documentation/devicetree/bindings/sound/qca,ipq4019-i2s1.txt b/Documentation/devicetree/bindings/sound/qca,ipq4019-i2s1.txt
> new file mode 100644
> index 0000000..47333b3
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/sound/qca,ipq4019-i2s1.txt
> @@ -0,0 +1,29 @@
> +* Qualcomm Technologies IPQ4019 ASoC I2S PCM driver

ditto

> +
> +This node models the Qualcomm Technologies IPQ4019 ASoC I2S PCM driver
> +
> +Required properties:
> +
> +- compatible	 : "qca,ipq4019-i2s1"

What's the difference between this and the previous one.

> +- dma-tx-channel : should have the mbox tx channel id
> +- stereo-tx-port : should have the stereo tx id
> +- clocks	 : should have the audio tx bit clock, tx master clock,
> +		   rx bit clock, rx master clock id
> +- clock-names	 : should be "audio_tx_bclk", "audio_tx_mclk", "audio_rx_bclk",
> +		   "audio_rx_mclk"
> +
> +Example:
> +i2s1: ipq4019-pcm-i2s1@0 {
> +	compatible = "qca,ipq4019-i2s1";
> +	dma-tx-channel = <MBOX1_TX_ID>;
> +	stereo-tx-port = <STEREO1_ID>;
> +	clocks = <&adcc ADCC_TXB_CLK_SRC>,
> +		<&adcc ADCC_TXM_CLK_SRC>,
> +		<&adcc ADCC_RXB_CLK_SRC>,
> +		<&adcc ADCC_RXM_CLK_SRC>;
> +	clock-names = "audio_tx_bclk",
> +		"audio_tx_mclk",
> +		"audio_rx_bclk",
> +		"audio_rx_mclk";
> +	status = "disabled";
> +};
> diff --git a/Documentation/devicetree/bindings/sound/qca,ipq4019-i2s2.txt b/Documentation/devicetree/bindings/sound/qca,ipq4019-i2s2.txt
> new file mode 100644
> index 0000000..9af0113
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/sound/qca,ipq4019-i2s2.txt
> @@ -0,0 +1,29 @@
> +* Qualcomm Technologies IPQ4019 ASoC I2S PCM driver
> +
> +This node models the Qualcomm Technologies IPQ4019 ASoC I2S PCM driver
> +
> +Required properties:
> +
> +- compatible	 : "qca,ipq4019-i2s2"
> +- dma-tx-channel : should have the mbox tx channel id
> +- stereo-tx-port : should have the stereo tx id
> +- clocks	 : should have the audio tx bit clock, tx master clock,
> +		   rx bit clock, rx master clock id
> +- clock-names	 : should be "audio_tx_bclk", "audio_tx_mclk", "audio_rx_bclk",
> +		   "audio_rx_mclk"
> +
> +Example:
> +i2s1: ipq4019-pcm-i2s2@0 {
> +	compatible = "qca,ipq4019-i2s2";
> +	dma-tx-channel = <MBOX2_TX_ID>;
> +	stereo-tx-port = <STEREO2_ID>;
> +	clocks = <&adcc ADCC_TXB_CLK_SRC>,
> +		<&adcc ADCC_TXM_CLK_SRC>,
> +		<&adcc ADCC_RXB_CLK_SRC>,
> +		<&adcc ADCC_RXM_CLK_SRC>;
> +	clock-names = "audio_tx_bclk",
> +		"audio_tx_mclk",
> +		"audio_rx_bclk",
> +		"audio_rx_mclk";
> +	status = "disabled";
> +};
> diff --git a/Documentation/devicetree/bindings/sound/qca,ipq4019-mbox.txt b/Documentation/devicetree/bindings/sound/qca,ipq4019-mbox.txt
> new file mode 100644
> index 0000000..51d6c51
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/sound/qca,ipq4019-mbox.txt
> @@ -0,0 +1,23 @@
> +* Qualcomm Technologies IPQ4019 ASoC MBOX driver
> +
> +This node models the Qualcomm Technologies IPQ4019 ASoC mbox driver
> +
> +Required properties:
> +
> +- compatible	 : "qca,ipq4019-mbox"
> +- dma-index	 : should have the mbox dma index

What is this exactly?

> +- reg		 : should have the stereo register address, length
> +- interrupts	 : should have the mbox interrupt no
> +- tx-channel	 : should have the mbox tx id
> +- rx-channel	 : should have the mbox rx id
> +
> +Example:
> +mbox0: mbox@7708000 {
> +	compatible = "qca,ipq4019-mbox";
> +	dma-index = <0>;
> +	reg = <0x7708000 0x1000>;
> +	interrupts = <0 156 0>;
> +	tx-channel = <MBOX0_TX_ID>;
> +	rx-channel = <MBOX0_RX_ID>;
> +	status = "disabled";
> +};
> diff --git a/Documentation/devicetree/bindings/sound/qca,ipq4019-pcm-i2s.txt b/Documentation/devicetree/bindings/sound/qca,ipq4019-pcm-i2s.txt
> new file mode 100644
> index 0000000..a47c7fb
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/sound/qca,ipq4019-pcm-i2s.txt
> @@ -0,0 +1,15 @@
> +* Qualcomm Technologies IPQ4019 ASoC platform driver
> +
> +This node models the Qualcomm Technologies IPQ4019 ASoC platform driver
> +
> +Required properties:
> +
> +- compatible	 : "qca,ipq4019-pcm-i2s"
> +- reg		 : should have the stereo register address, length
> +
> +Example:
> +i2splatform: qca-pcm-i2s@7709000 {
> +	compatible = "qca,ipq4019-pcm-i2s";
> +	reg = <0x7709000 0x1000>;
> +	status = "disabled";
> +};
> diff --git a/Documentation/devicetree/bindings/sound/qca,ipq4019-pcm-i2s1.txt b/Documentation/devicetree/bindings/sound/qca,ipq4019-pcm-i2s1.txt
> new file mode 100644
> index 0000000..cf23ca0b
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/sound/qca,ipq4019-pcm-i2s1.txt
> @@ -0,0 +1,15 @@
> +* Qualcomm Technologies IPQ4019 ASoC platform driver
> +
> +This node models the Qualcomm Technologies IPQ4019 ASoC platform driver

Now I'm confused. How does this relate to the machine driver above? An 
overview of the audio subsystem and its components would be helpful.

> +
> +Required properties:
> +
> +- compatible	 : "qca,ipq4019-pcm-i2s1"
> +- reg		 : should have the stereo register address, length
> +
> +Example:
> +i2s1platform: qca-pcm-i2s1@770b000 {
> +	compatible = "qca,ipq4019-pcm-i2s1";
> +	reg = <0x770b000 0x1000>;
> +	status = "disabled";
> +};
> diff --git a/Documentation/devicetree/bindings/sound/qca,ipq4019-pcm-i2s2.txt b/Documentation/devicetree/bindings/sound/qca,ipq4019-pcm-i2s2.txt
> new file mode 100644
> index 0000000..ae04380
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/sound/qca,ipq4019-pcm-i2s2.txt
> @@ -0,0 +1,15 @@
> +* Qualcomm Technologies IPQ4019 ASoC platform driver
> +
> +This node models the Qualcomm Technologies IPQ4019 ASoC platform driver
> +
> +Required properties:
> +
> +- compatible	 : "qca,ipq4019-pcm-i2s2"

Again, why the indexing here?

> +- reg		 : should have the stereo register address, length
> +
> +Example:
> +i2s2platform: qca-pcm-i2s1@770d000 {
> +	compatible = "qca,ipq4019-pcm-i2s2";
> +	reg = <0x770d000 0x1000>;
> +	status = "disabled";
> +};
> diff --git a/Documentation/devicetree/bindings/sound/qca,ipq4019-pcm-spdif.txt b/Documentation/devicetree/bindings/sound/qca,ipq4019-pcm-spdif.txt
> new file mode 100644
> index 0000000..b47c02c
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/sound/qca,ipq4019-pcm-spdif.txt
> @@ -0,0 +1,15 @@
> +* Qualcomm Technologies IPQ4019 ASoC SPDIF platform driver
> +
> +This node models the Qualcomm Technologies IPQ4019 ASoC SPDIF platform driver
> +
> +Required properties:
> +
> +- compatible	 : "qca,ipq4019-pcm-spdif"
> +- reg		 : should have the stereo register address, length
> +
> +Example:
> +tdmplatform: qca-pcm-spdif@7707000 {
> +	compatible = "qca,ipq4019-pcm-spdif";
> +	reg = <0x7709000 0x1000>;
> +	status = "disabled";
> +};
> diff --git a/Documentation/devicetree/bindings/sound/qca,ipq4019-pcm-tdm.txt b/Documentation/devicetree/bindings/sound/qca,ipq4019-pcm-tdm.txt
> new file mode 100644
> index 0000000..bd3aaa3
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/sound/qca,ipq4019-pcm-tdm.txt
> @@ -0,0 +1,15 @@
> +* Qualcomm Technologies IPQ4019 ASoC TDM platform driver
> +
> +This node models the Qualcomm Technologies IPQ4019 ASoC TDM platform driver
> +
> +Required properties:
> +
> +- compatible	 : "qca,ipq4019-pcm-tdm"
> +- reg		 : should have the stereo register address, length
> +
> +Example:
> +tdmplatform: qca-pcm-tdm@7709000 {
> +	compatible = "qca,ipq4019-pcm-tdm";
> +	reg = <0x7709000 0x1000>;
> +	status = "disabled";
> +};
> diff --git a/Documentation/devicetree/bindings/sound/qca,ipq4019-spdif.txt b/Documentation/devicetree/bindings/sound/qca,ipq4019-spdif.txt
> new file mode 100644
> index 0000000..5a80bbe
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/sound/qca,ipq4019-spdif.txt
> @@ -0,0 +1,35 @@
> +* Qualcomm Technologies IPQ4019 ASoC SPDIF driver
> +
> +This node models the Qualcomm Technologies IPQ4019 ASoC SPDIF driver
> +
> +Required properties:
> +
> +- compatible	 : "qca,ipq4019-spdif"
> +- dma-tx-channel : should have the mbox tx channel id
> +- dma-rx-channel : should have the mbox rx channel id
> +- stereo-tx-port : should have the stereo tx id
> +- stereo-rx-port : should have the stereo tx id
> +- clocks	 : should have the audio tx bit clock, tx master clock,
> +		   spdif clock, spdif divider clock, spdif in fast clock
> +- clock-names	 : should be "audio_tx_bclk", "audio_tx_mclk", "audio_spdif_src",
> +		   "audio_spdif_div2", "audio_spdifinfast_src"
> +
> +Example:
> +spdif: spdif@0 {
> +	compatible = "qca,ipq4019-spdif";
> +	dma-tx-channel = <MBOX0_TX_ID>;
> +	dma-rx-channel = <MBOX3_RX_ID>;
> +	stereo-tx-port = <STEREO0_ID>;
> +	stereo-rx-port = <STEREO3_ID>;
> +	clocks = <&adcc ADCC_TXB_CLK_SRC>,
> +		<&adcc ADCC_TXM_CLK_SRC>,
> +		<&adcc ADCC_SPDIF_SRC>,
> +		<&adcc ADCC_SPDIFDIV2_SRC>,
> +		<&adcc ADCC_AUDIO_SPDIFINFAST_SRC>;
> +	clock-names = "audio_tx_bclk",
> +		"audio_tx_mclk",
> +		"audio_spdif_src",
> +		"audio_spdif_div2",
> +		"audio_spdifinfast_src";
> +	status = "disabled";
> +};
> diff --git a/Documentation/devicetree/bindings/sound/qca,ipq4019-stereo.txt b/Documentation/devicetree/bindings/sound/qca,ipq4019-stereo.txt
> new file mode 100644
> index 0000000..35b4815
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/sound/qca,ipq4019-stereo.txt
> @@ -0,0 +1,17 @@
> +* Qualcomm Technologies IPQ4019 ASoC stereo driver
> +
> +This node models the Qualcomm Technologies IPQ4019 ASoC stereo driver
> +
> +Required properties:
> +
> +- compatible	 : "qca,ipq4019-stereo"
> +- reg		 : should have the stereo register address, length
> +- stereo-index	 : should have the stereo port index
> +
> +Example:
> +stereo0: stereo@7709000 {
> +	compatible = "qca,ipq4019-stereo";
> +	reg = <0x7709000 0x1000>;
> +	stereo-index = <STEREO0_ID>;
> +	status = "disabled";
> +};
> diff --git a/Documentation/devicetree/bindings/sound/qca,ipq4019-tdm.txt b/Documentation/devicetree/bindings/sound/qca,ipq4019-tdm.txt
> new file mode 100644
> index 0000000..c2bf38c
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/sound/qca,ipq4019-tdm.txt
> @@ -0,0 +1,33 @@
> +* Qualcomm Technologies IPQ4019 ASoC TDM driver
> +
> +This node models the Qualcomm Technologies IPQ4019 ASoC TDM driver
> +
> +Required properties:
> +
> +- compatible	 : "qca,ipq4019-tdm"
> +- dma-tx-channel : should have the mbox tx channel id
> +- dma-rx-channel : should have the mbox rx channel id
> +- stereo-tx-port : should have the stereo tx id
> +- stereo-rx-port : should have the stereo tx id
> +- clocks	 : should have the audio tx bit clock, tx master clock,
> +		   rx bit clock, rx master clock id
> +- clock-names	 : should be "audio_tx_bclk", "audio_tx_mclk", "audio_rx_bclk",
> +		   "audio_rx_mclk"
> +
> +Example:
> +tdm: tdm@0 {
> +	compatible = "qca,ipq4019-tdm";
> +	dma-tx-channel = <MBOX0_TX_ID>;
> +	dma-rx-channel = <MBOX3_RX_ID>;
> +	stereo-tx-port = <STEREO0_ID>;
> +	stereo-rx-port = <STEREO3_ID>;
> +	clocks = <&adcc ADCC_TXB_CLK_SRC>,
> +		<&adcc ADCC_TXM_CLK_SRC>,
> +		<&adcc ADCC_RXB_CLK_SRC>,
> +		<&adcc ADCC_RXM_CLK_SRC>;
> +	clock-names = "audio_tx_bclk",
> +		"audio_tx_mclk",
> +		"audio_rx_bclk",
> +		"audio_rx_mclk";
> +	status = "disabled";
> +};
> diff --git a/arch/arm/boot/dts/qcom-ipq4019-ap.dk01.1.dtsi b/arch/arm/boot/dts/qcom-ipq4019-ap.dk01.1.dtsi
> index b9457dd2..e2ab95a 100644
> --- a/arch/arm/boot/dts/qcom-ipq4019-ap.dk01.1.dtsi
> +++ b/arch/arm/boot/dts/qcom-ipq4019-ap.dk01.1.dtsi

This should be a separate patch.

> @@ -1,4 +1,4 @@
> -/* Copyright (c) 2015, The Linux Foundation. All rights reserved.
> +/* Copyright (c) 2015-2016, The Linux Foundation. All rights reserved.
>   *
>   * Permission to use, copy, modify, and/or distribute this software for any
>   * purpose with or without fee is hereby granted, provided that the above
> @@ -20,26 +20,7 @@
>  	model = "Qualcomm Technologies, Inc. IPQ4019/AP-DK01.1";
>  	compatible = "qcom,ipq4019";
>  
> -	clocks {
> -                xo: xo {
> -                        compatible = "fixed-clock";
> -                        clock-frequency = <48000000>;
> -                        #clock-cells = <0>;
> -                };
> -	};
> -
>  	soc {
> -
> -
> -		timer {
> -			compatible = "arm,armv7-timer";
> -			interrupts = <1 2 0xf08>,
> -				     <1 3 0xf08>,
> -				     <1 4 0xf08>,
> -				     <1 1 0xf08>;
> -			clock-frequency = <48000000>;
> -		};
> -

This hunk looks unrelated.

>  		pinctrl@0x01000000 {
>  			serial_pins: serial_pinmux {
>  				mux {
> @@ -69,6 +50,81 @@
>  					bias-disable;
>  					output-high;
>  				};
> +
> +			};
> +
> +			audio_pins: audio_pinmux {
> +				mux_1 {
> +					pins = "gpio25", "gpio53", "gpio60";
> +					function = "i2s_tx_bclk";
> +					bias-pull,up;
> +				};
> +
> +				mux_2 {
> +					pins = "gpio27", "gpio54", "gpio63";
> +					function = "i2s_txd1";
> +					bias-pull,up;
> +				};
> +
> +				mux_3 {
> +					pins = "gpio28", "gpio55";
> +					function = "i2s_txd2";
> +					bias-pull,up;
> +				};
> +
> +				mux_4 {
> +					pins = "gpio29", "gpio56";
> +					function = "i2s_txd3";
> +					bias-pull,up;
> +				};
> +
> +				mux_5 {
> +					pins = "gpio24", "gpio52";
> +					function = "i2s_tx_mclk";
> +					bias-pull,up;
> +				};
> +
> +				mux_6 {
> +					pins = "gpio26", "gpio57", "gpio61";
> +					function = "i2s_tx_fsync";
> +					bias-pull,up;
> +				};
> +
> +				mux_7 {
> +					pins = "gpio2", "gpio23", "gpio63";
> +					function = "i2s_rxd";
> +					bias-pull,up;
> +				};
> +
> +				mux_8 {
> +					pins = "gpio20", "gpio58";
> +					function = "i2s_rx_mclk";
> +					bias-pull,up;
> +				};
> +
> +				mux_9 {
> +					pins = "gpio0", "gpio21", "gpio60";
> +					function = "i2s_rx_bclk";
> +					bias-pull,up;
> +				};
> +
> +				mux_10 {
> +					pins = "gpio1", "gpio22", "gpio61";
> +					function = "i2s_rx_fsync";
> +					bias-pull,up;
> +				};
> +
> +				mux_11 {
> +					pins = "gpio34", "gpio59", "gpio63";
> +					function = "i2s_spdif_in";
> +					bias-pull,up;
> +				};
> +
> +				mux_12 {
> +					pins = "gpio35", "gpio62", "gpio63";
> +					function = "i2s_spdif_out";
> +					bias-pull,up;
> +				};
>  			};
>  		};
>  
> @@ -108,5 +164,104 @@
>  		watchdog@b017000 {
>  			status = "ok";
>  		};
> +
> +		adcc: clock-controller@7700038 {
> +			status = "ok";
> +		};
> +
> +		audio: audio@7700000 {
> +			status = "ok";
> +		};
> +
> +		mbox0: mbox@7708000 {
> +			status = "ok";
> +		};
> +
> +		mbox1: mbox@770a000 {
> +			status = "ok";
> +		};
> +
> +		mbox2: mbox@770c000 {
> +			status = "ok";
> +		};
> +
> +		mbox3: mbox@770e000 {
> +			status = "ok";
> +		};
> +
> +		mbox4: mbox@7706000 {
> +			status = "ok";
> +		};
> +
> +		stereo0: stereo@7709000 {
> +			status = "ok";
> +		};
> +
> +		stereo1: stereo@770b000 {
> +			status = "ok";
> +		};
> +
> +		stereo2: stereo@770d000 {
> +			status = "ok";
> +		};
> +
> +		stereo3: stereo@770f000 {
> +			status = "ok";
> +		};
> +
> +		/* Enable Audio Interfaces */
> +		i2s: ipq4019-pcm-i2s@0 {
> +			status = "ok";
> +		};
> +
> +		i2splatform: qca-pcm-i2s@7709000 {
> +			status = "ok";
> +		};
> +
> +		i2s1platform: qca-pcm-i2s1@770b000 {
> +			status = "ok";
> +		};
> +
> +		i2s1: ipq4019-pcm-i2s1@0 {
> +			status = "ok";
> +		};
> +
> +		i2s2platform: qca-pcm-i2s2@770d000 {
> +			status = "ok";
> +		};
> +
> +		i2s2: ipq4019-pcm-i2s2@0 {
> +			status = "ok";
> +		};
> +
> +		tdmplatform: qca-pcm-tdm@7709000 {
> +			status = "ok";
> +		};
> +
> +		tdm: tdm@0 {
> +			status = "ok";
> +		};
> +
> +		spdifplatform: qca-pcm-spdif@7707000 {
> +			status = "ok";
> +		};
> +
> +		spdif: spdif@0 {
> +			status = "ok";
> +		};
> +
> +		sound: sound@0 {
> +			pinctrl-0 = <&audio_pins>;
> +			pinctrl-names = "default";
> +			status = "ok";
> +		};
> +
> +		i2c_0: i2c@78b7000 { /* BLSP1 QUP2 */
> +			status = "ok";
> +
> +			qca_codec: qca_codec@12 {
> +				status = "ok";
> +			};
> +		};
>  	};
>  };
> diff --git a/arch/arm/boot/dts/qcom-ipq4019.dtsi b/arch/arm/boot/dts/qcom-ipq4019.dtsi
> index 5c08d19..e2b4810 100644
> --- a/arch/arm/boot/dts/qcom-ipq4019.dtsi
> +++ b/arch/arm/boot/dts/qcom-ipq4019.dtsi
> @@ -1,5 +1,5 @@
>  /*
> - * Copyright (c) 2015, The Linux Foundation. All rights reserved.
> + * Copyright (c) 2015-2016, The Linux Foundation. All rights reserved.
>   *
>   * This program is free software; you can redistribute it and/or modify
>   * it under the terms of the GNU General Public License version 2 and
> @@ -15,6 +15,8 @@
>  
>  #include "skeleton.dtsi"
>  #include <dt-bindings/clock/qcom,gcc-ipq4019.h>
> +#include <dt-bindings/clock/qca,adcc-ipq4019.h>
> +#include <dt-bindings/sound/ipq4019-audio.h>
>  #include <dt-bindings/interrupt-controller/arm-gic.h>
>  #include <dt-bindings/interrupt-controller/irq.h>
>  
> @@ -90,6 +92,21 @@
>  			clock-frequency = <32768>;
>  			#clock-cells = <0>;
>  		};
> +
> +		xo: xo {
> +			compatible = "fixed-clock";
> +			clock-frequency = <48000000>;
> +			#clock-cells = <0>;
> +		};
> +	};
> +
> +	timer {
> +		compatible = "arm,armv7-timer";
> +		interrupts = <1 2 0xf08>,
> +			     <1 3 0xf08>,
> +			     <1 4 0xf08>,
> +			     <1 1 0xf08>;
> +		clock-frequency = <48000000>;
>  	};
>  
>  	soc {
> @@ -156,8 +173,13 @@
>  			#address-cells = <1>;
>  			#size-cells = <0>;
>  			status = "disabled";
> -		};
>  
> +			qca_codec: qca_codec@12 {
> +				compatible = "qca,ipq4019-codec";
> +				reg = <0x12>;
> +				status = "disabled";
> +			};
> +		};
>  
>  		cryptobam: dma@8e04000 {
>  			compatible = "qcom,bam-v1.7.0";
> @@ -263,5 +285,226 @@
>  			compatible = "qcom,pshold";
>  			reg = <0x4ab000 0x4>;
>  		};
> +
> +		adcc: clock-controller@7700038 {
> +			compatible = "qcom,adcc-ipq4019";
> +			#clock-cells = <1>;
> +			#reset-cells = <1>;
> +			reg = <0x7700038 0x1DC>;
> +			status = "disabled";
> +		};
> +
> +		audio: audio@7700000 {
> +			compatible = "qca,ipq4019-audio-adss";
> +			reg = <0x7700000 0x34>,
> +				<0x7707000 0x20>;
> +			resets = <&gcc AUDIO_BLK_ARES>;
> +			reset-names = "blk_rst";
> +			status = "disabled";
> +		};
> +
> +		pcm: pcm@7704000 {
> +			compatible = "qca,ipq4019-pcm";
> +			reg = <0x7704000 0x2000>;
> +			dma-tx-channel = <MBOX3_TX_ID>;
> +			dma-rx-channel = <MBOX0_RX_ID>;
> +			stereo-tx-port = <STEREO3_ID>;
> +			stereo-rx-port = <STEREO0_ID>;
> +			clocks = <&adcc ADCC_PCM_CLK_SRC>;
> +			clock-names = "audio_pcm_clk";
> +			status = "disabled";
> +		};
> +
> +		mbox0: mbox@7708000 {
> +			dma-index = <0>;
> +			compatible = "qca,ipq4019-mbox";
> +			reg = <0x7708000 0x1000>;
> +			interrupts = <0 156 0>;
> +			tx-channel = <MBOX0_TX_ID>;
> +			rx-channel = <MBOX0_RX_ID>;
> +			status = "disabled";
> +		};
> +
> +		mbox1: mbox@770a000 {
> +			dma-index = <1>;
> +			compatible = "qca,ipq4019-mbox";
> +			reg = <0x770A000 0x1000>;
> +			interrupts = <0 157 0>;
> +			tx-channel = <MBOX1_TX_ID>;
> +			status = "disabled";
> +		};
> +
> +		mbox2: mbox@770c000 {
> +			dma-index = <2>;
> +			compatible = "qca,ipq4019-mbox";
> +			reg = <0x770C000 0x1000>;
> +			interrupts = <0 158 0>;
> +			tx-channel = <MBOX2_TX_ID>;
> +			status = "disabled";
> +		};
> +
> +		mbox3: mbox@770e000 {
> +			dma-index = <3>;
> +			compatible = "qca,ipq4019-mbox";
> +			reg = <0x770E000 0x1000>;
> +			interrupts = <0 159 0>;
> +			tx-channel = <MBOX3_TX_ID>;
> +			rx-channel = <MBOX3_RX_ID>;
> +			status = "disabled";
> +		};
> +
> +		mbox4: mbox@7706000 {
> +			dma-index = <4>;
> +			compatible = "qca,ipq4019-mbox";
> +			reg = <0x7706000 0x1000>;
> +			interrupts = <0 163 0>;
> +			rx-channel = <MBOX_SPDIF_RX_ID>;
> +			status = "disabled";
> +		};
> +
> +		stereo0: stereo@7709000 {
> +			stereo-index = <STEREO0_ID>;
> +			compatible = "qca,ipq4019-stereo";
> +			reg = <0x7709000 0x1000>;
> +			status = "disabled";
> +		};
> +
> +		stereo1: stereo@770b000 {
> +			stereo-index = <STEREO1_ID>;
> +			compatible = "qca,ipq4019-stereo";
> +			reg = <0x770B000 0x1000>;
> +			status = "disabled";
> +		};
> +
> +		stereo2: stereo@770d000 {
> +			stereo-index = <STEREO2_ID>;
> +			compatible = "qca,ipq4019-stereo";
> +			reg = <0x770D000 0x1000>;
> +			status = "disabled";
> +		};
> +
> +		stereo3: stereo@770f000 {
> +			stereo-index = <STEREO3_ID>;
> +			compatible = "qca,ipq4019-stereo";
> +			reg = <0x770F000 0x1000>;
> +			status = "disabled";
> +		};
> +
> +		i2splatform: qca-pcm-i2s@7709000 {
> +			compatible = "qca,ipq4019-pcm-i2s";
> +			reg = <0x7709000 0x1000>;
> +			status = "disabled";
> +		};
> +
> +		i2s: ipq4019-pcm-i2s@0 {
> +			compatible = "qca,ipq4019-i2s";
> +			dma-tx-channel = <MBOX0_TX_ID>;
> +			stereo-tx-port = <STEREO0_ID>;
> +			dma-rx-channel = <MBOX3_RX_ID>;
> +			stereo-rx-port = <STEREO3_ID>;
> +			clocks = <&adcc ADCC_TXB_CLK_SRC>,
> +				<&adcc ADCC_TXM_CLK_SRC>,
> +				<&adcc ADCC_RXB_CLK_SRC>,
> +				<&adcc ADCC_RXM_CLK_SRC>;
> +			clock-names = "audio_tx_bclk",
> +				"audio_tx_mclk",
> +				"audio_rx_bclk",
> +				"audio_rx_mclk";
> +			status = "disabled";
> +		};
> +
> +		i2s1platform: qca-pcm-i2s1@770b000 {
> +			compatible = "qca,ipq4019-pcm-i2s1";
> +			reg = <0x770b000 0x1000>;
> +			status = "disabled";
> +		};
> +
> +		i2s1: ipq4019-pcm-i2s1@0 {
> +			compatible = "qca,ipq4019-i2s1";
> +			dma-tx-channel = <MBOX1_TX_ID>;
> +			stereo-tx-port = <STEREO1_ID>;
> +			clocks = <&adcc ADCC_TXB_CLK_SRC>,
> +				<&adcc ADCC_TXM_CLK_SRC>,
> +				<&adcc ADCC_RXB_CLK_SRC>,
> +				<&adcc ADCC_RXM_CLK_SRC>;
> +			clock-names = "audio_tx_bclk",
> +				"audio_tx_mclk",
> +				"audio_rx_bclk",
> +				"audio_rx_mclk";
> +			status = "disabled";
> +		};
> +
> +		i2s2platform: qca-pcm-i2s2@770d000 {
> +			compatible = "qca,ipq4019-pcm-i2s2";
> +			reg = <0x770d000 0x1000>;
> +			status = "disabled";
> +		};
> +
> +		i2s2: ipq4019-pcm-i2s2@0 {
> +			compatible = "qca,ipq4019-i2s2";
> +			dma-tx-channel = <MBOX2_TX_ID>;
> +			stereo-tx-port = <STEREO2_ID>;
> +			clocks = <&adcc ADCC_TXB_CLK_SRC>,
> +				<&adcc ADCC_TXM_CLK_SRC>,
> +				<&adcc ADCC_RXB_CLK_SRC>,
> +				<&adcc ADCC_RXM_CLK_SRC>;
> +			clock-names = "audio_tx_bclk",
> +				"audio_tx_mclk",
> +				"audio_rx_bclk",
> +				"audio_rx_mclk";
> +			status = "disabled";
> +		};
> +
> +		tdmplatform: qca-pcm-tdm@7709000 {
> +			compatible = "qca,ipq4019-pcm-tdm";
> +			reg = <0x7709000 0x1000>;
> +			status = "disabled";
> +		};
> +
> +		tdm: tdm@0 {
> +			compatible = "qca,ipq4019-tdm";
> +			dma-tx-channel = <MBOX0_TX_ID>;
> +			dma-rx-channel = <MBOX3_RX_ID>;
> +			stereo-tx-port = <STEREO0_ID>;
> +			stereo-rx-port = <STEREO3_ID>;
> +			clocks = <&adcc ADCC_TXB_CLK_SRC>,
> +				<&adcc ADCC_TXM_CLK_SRC>,
> +				<&adcc ADCC_RXB_CLK_SRC>,
> +				<&adcc ADCC_RXM_CLK_SRC>;
> +			clock-names = "audio_tx_bclk",
> +				"audio_tx_mclk",
> +				"audio_rx_bclk",
> +				"audio_rx_mclk";
> +			status = "disabled";
> +		};
> +
> +		spdifplatform: qca-pcm-spdif@7707000 {
> +			compatible = "qca,ipq4019-pcm-spdif";
> +			reg = <0x7707000 0x1000>;
> +			status = "disabled";
> +		};
> +
> +		spdif: spdif@0 {
> +			compatible = "qca,ipq4019-spdif";
> +			dma-tx-channel = <MBOX0_TX_ID>;
> +			dma-rx-channel = <MBOX_SPDIF_RX_ID>;
> +			stereo-tx-port = <STEREO0_ID>;
> +			clocks = <&adcc ADCC_TXB_CLK_SRC>,
> +				<&adcc ADCC_TXM_CLK_SRC>,
> +				<&adcc ADCC_SPDIF_SRC>,
> +				<&adcc ADCC_SPDIFDIV2_SRC >,
> +				<&adcc ADCC_AUDIO_SPDIFINFAST_SRC>;
> +			clock-names = "audio_tx_bclk",
> +				"audio_tx_mclk",
> +				"audio_spdif_src",
> +				"audio_spdif_div2",
> +				"audio_spdifinfast_src";
> +			status = "disabled";
> +		};
> +
> +		sound: sound@0 {
> +			compatible = "qca,ipq4019-audio";
> +			status = "disabled";
> +		};
>  	};
>  };
> -- 
> The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
> a Linux Foundation Collaborative Project
> 

^ permalink raw reply	[flat|nested] 24+ messages in thread

* [PATCH 1/4] qcom: ipq4019: Add ipq4019 ASoC device tree changes
@ 2016-07-17 20:03     ` Rob Herring
  0 siblings, 0 replies; 24+ messages in thread
From: Rob Herring @ 2016-07-17 20:03 UTC (permalink / raw)
  To: linux-arm-kernel

On Fri, Jul 15, 2016 at 12:37:03PM +0530, njaigane at codeaurora.org wrote:
> From: Jaiganesh Narayanan <njaigane@codeaurora.org>
> 
> This patch adds the ipq4019 ASoC device tree changes and the
> binding documentation for pcm, spdif, tdm, stereo, codec, mbox,
> adss modules
> 
> Signed-off-by: Jaiganesh Narayanan <njaigane@codeaurora.org>
> ---
>  .../bindings/sound/qca,ipq4019-audio-adss.txt      |  20 ++
>  .../bindings/sound/qca,ipq4019-audio.txt           |  13 ++
>  .../bindings/sound/qca,ipq4019-codec.txt           |  15 ++
>  .../devicetree/bindings/sound/qca,ipq4019-i2s.txt  |  33 +++
>  .../devicetree/bindings/sound/qca,ipq4019-i2s1.txt |  29 +++
>  .../devicetree/bindings/sound/qca,ipq4019-i2s2.txt |  29 +++
>  .../devicetree/bindings/sound/qca,ipq4019-mbox.txt |  23 ++
>  .../bindings/sound/qca,ipq4019-pcm-i2s.txt         |  15 ++
>  .../bindings/sound/qca,ipq4019-pcm-i2s1.txt        |  15 ++
>  .../bindings/sound/qca,ipq4019-pcm-i2s2.txt        |  15 ++
>  .../bindings/sound/qca,ipq4019-pcm-spdif.txt       |  15 ++
>  .../bindings/sound/qca,ipq4019-pcm-tdm.txt         |  15 ++
>  .../bindings/sound/qca,ipq4019-spdif.txt           |  35 +++
>  .../bindings/sound/qca,ipq4019-stereo.txt          |  17 ++
>  .../devicetree/bindings/sound/qca,ipq4019-tdm.txt  |  33 +++
>  arch/arm/boot/dts/qcom-ipq4019-ap.dk01.1.dtsi      | 195 ++++++++++++++--
>  arch/arm/boot/dts/qcom-ipq4019.dtsi                | 247 ++++++++++++++++++++-
>  17 files changed, 742 insertions(+), 22 deletions(-)
>  create mode 100644 Documentation/devicetree/bindings/sound/qca,ipq4019-audio-adss.txt
>  create mode 100644 Documentation/devicetree/bindings/sound/qca,ipq4019-audio.txt
>  create mode 100644 Documentation/devicetree/bindings/sound/qca,ipq4019-codec.txt
>  create mode 100644 Documentation/devicetree/bindings/sound/qca,ipq4019-i2s.txt
>  create mode 100644 Documentation/devicetree/bindings/sound/qca,ipq4019-i2s1.txt
>  create mode 100644 Documentation/devicetree/bindings/sound/qca,ipq4019-i2s2.txt
>  create mode 100644 Documentation/devicetree/bindings/sound/qca,ipq4019-mbox.txt
>  create mode 100644 Documentation/devicetree/bindings/sound/qca,ipq4019-pcm-i2s.txt
>  create mode 100644 Documentation/devicetree/bindings/sound/qca,ipq4019-pcm-i2s1.txt
>  create mode 100644 Documentation/devicetree/bindings/sound/qca,ipq4019-pcm-i2s2.txt
>  create mode 100644 Documentation/devicetree/bindings/sound/qca,ipq4019-pcm-spdif.txt
>  create mode 100644 Documentation/devicetree/bindings/sound/qca,ipq4019-pcm-tdm.txt
>  create mode 100644 Documentation/devicetree/bindings/sound/qca,ipq4019-spdif.txt
>  create mode 100644 Documentation/devicetree/bindings/sound/qca,ipq4019-stereo.txt
>  create mode 100644 Documentation/devicetree/bindings/sound/qca,ipq4019-tdm.txt
> 
> diff --git a/Documentation/devicetree/bindings/sound/qca,ipq4019-audio-adss.txt b/Documentation/devicetree/bindings/sound/qca,ipq4019-audio-adss.txt
> new file mode 100644
> index 0000000..5ba2b9d
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/sound/qca,ipq4019-audio-adss.txt
> @@ -0,0 +1,20 @@
> +* Qualcomm Technologies IPQ4019 ASoC audio subsystem driver
> +
> +This node models the Qualcomm Technologies IPQ4019 ASoC audio subsystem driver
> +
> +Required properties:
> +
> +- compatible	: "qca,ipq4019-audio-adss"
> +- reg		: should have the stereo register address, length
> +- resets	: references to the reset controllers
> +- reset-names	: should be "blk_rst"
> +
> +
> +Example:
> +audio: audio at 7700000 {
> +	compatible = "qca,ipq4019-audio-adss";
> +	reg = <0x7700000 0x34>;
> +	resets = <&gcc AUDIO_BLK_ARES>;
> +	reset-names = "blk_rst";
> +	status = "disabled";
> +};
> diff --git a/Documentation/devicetree/bindings/sound/qca,ipq4019-audio.txt b/Documentation/devicetree/bindings/sound/qca,ipq4019-audio.txt
> new file mode 100644
> index 0000000..fde039f
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/sound/qca,ipq4019-audio.txt
> @@ -0,0 +1,13 @@
> +* Qualcomm Technologies IPQ4019 ASoC machine driver
> +
> +This node models the Qualcomm Technologies IPQ4019 ASoC machine driver

ASoC machine driver is a Linuxism.

> +
> +Required properties:
> +
> +- compatible		: "qca,ipq4019-audio"
> +
> +Example:
> +
> +sound: sound {
> +	compatible = "qca,ipq4019-audio";

I'd expect something else in here like phandle links to sub blocks. This 
alone just for purposes of instantiating a driver is not acceptible.

> +};
> diff --git a/Documentation/devicetree/bindings/sound/qca,ipq4019-codec.txt b/Documentation/devicetree/bindings/sound/qca,ipq4019-codec.txt
> new file mode 100644
> index 0000000..3df7742d
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/sound/qca,ipq4019-codec.txt
> @@ -0,0 +1,15 @@
> +* Qualcomm Technologies IPQ4019 ASoC Codec driver
> +
> +This node models the Qualcomm Technologies IPQ4019 ASoC Codec driver
> +
> +Required properties:
> +
> +- compatible	: "qca,ipq4019-codec"
> +- reg		: should have the stereo i2c register address
> +
> +Example:
> +qca_codec: qca_codec at 12 {

Don't use '_' in node names, just 'codec at ...'.

> +	compatible = "qca,ipq4019-codec";
> +	reg = <0x12>;
> +	status = "disabled";
> +};
> diff --git a/Documentation/devicetree/bindings/sound/qca,ipq4019-i2s.txt b/Documentation/devicetree/bindings/sound/qca,ipq4019-i2s.txt
> new file mode 100644
> index 0000000..af9b63e
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/sound/qca,ipq4019-i2s.txt
> @@ -0,0 +1,33 @@
> +* Qualcomm Technologies IPQ4019 ASoC PCM driver

Bindings describe h/w, not ASoC or drivers.

> +
> +This node models the Qualcomm Technologies IPQ4019 ASoC I2S PCM driver
> +
> +Required properties:
> +
> +- compatible	 : "qca,ipq4019-i2s"
> +- dma-tx-channel : should have the mbox tx channel id
> +- dma-rx-channel : should have the mbox rx channel id
> +- stereo-tx-port : should have the stereo tx id
> +- stereo-rx-port : should have the stereo rx id
> +- clocks	 : should have the audio tx bit clock, tx master clock,
> +		   rx bit clock, rx master clock id
> +- clock-names	 : should be "audio_tx_bclk", "audio_tx_mclk", "audio_rx_bclk",
> +		   "audio_rx_mclk"
> +
> +Example:
> +i2s: ipq4019-pcm-i2s at 0 {

Just i2s at ... Though 0 here is not valid without a reg property. There's 
no registers?

> +	compatible = "qca,ipq4019-i2s";
> +	dma-tx-channel = <MBOX0_TX_ID>;
> +	dma-rx-channel = <MBOX3_RX_ID>;
> +	stereo-tx-port = <STEREO0_ID>;
> +	stereo-rx-port = <STEREO3_ID>;
> +	clocks = <&adcc ADCC_TXB_CLK_SRC>,
> +		<&adcc ADCC_TXM_CLK_SRC>,
> +		<&adcc ADCC_RXB_CLK_SRC>,
> +		<&adcc ADCC_RXM_CLK_SRC>;
> +	clock-names = "audio_tx_bclk",
> +		"audio_tx_mclk",
> +		"audio_rx_bclk",
> +		"audio_rx_mclk";
> +	status = "disabled";
> +};
> diff --git a/Documentation/devicetree/bindings/sound/qca,ipq4019-i2s1.txt b/Documentation/devicetree/bindings/sound/qca,ipq4019-i2s1.txt
> new file mode 100644
> index 0000000..47333b3
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/sound/qca,ipq4019-i2s1.txt
> @@ -0,0 +1,29 @@
> +* Qualcomm Technologies IPQ4019 ASoC I2S PCM driver

ditto

> +
> +This node models the Qualcomm Technologies IPQ4019 ASoC I2S PCM driver
> +
> +Required properties:
> +
> +- compatible	 : "qca,ipq4019-i2s1"

What's the difference between this and the previous one.

> +- dma-tx-channel : should have the mbox tx channel id
> +- stereo-tx-port : should have the stereo tx id
> +- clocks	 : should have the audio tx bit clock, tx master clock,
> +		   rx bit clock, rx master clock id
> +- clock-names	 : should be "audio_tx_bclk", "audio_tx_mclk", "audio_rx_bclk",
> +		   "audio_rx_mclk"
> +
> +Example:
> +i2s1: ipq4019-pcm-i2s1 at 0 {
> +	compatible = "qca,ipq4019-i2s1";
> +	dma-tx-channel = <MBOX1_TX_ID>;
> +	stereo-tx-port = <STEREO1_ID>;
> +	clocks = <&adcc ADCC_TXB_CLK_SRC>,
> +		<&adcc ADCC_TXM_CLK_SRC>,
> +		<&adcc ADCC_RXB_CLK_SRC>,
> +		<&adcc ADCC_RXM_CLK_SRC>;
> +	clock-names = "audio_tx_bclk",
> +		"audio_tx_mclk",
> +		"audio_rx_bclk",
> +		"audio_rx_mclk";
> +	status = "disabled";
> +};
> diff --git a/Documentation/devicetree/bindings/sound/qca,ipq4019-i2s2.txt b/Documentation/devicetree/bindings/sound/qca,ipq4019-i2s2.txt
> new file mode 100644
> index 0000000..9af0113
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/sound/qca,ipq4019-i2s2.txt
> @@ -0,0 +1,29 @@
> +* Qualcomm Technologies IPQ4019 ASoC I2S PCM driver
> +
> +This node models the Qualcomm Technologies IPQ4019 ASoC I2S PCM driver
> +
> +Required properties:
> +
> +- compatible	 : "qca,ipq4019-i2s2"
> +- dma-tx-channel : should have the mbox tx channel id
> +- stereo-tx-port : should have the stereo tx id
> +- clocks	 : should have the audio tx bit clock, tx master clock,
> +		   rx bit clock, rx master clock id
> +- clock-names	 : should be "audio_tx_bclk", "audio_tx_mclk", "audio_rx_bclk",
> +		   "audio_rx_mclk"
> +
> +Example:
> +i2s1: ipq4019-pcm-i2s2 at 0 {
> +	compatible = "qca,ipq4019-i2s2";
> +	dma-tx-channel = <MBOX2_TX_ID>;
> +	stereo-tx-port = <STEREO2_ID>;
> +	clocks = <&adcc ADCC_TXB_CLK_SRC>,
> +		<&adcc ADCC_TXM_CLK_SRC>,
> +		<&adcc ADCC_RXB_CLK_SRC>,
> +		<&adcc ADCC_RXM_CLK_SRC>;
> +	clock-names = "audio_tx_bclk",
> +		"audio_tx_mclk",
> +		"audio_rx_bclk",
> +		"audio_rx_mclk";
> +	status = "disabled";
> +};
> diff --git a/Documentation/devicetree/bindings/sound/qca,ipq4019-mbox.txt b/Documentation/devicetree/bindings/sound/qca,ipq4019-mbox.txt
> new file mode 100644
> index 0000000..51d6c51
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/sound/qca,ipq4019-mbox.txt
> @@ -0,0 +1,23 @@
> +* Qualcomm Technologies IPQ4019 ASoC MBOX driver
> +
> +This node models the Qualcomm Technologies IPQ4019 ASoC mbox driver
> +
> +Required properties:
> +
> +- compatible	 : "qca,ipq4019-mbox"
> +- dma-index	 : should have the mbox dma index

What is this exactly?

> +- reg		 : should have the stereo register address, length
> +- interrupts	 : should have the mbox interrupt no
> +- tx-channel	 : should have the mbox tx id
> +- rx-channel	 : should have the mbox rx id
> +
> +Example:
> +mbox0: mbox at 7708000 {
> +	compatible = "qca,ipq4019-mbox";
> +	dma-index = <0>;
> +	reg = <0x7708000 0x1000>;
> +	interrupts = <0 156 0>;
> +	tx-channel = <MBOX0_TX_ID>;
> +	rx-channel = <MBOX0_RX_ID>;
> +	status = "disabled";
> +};
> diff --git a/Documentation/devicetree/bindings/sound/qca,ipq4019-pcm-i2s.txt b/Documentation/devicetree/bindings/sound/qca,ipq4019-pcm-i2s.txt
> new file mode 100644
> index 0000000..a47c7fb
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/sound/qca,ipq4019-pcm-i2s.txt
> @@ -0,0 +1,15 @@
> +* Qualcomm Technologies IPQ4019 ASoC platform driver
> +
> +This node models the Qualcomm Technologies IPQ4019 ASoC platform driver
> +
> +Required properties:
> +
> +- compatible	 : "qca,ipq4019-pcm-i2s"
> +- reg		 : should have the stereo register address, length
> +
> +Example:
> +i2splatform: qca-pcm-i2s at 7709000 {
> +	compatible = "qca,ipq4019-pcm-i2s";
> +	reg = <0x7709000 0x1000>;
> +	status = "disabled";
> +};
> diff --git a/Documentation/devicetree/bindings/sound/qca,ipq4019-pcm-i2s1.txt b/Documentation/devicetree/bindings/sound/qca,ipq4019-pcm-i2s1.txt
> new file mode 100644
> index 0000000..cf23ca0b
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/sound/qca,ipq4019-pcm-i2s1.txt
> @@ -0,0 +1,15 @@
> +* Qualcomm Technologies IPQ4019 ASoC platform driver
> +
> +This node models the Qualcomm Technologies IPQ4019 ASoC platform driver

Now I'm confused. How does this relate to the machine driver above? An 
overview of the audio subsystem and its components would be helpful.

> +
> +Required properties:
> +
> +- compatible	 : "qca,ipq4019-pcm-i2s1"
> +- reg		 : should have the stereo register address, length
> +
> +Example:
> +i2s1platform: qca-pcm-i2s1 at 770b000 {
> +	compatible = "qca,ipq4019-pcm-i2s1";
> +	reg = <0x770b000 0x1000>;
> +	status = "disabled";
> +};
> diff --git a/Documentation/devicetree/bindings/sound/qca,ipq4019-pcm-i2s2.txt b/Documentation/devicetree/bindings/sound/qca,ipq4019-pcm-i2s2.txt
> new file mode 100644
> index 0000000..ae04380
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/sound/qca,ipq4019-pcm-i2s2.txt
> @@ -0,0 +1,15 @@
> +* Qualcomm Technologies IPQ4019 ASoC platform driver
> +
> +This node models the Qualcomm Technologies IPQ4019 ASoC platform driver
> +
> +Required properties:
> +
> +- compatible	 : "qca,ipq4019-pcm-i2s2"

Again, why the indexing here?

> +- reg		 : should have the stereo register address, length
> +
> +Example:
> +i2s2platform: qca-pcm-i2s1 at 770d000 {
> +	compatible = "qca,ipq4019-pcm-i2s2";
> +	reg = <0x770d000 0x1000>;
> +	status = "disabled";
> +};
> diff --git a/Documentation/devicetree/bindings/sound/qca,ipq4019-pcm-spdif.txt b/Documentation/devicetree/bindings/sound/qca,ipq4019-pcm-spdif.txt
> new file mode 100644
> index 0000000..b47c02c
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/sound/qca,ipq4019-pcm-spdif.txt
> @@ -0,0 +1,15 @@
> +* Qualcomm Technologies IPQ4019 ASoC SPDIF platform driver
> +
> +This node models the Qualcomm Technologies IPQ4019 ASoC SPDIF platform driver
> +
> +Required properties:
> +
> +- compatible	 : "qca,ipq4019-pcm-spdif"
> +- reg		 : should have the stereo register address, length
> +
> +Example:
> +tdmplatform: qca-pcm-spdif at 7707000 {
> +	compatible = "qca,ipq4019-pcm-spdif";
> +	reg = <0x7709000 0x1000>;
> +	status = "disabled";
> +};
> diff --git a/Documentation/devicetree/bindings/sound/qca,ipq4019-pcm-tdm.txt b/Documentation/devicetree/bindings/sound/qca,ipq4019-pcm-tdm.txt
> new file mode 100644
> index 0000000..bd3aaa3
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/sound/qca,ipq4019-pcm-tdm.txt
> @@ -0,0 +1,15 @@
> +* Qualcomm Technologies IPQ4019 ASoC TDM platform driver
> +
> +This node models the Qualcomm Technologies IPQ4019 ASoC TDM platform driver
> +
> +Required properties:
> +
> +- compatible	 : "qca,ipq4019-pcm-tdm"
> +- reg		 : should have the stereo register address, length
> +
> +Example:
> +tdmplatform: qca-pcm-tdm at 7709000 {
> +	compatible = "qca,ipq4019-pcm-tdm";
> +	reg = <0x7709000 0x1000>;
> +	status = "disabled";
> +};
> diff --git a/Documentation/devicetree/bindings/sound/qca,ipq4019-spdif.txt b/Documentation/devicetree/bindings/sound/qca,ipq4019-spdif.txt
> new file mode 100644
> index 0000000..5a80bbe
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/sound/qca,ipq4019-spdif.txt
> @@ -0,0 +1,35 @@
> +* Qualcomm Technologies IPQ4019 ASoC SPDIF driver
> +
> +This node models the Qualcomm Technologies IPQ4019 ASoC SPDIF driver
> +
> +Required properties:
> +
> +- compatible	 : "qca,ipq4019-spdif"
> +- dma-tx-channel : should have the mbox tx channel id
> +- dma-rx-channel : should have the mbox rx channel id
> +- stereo-tx-port : should have the stereo tx id
> +- stereo-rx-port : should have the stereo tx id
> +- clocks	 : should have the audio tx bit clock, tx master clock,
> +		   spdif clock, spdif divider clock, spdif in fast clock
> +- clock-names	 : should be "audio_tx_bclk", "audio_tx_mclk", "audio_spdif_src",
> +		   "audio_spdif_div2", "audio_spdifinfast_src"
> +
> +Example:
> +spdif: spdif at 0 {
> +	compatible = "qca,ipq4019-spdif";
> +	dma-tx-channel = <MBOX0_TX_ID>;
> +	dma-rx-channel = <MBOX3_RX_ID>;
> +	stereo-tx-port = <STEREO0_ID>;
> +	stereo-rx-port = <STEREO3_ID>;
> +	clocks = <&adcc ADCC_TXB_CLK_SRC>,
> +		<&adcc ADCC_TXM_CLK_SRC>,
> +		<&adcc ADCC_SPDIF_SRC>,
> +		<&adcc ADCC_SPDIFDIV2_SRC>,
> +		<&adcc ADCC_AUDIO_SPDIFINFAST_SRC>;
> +	clock-names = "audio_tx_bclk",
> +		"audio_tx_mclk",
> +		"audio_spdif_src",
> +		"audio_spdif_div2",
> +		"audio_spdifinfast_src";
> +	status = "disabled";
> +};
> diff --git a/Documentation/devicetree/bindings/sound/qca,ipq4019-stereo.txt b/Documentation/devicetree/bindings/sound/qca,ipq4019-stereo.txt
> new file mode 100644
> index 0000000..35b4815
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/sound/qca,ipq4019-stereo.txt
> @@ -0,0 +1,17 @@
> +* Qualcomm Technologies IPQ4019 ASoC stereo driver
> +
> +This node models the Qualcomm Technologies IPQ4019 ASoC stereo driver
> +
> +Required properties:
> +
> +- compatible	 : "qca,ipq4019-stereo"
> +- reg		 : should have the stereo register address, length
> +- stereo-index	 : should have the stereo port index
> +
> +Example:
> +stereo0: stereo at 7709000 {
> +	compatible = "qca,ipq4019-stereo";
> +	reg = <0x7709000 0x1000>;
> +	stereo-index = <STEREO0_ID>;
> +	status = "disabled";
> +};
> diff --git a/Documentation/devicetree/bindings/sound/qca,ipq4019-tdm.txt b/Documentation/devicetree/bindings/sound/qca,ipq4019-tdm.txt
> new file mode 100644
> index 0000000..c2bf38c
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/sound/qca,ipq4019-tdm.txt
> @@ -0,0 +1,33 @@
> +* Qualcomm Technologies IPQ4019 ASoC TDM driver
> +
> +This node models the Qualcomm Technologies IPQ4019 ASoC TDM driver
> +
> +Required properties:
> +
> +- compatible	 : "qca,ipq4019-tdm"
> +- dma-tx-channel : should have the mbox tx channel id
> +- dma-rx-channel : should have the mbox rx channel id
> +- stereo-tx-port : should have the stereo tx id
> +- stereo-rx-port : should have the stereo tx id
> +- clocks	 : should have the audio tx bit clock, tx master clock,
> +		   rx bit clock, rx master clock id
> +- clock-names	 : should be "audio_tx_bclk", "audio_tx_mclk", "audio_rx_bclk",
> +		   "audio_rx_mclk"
> +
> +Example:
> +tdm: tdm at 0 {
> +	compatible = "qca,ipq4019-tdm";
> +	dma-tx-channel = <MBOX0_TX_ID>;
> +	dma-rx-channel = <MBOX3_RX_ID>;
> +	stereo-tx-port = <STEREO0_ID>;
> +	stereo-rx-port = <STEREO3_ID>;
> +	clocks = <&adcc ADCC_TXB_CLK_SRC>,
> +		<&adcc ADCC_TXM_CLK_SRC>,
> +		<&adcc ADCC_RXB_CLK_SRC>,
> +		<&adcc ADCC_RXM_CLK_SRC>;
> +	clock-names = "audio_tx_bclk",
> +		"audio_tx_mclk",
> +		"audio_rx_bclk",
> +		"audio_rx_mclk";
> +	status = "disabled";
> +};
> diff --git a/arch/arm/boot/dts/qcom-ipq4019-ap.dk01.1.dtsi b/arch/arm/boot/dts/qcom-ipq4019-ap.dk01.1.dtsi
> index b9457dd2..e2ab95a 100644
> --- a/arch/arm/boot/dts/qcom-ipq4019-ap.dk01.1.dtsi
> +++ b/arch/arm/boot/dts/qcom-ipq4019-ap.dk01.1.dtsi

This should be a separate patch.

> @@ -1,4 +1,4 @@
> -/* Copyright (c) 2015, The Linux Foundation. All rights reserved.
> +/* Copyright (c) 2015-2016, The Linux Foundation. All rights reserved.
>   *
>   * Permission to use, copy, modify, and/or distribute this software for any
>   * purpose with or without fee is hereby granted, provided that the above
> @@ -20,26 +20,7 @@
>  	model = "Qualcomm Technologies, Inc. IPQ4019/AP-DK01.1";
>  	compatible = "qcom,ipq4019";
>  
> -	clocks {
> -                xo: xo {
> -                        compatible = "fixed-clock";
> -                        clock-frequency = <48000000>;
> -                        #clock-cells = <0>;
> -                };
> -	};
> -
>  	soc {
> -
> -
> -		timer {
> -			compatible = "arm,armv7-timer";
> -			interrupts = <1 2 0xf08>,
> -				     <1 3 0xf08>,
> -				     <1 4 0xf08>,
> -				     <1 1 0xf08>;
> -			clock-frequency = <48000000>;
> -		};
> -

This hunk looks unrelated.

>  		pinctrl at 0x01000000 {
>  			serial_pins: serial_pinmux {
>  				mux {
> @@ -69,6 +50,81 @@
>  					bias-disable;
>  					output-high;
>  				};
> +
> +			};
> +
> +			audio_pins: audio_pinmux {
> +				mux_1 {
> +					pins = "gpio25", "gpio53", "gpio60";
> +					function = "i2s_tx_bclk";
> +					bias-pull,up;
> +				};
> +
> +				mux_2 {
> +					pins = "gpio27", "gpio54", "gpio63";
> +					function = "i2s_txd1";
> +					bias-pull,up;
> +				};
> +
> +				mux_3 {
> +					pins = "gpio28", "gpio55";
> +					function = "i2s_txd2";
> +					bias-pull,up;
> +				};
> +
> +				mux_4 {
> +					pins = "gpio29", "gpio56";
> +					function = "i2s_txd3";
> +					bias-pull,up;
> +				};
> +
> +				mux_5 {
> +					pins = "gpio24", "gpio52";
> +					function = "i2s_tx_mclk";
> +					bias-pull,up;
> +				};
> +
> +				mux_6 {
> +					pins = "gpio26", "gpio57", "gpio61";
> +					function = "i2s_tx_fsync";
> +					bias-pull,up;
> +				};
> +
> +				mux_7 {
> +					pins = "gpio2", "gpio23", "gpio63";
> +					function = "i2s_rxd";
> +					bias-pull,up;
> +				};
> +
> +				mux_8 {
> +					pins = "gpio20", "gpio58";
> +					function = "i2s_rx_mclk";
> +					bias-pull,up;
> +				};
> +
> +				mux_9 {
> +					pins = "gpio0", "gpio21", "gpio60";
> +					function = "i2s_rx_bclk";
> +					bias-pull,up;
> +				};
> +
> +				mux_10 {
> +					pins = "gpio1", "gpio22", "gpio61";
> +					function = "i2s_rx_fsync";
> +					bias-pull,up;
> +				};
> +
> +				mux_11 {
> +					pins = "gpio34", "gpio59", "gpio63";
> +					function = "i2s_spdif_in";
> +					bias-pull,up;
> +				};
> +
> +				mux_12 {
> +					pins = "gpio35", "gpio62", "gpio63";
> +					function = "i2s_spdif_out";
> +					bias-pull,up;
> +				};
>  			};
>  		};
>  
> @@ -108,5 +164,104 @@
>  		watchdog at b017000 {
>  			status = "ok";
>  		};
> +
> +		adcc: clock-controller at 7700038 {
> +			status = "ok";
> +		};
> +
> +		audio: audio at 7700000 {
> +			status = "ok";
> +		};
> +
> +		mbox0: mbox at 7708000 {
> +			status = "ok";
> +		};
> +
> +		mbox1: mbox at 770a000 {
> +			status = "ok";
> +		};
> +
> +		mbox2: mbox at 770c000 {
> +			status = "ok";
> +		};
> +
> +		mbox3: mbox at 770e000 {
> +			status = "ok";
> +		};
> +
> +		mbox4: mbox at 7706000 {
> +			status = "ok";
> +		};
> +
> +		stereo0: stereo at 7709000 {
> +			status = "ok";
> +		};
> +
> +		stereo1: stereo at 770b000 {
> +			status = "ok";
> +		};
> +
> +		stereo2: stereo at 770d000 {
> +			status = "ok";
> +		};
> +
> +		stereo3: stereo at 770f000 {
> +			status = "ok";
> +		};
> +
> +		/* Enable Audio Interfaces */
> +		i2s: ipq4019-pcm-i2s at 0 {
> +			status = "ok";
> +		};
> +
> +		i2splatform: qca-pcm-i2s at 7709000 {
> +			status = "ok";
> +		};
> +
> +		i2s1platform: qca-pcm-i2s1 at 770b000 {
> +			status = "ok";
> +		};
> +
> +		i2s1: ipq4019-pcm-i2s1 at 0 {
> +			status = "ok";
> +		};
> +
> +		i2s2platform: qca-pcm-i2s2 at 770d000 {
> +			status = "ok";
> +		};
> +
> +		i2s2: ipq4019-pcm-i2s2 at 0 {
> +			status = "ok";
> +		};
> +
> +		tdmplatform: qca-pcm-tdm at 7709000 {
> +			status = "ok";
> +		};
> +
> +		tdm: tdm at 0 {
> +			status = "ok";
> +		};
> +
> +		spdifplatform: qca-pcm-spdif at 7707000 {
> +			status = "ok";
> +		};
> +
> +		spdif: spdif at 0 {
> +			status = "ok";
> +		};
> +
> +		sound: sound at 0 {
> +			pinctrl-0 = <&audio_pins>;
> +			pinctrl-names = "default";
> +			status = "ok";
> +		};
> +
> +		i2c_0: i2c at 78b7000 { /* BLSP1 QUP2 */
> +			status = "ok";
> +
> +			qca_codec: qca_codec at 12 {
> +				status = "ok";
> +			};
> +		};
>  	};
>  };
> diff --git a/arch/arm/boot/dts/qcom-ipq4019.dtsi b/arch/arm/boot/dts/qcom-ipq4019.dtsi
> index 5c08d19..e2b4810 100644
> --- a/arch/arm/boot/dts/qcom-ipq4019.dtsi
> +++ b/arch/arm/boot/dts/qcom-ipq4019.dtsi
> @@ -1,5 +1,5 @@
>  /*
> - * Copyright (c) 2015, The Linux Foundation. All rights reserved.
> + * Copyright (c) 2015-2016, The Linux Foundation. All rights reserved.
>   *
>   * This program is free software; you can redistribute it and/or modify
>   * it under the terms of the GNU General Public License version 2 and
> @@ -15,6 +15,8 @@
>  
>  #include "skeleton.dtsi"
>  #include <dt-bindings/clock/qcom,gcc-ipq4019.h>
> +#include <dt-bindings/clock/qca,adcc-ipq4019.h>
> +#include <dt-bindings/sound/ipq4019-audio.h>
>  #include <dt-bindings/interrupt-controller/arm-gic.h>
>  #include <dt-bindings/interrupt-controller/irq.h>
>  
> @@ -90,6 +92,21 @@
>  			clock-frequency = <32768>;
>  			#clock-cells = <0>;
>  		};
> +
> +		xo: xo {
> +			compatible = "fixed-clock";
> +			clock-frequency = <48000000>;
> +			#clock-cells = <0>;
> +		};
> +	};
> +
> +	timer {
> +		compatible = "arm,armv7-timer";
> +		interrupts = <1 2 0xf08>,
> +			     <1 3 0xf08>,
> +			     <1 4 0xf08>,
> +			     <1 1 0xf08>;
> +		clock-frequency = <48000000>;
>  	};
>  
>  	soc {
> @@ -156,8 +173,13 @@
>  			#address-cells = <1>;
>  			#size-cells = <0>;
>  			status = "disabled";
> -		};
>  
> +			qca_codec: qca_codec at 12 {
> +				compatible = "qca,ipq4019-codec";
> +				reg = <0x12>;
> +				status = "disabled";
> +			};
> +		};
>  
>  		cryptobam: dma at 8e04000 {
>  			compatible = "qcom,bam-v1.7.0";
> @@ -263,5 +285,226 @@
>  			compatible = "qcom,pshold";
>  			reg = <0x4ab000 0x4>;
>  		};
> +
> +		adcc: clock-controller at 7700038 {
> +			compatible = "qcom,adcc-ipq4019";
> +			#clock-cells = <1>;
> +			#reset-cells = <1>;
> +			reg = <0x7700038 0x1DC>;
> +			status = "disabled";
> +		};
> +
> +		audio: audio at 7700000 {
> +			compatible = "qca,ipq4019-audio-adss";
> +			reg = <0x7700000 0x34>,
> +				<0x7707000 0x20>;
> +			resets = <&gcc AUDIO_BLK_ARES>;
> +			reset-names = "blk_rst";
> +			status = "disabled";
> +		};
> +
> +		pcm: pcm at 7704000 {
> +			compatible = "qca,ipq4019-pcm";
> +			reg = <0x7704000 0x2000>;
> +			dma-tx-channel = <MBOX3_TX_ID>;
> +			dma-rx-channel = <MBOX0_RX_ID>;
> +			stereo-tx-port = <STEREO3_ID>;
> +			stereo-rx-port = <STEREO0_ID>;
> +			clocks = <&adcc ADCC_PCM_CLK_SRC>;
> +			clock-names = "audio_pcm_clk";
> +			status = "disabled";
> +		};
> +
> +		mbox0: mbox at 7708000 {
> +			dma-index = <0>;
> +			compatible = "qca,ipq4019-mbox";
> +			reg = <0x7708000 0x1000>;
> +			interrupts = <0 156 0>;
> +			tx-channel = <MBOX0_TX_ID>;
> +			rx-channel = <MBOX0_RX_ID>;
> +			status = "disabled";
> +		};
> +
> +		mbox1: mbox at 770a000 {
> +			dma-index = <1>;
> +			compatible = "qca,ipq4019-mbox";
> +			reg = <0x770A000 0x1000>;
> +			interrupts = <0 157 0>;
> +			tx-channel = <MBOX1_TX_ID>;
> +			status = "disabled";
> +		};
> +
> +		mbox2: mbox at 770c000 {
> +			dma-index = <2>;
> +			compatible = "qca,ipq4019-mbox";
> +			reg = <0x770C000 0x1000>;
> +			interrupts = <0 158 0>;
> +			tx-channel = <MBOX2_TX_ID>;
> +			status = "disabled";
> +		};
> +
> +		mbox3: mbox at 770e000 {
> +			dma-index = <3>;
> +			compatible = "qca,ipq4019-mbox";
> +			reg = <0x770E000 0x1000>;
> +			interrupts = <0 159 0>;
> +			tx-channel = <MBOX3_TX_ID>;
> +			rx-channel = <MBOX3_RX_ID>;
> +			status = "disabled";
> +		};
> +
> +		mbox4: mbox at 7706000 {
> +			dma-index = <4>;
> +			compatible = "qca,ipq4019-mbox";
> +			reg = <0x7706000 0x1000>;
> +			interrupts = <0 163 0>;
> +			rx-channel = <MBOX_SPDIF_RX_ID>;
> +			status = "disabled";
> +		};
> +
> +		stereo0: stereo at 7709000 {
> +			stereo-index = <STEREO0_ID>;
> +			compatible = "qca,ipq4019-stereo";
> +			reg = <0x7709000 0x1000>;
> +			status = "disabled";
> +		};
> +
> +		stereo1: stereo at 770b000 {
> +			stereo-index = <STEREO1_ID>;
> +			compatible = "qca,ipq4019-stereo";
> +			reg = <0x770B000 0x1000>;
> +			status = "disabled";
> +		};
> +
> +		stereo2: stereo at 770d000 {
> +			stereo-index = <STEREO2_ID>;
> +			compatible = "qca,ipq4019-stereo";
> +			reg = <0x770D000 0x1000>;
> +			status = "disabled";
> +		};
> +
> +		stereo3: stereo at 770f000 {
> +			stereo-index = <STEREO3_ID>;
> +			compatible = "qca,ipq4019-stereo";
> +			reg = <0x770F000 0x1000>;
> +			status = "disabled";
> +		};
> +
> +		i2splatform: qca-pcm-i2s at 7709000 {
> +			compatible = "qca,ipq4019-pcm-i2s";
> +			reg = <0x7709000 0x1000>;
> +			status = "disabled";
> +		};
> +
> +		i2s: ipq4019-pcm-i2s at 0 {
> +			compatible = "qca,ipq4019-i2s";
> +			dma-tx-channel = <MBOX0_TX_ID>;
> +			stereo-tx-port = <STEREO0_ID>;
> +			dma-rx-channel = <MBOX3_RX_ID>;
> +			stereo-rx-port = <STEREO3_ID>;
> +			clocks = <&adcc ADCC_TXB_CLK_SRC>,
> +				<&adcc ADCC_TXM_CLK_SRC>,
> +				<&adcc ADCC_RXB_CLK_SRC>,
> +				<&adcc ADCC_RXM_CLK_SRC>;
> +			clock-names = "audio_tx_bclk",
> +				"audio_tx_mclk",
> +				"audio_rx_bclk",
> +				"audio_rx_mclk";
> +			status = "disabled";
> +		};
> +
> +		i2s1platform: qca-pcm-i2s1 at 770b000 {
> +			compatible = "qca,ipq4019-pcm-i2s1";
> +			reg = <0x770b000 0x1000>;
> +			status = "disabled";
> +		};
> +
> +		i2s1: ipq4019-pcm-i2s1 at 0 {
> +			compatible = "qca,ipq4019-i2s1";
> +			dma-tx-channel = <MBOX1_TX_ID>;
> +			stereo-tx-port = <STEREO1_ID>;
> +			clocks = <&adcc ADCC_TXB_CLK_SRC>,
> +				<&adcc ADCC_TXM_CLK_SRC>,
> +				<&adcc ADCC_RXB_CLK_SRC>,
> +				<&adcc ADCC_RXM_CLK_SRC>;
> +			clock-names = "audio_tx_bclk",
> +				"audio_tx_mclk",
> +				"audio_rx_bclk",
> +				"audio_rx_mclk";
> +			status = "disabled";
> +		};
> +
> +		i2s2platform: qca-pcm-i2s2 at 770d000 {
> +			compatible = "qca,ipq4019-pcm-i2s2";
> +			reg = <0x770d000 0x1000>;
> +			status = "disabled";
> +		};
> +
> +		i2s2: ipq4019-pcm-i2s2 at 0 {
> +			compatible = "qca,ipq4019-i2s2";
> +			dma-tx-channel = <MBOX2_TX_ID>;
> +			stereo-tx-port = <STEREO2_ID>;
> +			clocks = <&adcc ADCC_TXB_CLK_SRC>,
> +				<&adcc ADCC_TXM_CLK_SRC>,
> +				<&adcc ADCC_RXB_CLK_SRC>,
> +				<&adcc ADCC_RXM_CLK_SRC>;
> +			clock-names = "audio_tx_bclk",
> +				"audio_tx_mclk",
> +				"audio_rx_bclk",
> +				"audio_rx_mclk";
> +			status = "disabled";
> +		};
> +
> +		tdmplatform: qca-pcm-tdm at 7709000 {
> +			compatible = "qca,ipq4019-pcm-tdm";
> +			reg = <0x7709000 0x1000>;
> +			status = "disabled";
> +		};
> +
> +		tdm: tdm at 0 {
> +			compatible = "qca,ipq4019-tdm";
> +			dma-tx-channel = <MBOX0_TX_ID>;
> +			dma-rx-channel = <MBOX3_RX_ID>;
> +			stereo-tx-port = <STEREO0_ID>;
> +			stereo-rx-port = <STEREO3_ID>;
> +			clocks = <&adcc ADCC_TXB_CLK_SRC>,
> +				<&adcc ADCC_TXM_CLK_SRC>,
> +				<&adcc ADCC_RXB_CLK_SRC>,
> +				<&adcc ADCC_RXM_CLK_SRC>;
> +			clock-names = "audio_tx_bclk",
> +				"audio_tx_mclk",
> +				"audio_rx_bclk",
> +				"audio_rx_mclk";
> +			status = "disabled";
> +		};
> +
> +		spdifplatform: qca-pcm-spdif at 7707000 {
> +			compatible = "qca,ipq4019-pcm-spdif";
> +			reg = <0x7707000 0x1000>;
> +			status = "disabled";
> +		};
> +
> +		spdif: spdif at 0 {
> +			compatible = "qca,ipq4019-spdif";
> +			dma-tx-channel = <MBOX0_TX_ID>;
> +			dma-rx-channel = <MBOX_SPDIF_RX_ID>;
> +			stereo-tx-port = <STEREO0_ID>;
> +			clocks = <&adcc ADCC_TXB_CLK_SRC>,
> +				<&adcc ADCC_TXM_CLK_SRC>,
> +				<&adcc ADCC_SPDIF_SRC>,
> +				<&adcc ADCC_SPDIFDIV2_SRC >,
> +				<&adcc ADCC_AUDIO_SPDIFINFAST_SRC>;
> +			clock-names = "audio_tx_bclk",
> +				"audio_tx_mclk",
> +				"audio_spdif_src",
> +				"audio_spdif_div2",
> +				"audio_spdifinfast_src";
> +			status = "disabled";
> +		};
> +
> +		sound: sound at 0 {
> +			compatible = "qca,ipq4019-audio";
> +			status = "disabled";
> +		};
>  	};
>  };
> -- 
> The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
> a Linux Foundation Collaborative Project
> 

^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: [PATCH 2/4] qcom: ipq4019: ASoC clock driver support
  2016-07-15  7:07   ` njaigane at codeaurora.org
@ 2016-08-16  1:00     ` Stephen Boyd
  -1 siblings, 0 replies; 24+ messages in thread
From: Stephen Boyd @ 2016-08-16  1:00 UTC (permalink / raw)
  To: njaigane
  Cc: linux-arm-msm, linux, devicetree, linux-kernel, linux-soc,
	linux-arm-kernel, twp, andy.gross, david.brown, robh+dt,
	pawel.moll, mark.rutland, ijc+devicetree, galak, linux,
	mturquette, linus.walleij, plai, bgoswami, lgirdwood, broonie,
	perex, tiwai, bjorn.andersson, varada, pradeepb, snlakshm,
	linux-clk, linux-gpio, alsa-devel, bselvara

On 07/15, njaigane@codeaurora.org wrote:
> diff --git a/drivers/clk/qcom/Makefile b/drivers/clk/qcom/Makefile
> index 2a25f4e..aec6ab4 100644
> --- a/drivers/clk/qcom/Makefile
> +++ b/drivers/clk/qcom/Makefile
> @@ -4,6 +4,7 @@ clk-qcom-y += common.o
>  clk-qcom-y += clk-regmap.o
>  clk-qcom-y += clk-alpha-pll.o
>  clk-qcom-y += clk-pll.o
> +clk-qcom-y += clk-qcapll.o
>  clk-qcom-y += clk-rcg.o
>  clk-qcom-y += clk-rcg2.o
>  clk-qcom-y += clk-branch.o
> @@ -15,6 +16,7 @@ clk-qcom-$(CONFIG_QCOM_GDSC) += gdsc.o
>  obj-$(CONFIG_APQ_GCC_8084) += gcc-apq8084.o
>  obj-$(CONFIG_APQ_MMCC_8084) += mmcc-apq8084.o
>  obj-$(CONFIG_IPQ_GCC_4019) += gcc-ipq4019.o
> +obj-$(CONFIG_IPQ_ADCC_4019) += adcc-ipq4019.o

Alphabetize on config please.

>  obj-$(CONFIG_IPQ_GCC_806X) += gcc-ipq806x.o
>  obj-$(CONFIG_IPQ_LCC_806X) += lcc-ipq806x.o
>  obj-$(CONFIG_MSM_GCC_8660) += gcc-msm8660.o
> diff --git a/drivers/clk/qcom/adcc-ipq4019.c b/drivers/clk/qcom/adcc-ipq4019.c
> new file mode 100644
> index 0000000..0ed90e1
> --- /dev/null
> +++ b/drivers/clk/qcom/adcc-ipq4019.c
> @@ -0,0 +1,700 @@
> +/*
> + * Copyright (c) 2014 - 2016 The Linux Foundation. All rights reserved.
> + *
> + * This software is licensed under the terms of the GNU General Public
> + * License version 2, as published by the Free Software Foundation, and
> + * may be copied, distributed, and modified under those terms.
> + *
> + * 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 <linux/kernel.h>
> +#include <linux/err.h>
> +#include <linux/platform_device.h>
> +#include <linux/module.h>
> +#include <linux/of.h>
> +#include <linux/of_device.h>
> +#include <linux/clk-provider.h>
> +#include <linux/delay.h>
> +#include <linux/regmap.h>
> +#include <linux/reset-controller.h>
> +
> +#include <dt-bindings/clock/qca,adcc-ipq4019.h>
> +
> +#include "common.h"
> +#include "clk-regmap.h"
> +#include "clk-rcg.h"
> +#include "clk-qcapll.h"
> +#include "clk-branch.h"
> +#include "reset.h"
> +
> +#define AUDIO_PLL_CONFIG_REG				0x00000
> +#define AUDIO_PLL_MODULATION_REG			0x00004
> +#define AUDIO_PLL_MOD_STEP_REG				0x00008
> +#define CURRENT_AUDIO_PLL_MODULATION_REG		0x0000c
> +#define AUDIO_PLL_CONFIG1_REG				0x00010
> +#define AUDIO_ATB_SETTING_REG				0x00014
> +#define AUDIO_RXB_CFG_MUXR_REG				0x000cc
> +#define AUDIO_RXB_MISC_REG				0x000d0
> +#define AUDIO_RXB_CBCR_REG				0x000D4
> +#define AUDIO_RXM_CMD_RCGR_REG				0x000e8
> +#define AUDIO_RXM_CFG_RCGR_REG				0x000ec
> +#define AUDIO_RXM_MISC_REG				0x000f0
> +#define AUDIO_RXM_CBCR_REG				0x000F4
> +#define AUDIO_TXB_CFG_MUXR_REG				0x0010c
> +#define AUDIO_TXB_MISC_REG				0x00110
> +#define AUDIO_TXB_CBCR_REG				0x00114
> +#define AUDIO_SPDIF_MISC_REG				0x00118
> +#define AUDIO_SPDIF_CBCR_REG				0x0011c
> +#define AUDIO_SPDIFDIV2_MISC_REG			0x00120
> +#define AUDIO_SPDIFDIV2_CBCR_REG			0x00124
> +#define AUDIO_TXM_CMD_RCGR_REG				0x00128
> +#define AUDIO_TXM_CFG_RCGR_REG				0x0012c
> +#define AUDIO_TXM_MISC_REG				0x00130
> +#define AUDIO_TXM_CBCR_REG				0x00134
> +#define AUDIO_SAMPLE_CBCR_REG				0x00154
> +#define AUDIO_PCM_CMD_RCGR_REG				0x00168
> +#define AUDIO_PCM_CFG_RCGR_REG				0x0016C
> +#define AUDIO_PCM_MISC_REG				0x00170
> +#define AUDIO_PCM_CBCR_REG				0x00174
> +#define AUDIO_XO_CBCR_REG				0x00194
> +#define AUDIO_SPDIFINFAST_CMD_RCGR_REG			0x001A8
> +#define AUDIO_SPDIFINFAST_CFG_RCGR_REG			0x001AC
> +#define AUDIO_SPDIFINFAST_CBCR_REG			0x001B4
> +#define AUDIO_AHB_CBCR_REG				0x001c8
> +#define AUDIO_AHB_I2S0_CBCR_REG				0x001cc
> +#define AUDIO_AHB_I2S3_CBCR_REG				0x001d0
> +#define AUDIO_AHB_MBOX0_CBCR_REG			0x001D4
> +#define AUDIO_AHB_MBOX3_CBCR_REG			0x001d8

Lowercase hex only please. Also, just put the registers in the
structures directly. The defines are just a waste of lines.

> +
> +#define F(f, s, h, m, n) { (f), (s), (2 * (h) - 1), (m), (n) }

Is this used?

> +#define P_XO 0
> +#define ADSS_PLL 1
> +#define MCLK_MCLK_IN 2
> +#define BCLK_BCLK_IN 2
> +#define BCLK_MCLK_IN 3

Please preface all the sources with P_ so we know they're
"parents".

> +
> +static struct parent_map adcc_xo_adpll_padmclk_map[] = {
> +	{  P_XO, 0 },
> +	{  ADSS_PLL, 1 },
> +	{  MCLK_MCLK_IN, 2 },
> +};
> +
> +static const char * const adcc_xo_adpll_padmclk[] = {
> +	"xo",
> +	"adss_pll",
> +	"padmclk",
> +};
> +
> +static struct parent_map adcc_xo_adpll_padbclk_padmclk_map[] = {
> +	{  P_XO, 0 },
> +	{  ADSS_PLL, 1 },
> +	{  MCLK_MCLK_IN, 2 },
> +	{  BCLK_MCLK_IN, 3 },
> +};
> +
> +static const char * const adcc_xo_adpll_padbclk_padmclk[] = {
> +	"xo",
> +	"adss_pll",
> +	"padbclk",
> +	"padmclk",
> +};
> +
> +static struct parent_map adcc_xo_adpll_map[] = {
> +	{  P_XO, 0 },
> +	{  ADSS_PLL, 1 },
> +};
> +
> +static const char * const adcc_xo_adpll[] = {
> +	"xo",
> +	"adss_pll",
> +};
> +
> +static const struct pll_freq_tbl adss_freq_tbl[] = {
> +	{163840000, 1, 5, 40, 0x3D708},
> +	{180633600, 1, 5, 45, 0xA234},
> +	{184320000, 1, 5, 46, 0x51E9},
> +	{196608000, 1, 5, 49, 0x9bA6},
> +	{197568000, 1, 5, 49, 0x19168},

Spaces around braces please.

	{ 197568000, 1, 5, 49, 0x19168 },

> +	{}
> +};
> +
> +static struct clk_qcapll adss_pll_src = {
> +	.config_reg		= AUDIO_PLL_CONFIG_REG,
> +	.mod_reg		= AUDIO_PLL_MODULATION_REG,
> +	.modstep_reg		= AUDIO_PLL_MOD_STEP_REG,
> +	.current_mod_pll_reg	= CURRENT_AUDIO_PLL_MODULATION_REG,
> +	.config1_reg		= AUDIO_PLL_CONFIG1_REG,
> +	.freq_tbl = adss_freq_tbl,
> +	.clkr.hw.init = &(struct clk_init_data){
> +		.name = "adss_pll",
> +		.parent_names = (const char *[]){ "xo" },
> +		.num_parents = 1,
> +		.ops = &clk_qcapll_ops,
> +		.flags = CLK_IGNORE_UNUSED,
> +	},
> +};
> +
> +static const struct freq_tbl ftbl_m_clk[] = {
> +	{255, MCLK_MCLK_IN, 1, 0, 0},
> +	{2048000, ADSS_PLL, 96, 0, 0},
> +	{2822400, ADSS_PLL, 64, 0, 0},
> +	{4096000, ADSS_PLL, 48, 0, 0},
> +	{5644800, ADSS_PLL, 32, 0, 0},
> +	{6144000, ADSS_PLL, 32, 0, 0},
> +	{8192000, ADSS_PLL, 24, 0, 0},
> +	{11289600, ADSS_PLL, 16, 0, 0},
> +	{12288000, ADSS_PLL, 16, 0, 0},
> +	{14112000, ADSS_PLL, 14, 0, 0},
> +	{15360000, ADSS_PLL, 12, 0, 0},
> +	{16384000, ADSS_PLL, 12, 0, 0},
> +	{20480000, ADSS_PLL, 8, 0, 0},
> +	{22579200, ADSS_PLL, 8, 0, 0},
> +	{24576000, ADSS_PLL, 8, 0, 0},
> +	{30720000, ADSS_PLL, 6, 0, 0},
> +	{ }
> +};
> +
> +static struct clk_cdiv_rcg2 rxm_clk_src = {
> +	.cdiv.offset = AUDIO_RXM_MISC_REG,
> +	.cdiv.shift = 4,
> +	.cdiv.mask = 0xf,
> +	.cmd_rcgr = AUDIO_RXM_CMD_RCGR_REG,
> +	.hid_width = 5,
> +	.parent_map = adcc_xo_adpll_padmclk_map,
> +	.freq_tbl = ftbl_m_clk,
> +	.clkr.hw.init = &(struct clk_init_data){
> +		.name = "rxm_clk_src",
> +		.parent_names = adcc_xo_adpll_padmclk,
> +		.num_parents = 3,
> +		.ops = &clk_cdiv_rcg2_ops,
> +		.flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED,
> +	},
> +};
> +
> +static struct clk_branch adcc_rxm_clk_src = {
> +	.halt_reg = AUDIO_RXM_CBCR_REG,
> +	.clkr = {
> +		.enable_reg = AUDIO_RXM_CBCR_REG,
> +		.enable_mask = BIT(0),
> +		.hw.init = &(struct clk_init_data){
> +			.name = "adcc_rxm_clk_src",
> +			.parent_names = (const char *[]){"rxm_clk_src"},
> +			.num_parents = 1,
> +			.ops = &clk_branch2_ops,
> +			.flags = CLK_SET_RATE_PARENT,
> +		},
> +	},
> +};
> +
> +static struct clk_cdiv_rcg2 txm_clk_src = {
> +	.cdiv.offset = AUDIO_TXM_MISC_REG,
> +	.cdiv.shift = 4,
> +	.cdiv.mask = 0xf,
> +	.cmd_rcgr = AUDIO_TXM_CMD_RCGR_REG,
> +	.hid_width = 5,
> +	.parent_map = adcc_xo_adpll_padmclk_map,
> +	.freq_tbl = ftbl_m_clk,
> +	.clkr.hw.init = &(struct clk_init_data){
> +		.name = "txm_clk_src",
> +		.parent_names = adcc_xo_adpll_padmclk,
> +		.num_parents = 3,
> +		.ops = &clk_cdiv_rcg2_ops,
> +		.flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED,
> +	},
> +};
> +
> +static struct clk_branch adcc_txm_clk_src = {
> +	.halt_reg = AUDIO_TXM_CBCR_REG,
> +	.clkr = {
> +		.enable_reg = AUDIO_TXM_CBCR_REG,
> +		.enable_mask = BIT(0),
> +		.hw.init = &(struct clk_init_data){
> +			.name = "adcc_txm_clk_src",
> +			.parent_names = (const char *[]){
> +				"txm_clk_src",
> +			},
> +			.num_parents = 1,
> +			.ops = &clk_branch2_ops,
> +			.flags = CLK_SET_RATE_PARENT,
> +		},
> +	},
> +};
> +
> +static const struct freq_tbl ftbl_bclk_clk[] = {
> +	{254, BCLK_BCLK_IN, 1, 0, 0},
> +	{255, BCLK_MCLK_IN, 1, 0, 0},
> +	{512000, ADSS_PLL, 384, 0, 0},
> +	{705600, ADSS_PLL, 256, 0, 0},
> +	{1024000, ADSS_PLL, 192, 0, 0},
> +	{1411200, ADSS_PLL, 128, 0, 0},
> +	{1536000, ADSS_PLL, 128, 0, 0},
> +	{2048000, ADSS_PLL, 96, 0, 0},
> +	{2822400, ADSS_PLL, 64, 0, 0},
> +	{3072000, ADSS_PLL, 64, 0, 0},
> +	{4096000, ADSS_PLL, 48, 0, 0},
> +	{5120000, ADSS_PLL, 32, 0, 0},
> +	{5644800, ADSS_PLL, 32, 0, 0},
> +	{6144000, ADSS_PLL, 32, 0, 0},
> +	{7056000, ADSS_PLL, 24, 0, 0},
> +	{7680000, ADSS_PLL, 24, 0, 0},
> +	{8192000, ADSS_PLL, 24, 0, 0},
> +	{10240000, ADSS_PLL, 16, 0, 0},
> +	{11289600, ADSS_PLL, 16, 0, 0},
> +	{12288000, ADSS_PLL, 16, 0, 0},
> +	{14112000, ADSS_PLL, 16, 0, 0},
> +	{15360000, ADSS_PLL, 12, 0, 0},
> +	{16384000, ADSS_PLL, 12, 0, 0},
> +	{22579200, ADSS_PLL, 8, 0, 0},
> +	{24576000, ADSS_PLL,  8, 0, 0},
> +	{30720000, ADSS_PLL,  6, 0, 0},
> +	{ }
> +};
> +
> +static struct clk_muxr_misc txb_clk_src = {
> +	.misc.offset = AUDIO_TXB_MISC_REG,
> +	.misc.shift = 1,
> +	.misc.mask = 0x1FF,
> +	.muxr.offset = AUDIO_TXB_CFG_MUXR_REG,
> +	.muxr.shift = 8,
> +	.muxr.mask = 0x7,
> +	.parent_map = adcc_xo_adpll_padbclk_padmclk_map,
> +	.freq_tbl = ftbl_bclk_clk,
> +	.clkr.hw.init = &(struct clk_init_data){
> +		.name = "txb_clk_src",
> +		.parent_names = adcc_xo_adpll_padbclk_padmclk,
> +		.num_parents = 4,
> +		.ops = &clk_muxr_misc_ops,
> +		.flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED,
> +	},
> +};
> +
> +static struct clk_branch adcc_txb_clk_src = {
> +	.halt_reg = AUDIO_TXB_CBCR_REG,
> +	.clkr = {
> +		.enable_reg = AUDIO_TXB_CBCR_REG,
> +		.enable_mask = BIT(0),
> +		.hw.init = &(struct clk_init_data){
> +			.name = "adcc_txb_clk_src",
> +			.parent_names = (const char *[]){
> +				"txb_clk_src",
> +			},
> +			.num_parents = 1,
> +			.ops = &clk_branch2_ops,
> +			.flags = CLK_SET_RATE_PARENT,
> +		},
> +	},
> +};
> +
> +static struct clk_muxr_misc rxb_clk_src = {
> +	.misc.offset = AUDIO_RXB_MISC_REG,
> +	.misc.shift = 1,
> +	.misc.mask = 0x1FF,
> +	.muxr.offset = AUDIO_RXB_CFG_MUXR_REG,
> +	.muxr.shift = 8,
> +	.muxr.mask = 0x7,
> +	.parent_map = adcc_xo_adpll_padbclk_padmclk_map,
> +	.freq_tbl = ftbl_bclk_clk,
> +	.clkr.hw.init = &(struct clk_init_data){
> +		.name = "rxb_clk_src",
> +		.parent_names = adcc_xo_adpll_padbclk_padmclk,
> +		.num_parents = 4,
> +		.ops = &clk_muxr_misc_ops,
> +		.flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED,
> +	},
> +};
> +
> +
> +static struct clk_branch adcc_rxb_clk_src = {
> +	.halt_reg = AUDIO_RXB_CBCR_REG,
> +	.clkr = {
> +		.enable_reg = AUDIO_RXB_CBCR_REG,
> +		.enable_mask = BIT(0),
> +		.hw.init = &(struct clk_init_data){
> +			.name = "adcc_rxb_clk_src",
> +			.parent_names = (const char *[]){
> +				"rxb_clk_src",
> +			},
> +			.num_parents = 1,
> +			.ops = &clk_branch2_ops,
> +			.flags = CLK_SET_RATE_PARENT,
> +		},
> +	},
> +};
> +
> +
> +
> +static const struct freq_tbl ftbl_adcc_pcm_clk[] = {
> +	{8192000, ADSS_PLL, 24, 0, 0},
> +	{16384000, ADSS_PLL, 12, 0, 0},
> +	{ }
> +};
> +
> +static struct clk_cdiv_rcg2 pcm_clk_src = {
> +	.cdiv.offset = AUDIO_PCM_MISC_REG,
> +	.cdiv.shift = 4,
> +	.cdiv.mask = 0xf,
> +	.cmd_rcgr = AUDIO_PCM_CMD_RCGR_REG,
> +	.hid_width = 5,
> +	.parent_map = adcc_xo_adpll_map,
> +	.freq_tbl = ftbl_adcc_pcm_clk,
> +	.clkr.hw.init = &(struct clk_init_data){
> +		.name = "pcm_clk_src",
> +		.parent_names = adcc_xo_adpll,
> +		.num_parents = 2,
> +		.ops = &clk_cdiv_rcg2_ops,
> +		.flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED,
> +	},
> +};
> +
> +
> +
> +static struct clk_branch adcc_pcm_clk_src = {
> +	.halt_reg = AUDIO_PCM_CBCR_REG,
> +	.clkr = {
> +		.enable_reg = AUDIO_PCM_CBCR_REG,
> +		.enable_mask = BIT(0),
> +		.hw.init = &(struct clk_init_data){
> +			.name = "adcc_pcm_clk_src",
> +			.parent_names = (const char *[]){
> +				"pcm_clk_src",
> +			},
> +			.num_parents = 1,
> +			.ops = &clk_branch2_ops,
> +			.flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED,
> +		},
> +	},
> +};
> +
> +
> +

Remove all but one newline here.

> +static const struct freq_tbl ftbl_adcc_spdifinfast_clk[] = {
> +	F(49152000, ADSS_PLL, 0x04, 0, 0),
> +	{ }
> +};
> +
> +static struct clk_rcg2 spdifinfast_src = {
> +	.cmd_rcgr = AUDIO_SPDIFINFAST_CMD_RCGR_REG,
> +	.hid_width = 5,
> +	.parent_map = adcc_xo_adpll_map,
> +	.freq_tbl = ftbl_adcc_spdifinfast_clk,
> +	.clkr.hw.init = &(struct clk_init_data){
> +		.name = "spdifinfast_src",
> +		.parent_names = adcc_xo_adpll,
> +		.num_parents = 2,
> +		.ops = &clk_rcg2_ops,
> +		.flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED,
> +	},
> +};
> +
> +static struct clk_branch adcc_spdifinfast_src = {
> +	.halt_reg = AUDIO_SPDIFINFAST_CBCR_REG,
> +	.clkr = {
> +		.enable_reg = AUDIO_SPDIFINFAST_CBCR_REG,
> +		.enable_mask = BIT(0),
> +		.hw.init = &(struct clk_init_data){
> +			.name = "adcc_spdifinfast_src",
> +			.parent_names = (const char *[]){
> +				"spdifinfast_src",
> +			},
> +			.num_parents = 1,
> +			.ops = &clk_branch2_ops,
> +			.flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED,
> +		},
> +	},
> +};
> +
> +static struct clk_muxr_misc spdif_src = {
> +	.misc.offset = AUDIO_SPDIF_MISC_REG,
> +	.misc.shift = 1,
> +	.misc.mask = 0x1FF,
> +	.muxr.offset = AUDIO_TXB_CFG_MUXR_REG,
> +	.muxr.shift = 8,
> +	.muxr.mask = 0x7,
> +	.parent_map = adcc_xo_adpll_padbclk_padmclk_map,
> +	.freq_tbl = ftbl_m_clk,
> +	.clkr.hw.init = &(struct clk_init_data){
> +		.name = "spdif_src",
> +		.parent_names = adcc_xo_adpll_padbclk_padmclk,
> +		.num_parents = 4,
> +		.ops = &clk_muxr_misc_ops,
> +		.flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED,
> +	},
> +};
> +
> +static struct clk_branch adcc_spdif_src = {
> +	.halt_reg = AUDIO_SPDIF_CBCR_REG,
> +	.clkr = {
> +		.enable_reg = AUDIO_SPDIF_CBCR_REG,
> +		.enable_mask = BIT(0),
> +		.hw.init = &(struct clk_init_data){
> +			.name = "adcc_spdif_src",
> +			.parent_names = (const char *[]){
> +				"spdif_src",
> +			},
> +			.num_parents = 1,
> +			.ops = &clk_branch2_ops,
> +			.flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED,
> +		},
> +	},
> +};
> +
> +static struct clk_muxr_misc spdifdiv2_src = {
> +	.misc.offset = AUDIO_SPDIFDIV2_MISC_REG,
> +	.misc.shift = 1,
> +	.misc.mask = 0x1FF,
> +	.parent_map = adcc_xo_adpll_padbclk_padmclk_map,
> +	.muxr.offset = AUDIO_TXB_CFG_MUXR_REG,
> +	.muxr.shift = 8,
> +	.muxr.mask = 0x7,
> +	.freq_tbl = ftbl_bclk_clk,
> +	.clkr.hw.init = &(struct clk_init_data){
> +		.name = "spdifdiv2_src",
> +		.parent_names = adcc_xo_adpll_padbclk_padmclk,
> +		.num_parents = 4,
> +		.ops = &clk_muxr_misc_ops,
> +		.flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED,
> +	},
> +};
> +
> +static struct clk_branch adcc_spdifdiv2_src = {
> +	.halt_reg = AUDIO_SPDIFDIV2_CBCR_REG,
> +	.clkr = {
> +		.enable_reg = AUDIO_SPDIFDIV2_CBCR_REG,
> +		.enable_mask = BIT(0),
> +		.hw.init = &(struct clk_init_data){
> +			.name = "adcc_spdifdiv2_src",
> +			.parent_names = (const char *[]){
> +				"spdifdiv2_src",
> +			},
> +			.num_parents = 1,
> +			.ops = &clk_branch2_ops,
> +			.flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED,
> +		},
> +	},
> +};
> +
> +static struct clk_branch adcc_sample_src = {
> +	.halt_reg = AUDIO_SAMPLE_CBCR_REG,
> +	.clkr = {
> +		.enable_reg = AUDIO_SAMPLE_CBCR_REG,
> +		.enable_mask = BIT(0),
> +		.hw.init = &(struct clk_init_data){
> +			.name = "adcc_sample_src",
> +			.parent_names = (const char *[]){
> +				"pcnoc_clk_src",
> +			},
> +			.num_parents = 1,
> +			.ops = &clk_branch2_ops,
> +			.flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED,
> +		},
> +	},
> +};
> +
> +static struct clk_branch adcc_xo_src = {
> +	.halt_reg = AUDIO_XO_CBCR_REG,
> +	.clkr = {
> +		.enable_reg = AUDIO_XO_CBCR_REG,
> +		.enable_mask = BIT(0),
> +		.hw.init = &(struct clk_init_data){
> +			.name = "adcc_xo_src",
> +			.parent_names = (const char *[]){
> +				"XO",
> +			},
> +			.num_parents = 1,
> +			.ops = &clk_branch2_ops,
> +			.flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED,
> +		},
> +	},
> +};
> +
> +
> +static struct clk_branch adcc_ahb_src = {
> +	.halt_reg = AUDIO_AHB_CBCR_REG,
> +	.clkr = {
> +		.enable_reg = AUDIO_AHB_CBCR_REG,
> +		.enable_mask = BIT(0),
> +		.hw.init = &(struct clk_init_data){
> +			.name = "adcc_audio_ahb_src",
> +			.parent_names = (const char *[]){
> +				"pcnoc_clk_src",
> +			},
> +			.num_parents = 1,
> +			.ops = &clk_branch2_ops,
> +			.flags = CLK_IGNORE_UNUSED,
> +		},
> +	},
> +};
> +
> +static struct clk_branch adcc_ahb_i2s0_src = {
> +	.halt_reg = AUDIO_AHB_I2S0_CBCR_REG,
> +	.clkr = {
> +		.enable_reg = AUDIO_AHB_I2S0_CBCR_REG,
> +		.enable_mask = BIT(0),
> +		.hw.init = &(struct clk_init_data){
> +			.name = "adcc_audio_ahb_i2s0",
> +			.parent_names = (const char *[]){
> +				"pcnoc_clk_src",
> +			},
> +			.num_parents = 1,
> +			.ops = &clk_branch2_ops,
> +			.flags = CLK_IGNORE_UNUSED,
> +		},
> +	},
> +};
> +
> +static struct clk_branch adcc_ahb_i2s3_src = {
> +	.halt_reg = AUDIO_AHB_I2S3_CBCR_REG,
> +	.clkr = {
> +		.enable_reg = AUDIO_AHB_I2S3_CBCR_REG,
> +		.enable_mask = BIT(0),
> +		.hw.init = &(struct clk_init_data){
> +			.name = "adcc_audio_ahb_i2s3",
> +			.parent_names = (const char *[]){
> +				"pcnoc_clk_src",
> +			},
> +			.num_parents = 1,
> +			.ops = &clk_branch2_ops,
> +			.flags = CLK_IGNORE_UNUSED,
> +		},
> +	},
> +};
> +
> +static struct clk_branch adcc_ahb_mbox0_src = {
> +	.halt_reg = AUDIO_AHB_MBOX0_CBCR_REG,
> +	.clkr = {
> +		.enable_reg = AUDIO_AHB_MBOX0_CBCR_REG,
> +		.enable_mask = BIT(0),
> +		.hw.init = &(struct clk_init_data){
> +			.name = "adcc_audio_mbox0_src",
> +			.parent_names = (const char *[]){
> +				"pcnoc_clk_src",
> +			},
> +			.num_parents = 1,
> +			.ops = &clk_branch2_ops,
> +			.flags = CLK_IGNORE_UNUSED,
> +		},
> +	},
> +};
> +
> +static struct clk_branch adcc_ahb_mbox3_src = {
> +	.halt_reg = AUDIO_AHB_MBOX3_CBCR_REG,
> +	.clkr = {
> +		.enable_reg = AUDIO_AHB_MBOX3_CBCR_REG,
> +		.enable_mask = BIT(0),
> +		.hw.init = &(struct clk_init_data){
> +			.name = "adcc_ahb_mbox3_src",
> +			.parent_names = (const char *[]){
> +				"pcnoc_clk_src",
> +			},
> +			.num_parents = 1,
> +			.ops = &clk_branch2_ops,
> +			.flags = CLK_IGNORE_UNUSED,
> +		},
> +	},
> +};
> +
> +static struct clk_regmap *adcc_ipq4019_clocks[] = {
> +	[ADSS_PLL_SRC]				= &adss_pll_src.clkr,
> +	[RXM_CLK_SRC]				= &rxm_clk_src.clkr,
> +	[ADCC_RXM_CLK_SRC]			= &adcc_rxm_clk_src.clkr,
> +	[TXM_CLK_SRC]				= &txm_clk_src.clkr,
> +	[ADCC_TXM_CLK_SRC]			= &adcc_txm_clk_src.clkr,
> +	[TXB_CLK_SRC]				= &txb_clk_src.clkr,
> +	[ADCC_TXB_CLK_SRC]			= &adcc_txb_clk_src.clkr,
> +	[RXB_CLK_SRC]				= &rxb_clk_src.clkr,
> +	[ADCC_RXB_CLK_SRC]			= &adcc_rxb_clk_src.clkr,
> +	[PCM_CLK_SRC]				= &pcm_clk_src.clkr,
> +	[ADCC_PCM_CLK_SRC]			= &adcc_pcm_clk_src.clkr,
> +	[AUDIO_SPDIFINFAST_SRC]			= &spdifinfast_src.clkr,
> +	[ADCC_AUDIO_SPDIFINFAST_SRC]		= &adcc_spdifinfast_src.clkr,
> +	[ADCC_AUDIO_AHB_SRC]			= &adcc_ahb_src.clkr,
> +	[ADCC_AHB_I2S0]				= &adcc_ahb_i2s0_src.clkr,
> +	[ADCC_AHB_I2S3]				= &adcc_ahb_i2s3_src.clkr,
> +	[ADCC_AHB_MBOX0_SRC]			= &adcc_ahb_mbox0_src.clkr,
> +	[ADCC_AHB_MBOX3_SRC]			= &adcc_ahb_mbox3_src.clkr,
> +	[SPDIF_SRC]				= &spdif_src.clkr,
> +	[ADCC_SPDIF_SRC]			= &adcc_spdif_src.clkr,
> +	[SPDIFDIV2_SRC]				= &spdifdiv2_src.clkr,
> +	[ADCC_SPDIFDIV2_SRC]			= &adcc_spdifdiv2_src.clkr,
> +	[ADCC_SAMPLE_SRC]			= &adcc_sample_src.clkr,
> +	[ADCC_XO_SRC]				= &adcc_xo_src.clkr,
> +};
> +
> +static const struct qcom_reset_map adcc_ipq4019_resets[] = {
> +};

Are there any resets? If not, please update the common.c file to
handle that case and not register a reset provider.

> +
> +struct cdiv_fixed {

Is this structure used?

> +	char	*name;
> +	char	*pname;
> +	u32	flags;
> +	u32	mult;
> +	u32	div;
> +};
> +
> +static const struct regmap_config adcc_ipq4019_regmap_config = {
> +	.reg_bits	= 32,
> +	.reg_stride	= 4,
> +	.val_bits	= 32,
> +	.max_register	= 0x2ff,
> +	.fast_io	= true,
> +};
> +
> +static const struct qcom_cc_desc adcc_ipq4019_desc = {
> +	.config = &adcc_ipq4019_regmap_config,
> +	.clks = adcc_ipq4019_clocks,
> +	.num_clks = ARRAY_SIZE(adcc_ipq4019_clocks),
> +	.resets = adcc_ipq4019_resets,
> +	.num_resets = ARRAY_SIZE(adcc_ipq4019_resets),
> +};
> +
> +static const struct of_device_id adcc_ipq4019_match_table[] = {
> +	{ .compatible = "qcom,adcc-ipq4019" },
> +	{ }
> +};
> +MODULE_DEVICE_TABLE(of, gcc_ipq4019_match_table);
> +
> +static int adcc_ipq4019_probe(struct platform_device *pdev)
> +{
> +	struct device *dev = &pdev->dev;
> +	struct regmap *regmap;
> +
> +	/* High speed external clock */
> +	clk_register_fixed_rate(dev, "xo", NULL, CLK_IS_ROOT, 48000000);

This should come from the board, don't register it here.

> +
> +	/* External padbclk & padmclk clock.These [254 & 255] frequencies are

Multiline comments put the "/*" on a separate line from the rest
of the text.

> +	 * taken as tokens only to support the INPUTS from PADS.
> +	 * Reference: ADSS_HPG/HDD document for IPQ4019
> +	 */
> +	clk_register_fixed_rate(dev, "padbclk", NULL, CLK_IS_ROOT, 254);
> +	clk_register_fixed_rate(dev, "padmclk", NULL, CLK_IS_ROOT, 255);

This looks like a hack. What's going on?

> +
> +	regmap = qcom_cc_map(pdev, &adcc_ipq4019_desc);
> +	if (IS_ERR(regmap))
> +		return PTR_ERR(regmap);
> +
> +	return qcom_cc_really_probe(pdev, &adcc_ipq4019_desc, regmap);

You don't have to call qcom_cc_map() and qcom_cc_really_probe()
if you don't need to do anything with the mapping in this probe.
Just call qcom_cc_probe().

> +}
> +
> +static int adcc_ipq4019_remove(struct platform_device *pdev)
> +{
> +	qcom_cc_remove(pdev);
> +	return 0;

This is useless to call now, and in fact it's been deleted.

> +}

> diff --git a/drivers/clk/qcom/clk-qcapll.c b/drivers/clk/qcom/clk-qcapll.c
> new file mode 100644
> index 0000000..fac45c8
> --- /dev/null
> +++ b/drivers/clk/qcom/clk-qcapll.c
> @@ -0,0 +1,197 @@
> +/*
> + * Copyright (c) 2013, 2015-2016 The Linux Foundation. All rights reserved.
> + *
> + * This software is licensed under the terms of the GNU General Public
> + * License version 2, as published by the Free Software Foundation, and
> + * may be copied, distributed, and modified under those terms.
> + *
> + * 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 <linux/kernel.h>
> +#include <linux/bitops.h>
> +#include <linux/err.h>
> +#include <linux/delay.h>
> +#include <linux/export.h>
> +#include <linux/clk-provider.h>
> +#include <linux/regmap.h>
> +
> +#include <asm/div64.h>
> +
> +#include "clk-qcapll.h"
> +
> +#define PLL_CONFIG1_SRESET_L		BIT(0)
> +#define PLL_MODULATION_START		BIT(0)
> +#define PLL_CONFIG_PLLPWD		BIT(5)
> +
> +#define PLL_POSTDIV_MASK	0x380
> +#define PLL_POSTDIV_SHFT	7
> +#define PLL_PLLPWD_MASK         0x20
> +#define PLL_PLLPWD_SHFT         5
> +#define PLL_REFDIV_MASK		0x7
> +#define PLL_REFDIV_SHFT		0
> +#define PLL_TGT_INT_SHFT	1
> +#define PLL_TGT_INT_MASK	0x3FE
> +#define PLL_TGT_FRAC_MASK	0x1FFFF800
> +#define PLL_TGT_FRAC_SHFT	11
> +
> +
> +static int clk_qcapll_enable(struct clk_hw *hw)
> +{
> +	struct clk_qcapll *pll = to_clk_qcapll(hw);
> +	int ret;
> +
> +	/* Enable PLL bypass mode. */
> +	ret = regmap_update_bits(pll->clkr.regmap, pll->config_reg,
> +				 PLL_CONFIG_PLLPWD, 0);
> +	if (ret)
> +		return ret;
> +
> +	return 0;
> +}
> +
> +static void clk_qcapll_disable(struct clk_hw *hw)
> +{
> +	struct clk_qcapll *pll = to_clk_qcapll(hw);
> +
> +	/* Disable PLL bypass mode. */
> +	regmap_update_bits(pll->clkr.regmap, pll->config_reg, PLL_CONFIG_PLLPWD,
> +			   0x1);
> +}
> +
> +static int clk_qcapll_is_enabled(struct clk_hw *hw)
> +{
> +	u32 config;
> +	struct clk_qcapll *pll = to_clk_qcapll(hw);
> +
> +	regmap_read(pll->clkr.regmap, pll->config_reg, &config);
> +	return config & PLL_PLLPWD_MASK;
> +}
> +
> +static unsigned long
> +clk_qcapll_recalc_rate(struct clk_hw *hw, unsigned long parent_rate)
> +{
> +	struct clk_qcapll *pll = to_clk_qcapll(hw);
> +	u32 ref_div, post_plldiv, tgt_div_frac, tgt_div_int;
> +	u32 config, mod_reg;
> +
> +	regmap_read(pll->clkr.regmap, pll->config_reg, &config);
> +	regmap_read(pll->clkr.regmap, pll->mod_reg, &mod_reg);
> +
> +	ref_div = (config & PLL_REFDIV_MASK) >> PLL_REFDIV_SHFT;
> +	post_plldiv = (config & PLL_POSTDIV_SHFT) >> PLL_POSTDIV_SHFT;

Why did we read these if we don't do math?

> +	tgt_div_frac = (mod_reg & PLL_TGT_FRAC_MASK) >>  PLL_TGT_FRAC_SHFT;
> +	tgt_div_int = (mod_reg & PLL_TGT_INT_MASK) >> PLL_TGT_INT_SHFT;
> +
> +	/*
> +	 * FICO = (Fref / (refdiv+1)) * (Ninv + Nfrac[17:5]/2^13
> +	 *	   + Nfrac[4:0]/(25*2^13)).
> +	 *
> +	 * we use this Lookups to get the precise frequencies as we need

why is Lookups capitalized?

> +	 * the calculation would need use of some math functions to get
> +	 * precise values which will add to the complexity. Hence, a simple
> +	 * lookup table based on the Fract values

Why is Fract capitalized? What does Fract even mean?

> +	 */
> +
> +	if (tgt_div_frac == 0x3D708)
> +		return 163840000;
> +	else if (tgt_div_frac == 0xA234)
> +		return 180633600;
> +	else if (tgt_div_frac == 0x51E9)
> +		return 184320000;
> +	else if (tgt_div_frac == 0x9bA6)
> +		return 196608000;
> +	else if (tgt_div_frac == 0x19168)
> +		return 197568000;

Math is ok, this isn't performance sensitive code.

> +
> +	return 0;
> +}
> +
> +static const
> +struct pll_freq_tbl *find_freq(const struct pll_freq_tbl *f, unsigned long rate)
> +{
> +	if (!f)
> +		return NULL;
> +
> +	for (; f->freq; f++)
> +		if (rate <= f->freq)
> +			return f;
> +
> +	return NULL;
> +}

We have qcom_find_freq for this I thought? Ah I see that this is
the same named structure but qca pll specific. Please rename the
struct and function to be qca specific.

> +
> +static int
> +clk_qcapll_determine_rate(struct clk_hw *hw, struct clk_rate_request *req)
> +{
> +	struct clk_qcapll *pll = to_clk_qcapll(hw);
> +	const struct pll_freq_tbl *f;
> +	unsigned long rate;
> +
> +	f = find_freq(pll->freq_tbl, req->rate);
> +	if (!f)
> +		rate = clk_qcapll_recalc_rate(hw, req->best_parent_rate);
> +	else
> +		rate = f->freq;
> +
> +	req->best_parent_rate = req->rate = rate;
> +
> +	return 0;
> +}
> +
> +static int
> +clk_qcapll_set_rate(struct clk_hw *hw, unsigned long rate, unsigned long p_rate)
> +{
> +	struct clk_qcapll *pll = to_clk_qcapll(hw);
> +	const struct pll_freq_tbl *f;
> +	u32 val, mask;
> +
> +	f = find_freq(pll->freq_tbl, rate);
> +	if (!f)
> +		return -EINVAL;
> +
> +	if (clk_qcapll_is_enabled(hw))
> +		clk_qcapll_disable(hw);
> +
> +	regmap_write(pll->clkr.regmap, pll->config1_reg, 0xc);
> +	udelay(2);
> +	regmap_write(pll->clkr.regmap, pll->config1_reg, 0xd);
> +
> +	val = f->postplldiv << PLL_POSTDIV_SHFT;
> +	val |= f->refdiv << PLL_REFDIV_SHFT;
> +
> +	mask = PLL_POSTDIV_MASK | PLL_REFDIV_MASK;
> +	regmap_update_bits(pll->clkr.regmap, pll->config_reg, mask, val);
> +
> +	clk_qcapll_enable(hw);
> +
> +	val = f->tgt_div_int << PLL_TGT_INT_SHFT;
> +	val |= f->tgt_div_frac << PLL_TGT_FRAC_SHFT;
> +
> +	mask = PLL_TGT_FRAC_MASK | PLL_TGT_INT_MASK;
> +	regmap_update_bits(pll->clkr.regmap, pll->mod_reg, mask, val);
> +
> +	/* Start the PLL to initiate the Modulation. */

Please drop full stop.

> +	regmap_update_bits(pll->clkr.regmap, pll->mod_reg,
> +						PLL_MODULATION_START, 0);
> +
> +	/*
> +	 * Wait until PLL is locked. Refer DPLL document for IPQ4019.
> +	 * This is recommended settling time for the PLL.
> +	 */
> +	udelay(50);
> +
> +	return 0;
> +}
> +
> +const struct clk_ops clk_qcapll_ops = {
> +	.enable = clk_qcapll_enable,
> +	.disable = clk_qcapll_disable,
> +	.is_enabled = clk_qcapll_is_enabled,
> +	.recalc_rate = clk_qcapll_recalc_rate,
> +	.determine_rate = clk_qcapll_determine_rate,
> +	.set_rate = clk_qcapll_set_rate,
> +};
> +EXPORT_SYMBOL_GPL(clk_qcapll_ops);
> diff --git a/drivers/clk/qcom/clk-qcapll.h b/drivers/clk/qcom/clk-qcapll.h
> new file mode 100644
> index 0000000..c0304ac
> --- /dev/null
> +++ b/drivers/clk/qcom/clk-qcapll.h
> @@ -0,0 +1,60 @@
> +/*
> + * Copyright (c) 2013, 2015-2016 The Linux Foundation. All rights reserved.
> + *
> + * This software is licensed under the terms of the GNU General Public
> + * License version 2, as published by the Free Software Foundation, and
> + * may be copied, distributed, and modified under those terms.
> + *
> + * 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.
> + */
> +
> +#ifndef __QCOM_CLK_QCA_PLL_H__
> +#define __QCOM_CLK_QCA_PLL_H__
> +
> +#include <linux/clk-provider.h>
> +#include "clk-regmap.h"
> +
> +/**
> + * struct pll_freq_tbl - PLL frequency table

Missing freq. Perhaps we should expand the general pll_freq_tbl
structure with these parameters? Or use a union for different
types of pll settings? Or just rename it to be qca specific.

> + * @postplldiv: postplldiv value
> + * @refdiv: refdiv value
> + * @tgt_div_int: tgt_div_int value
> + * @tgt_div_frac: tgt_div_frac values
> + */
> +struct pll_freq_tbl {
> +	unsigned long freq;
> +	u8 postplldiv;
> +	u8 refdiv;
> +	u8 tgt_div_int;
> +	u32 tgt_div_frac;
> +};
> +
> +/**
> + * struct clk_pll - phase locked loop (PLL)

It isn't called that.

> + * @config_reg: config register
> + * @mode_reg: mode register
> + * @status_reg: status register
> + * @status_bit: ANDed with @status_reg to determine if PLL is enabled
> + * @freq_tbl: PLL frequency table
> + * @hw: handle between common and hardware-specific interfaces

This doesn't even exist. clkr instead?

> + */
> +struct clk_qcapll {
> +	u32 config_reg;
> +	u32 mod_reg;
> +	u32 modstep_reg;
> +	u32 current_mod_pll_reg;
> +	u32 config1_reg;
> +
> +	const struct pll_freq_tbl *freq_tbl;
> +	struct clk_regmap clkr;
> +};
> +
> +extern const struct clk_ops clk_qcapll_ops;
> +
> +#define to_clk_qcapll(_hw) container_of(to_clk_regmap(_hw), \
> +						struct clk_qcapll, clkr)
> +
> +#endif
> diff --git a/drivers/clk/qcom/clk-rcg.h b/drivers/clk/qcom/clk-rcg.h
> index b904c33..562207c 100644
> --- a/drivers/clk/qcom/clk-rcg.h
> +++ b/drivers/clk/qcom/clk-rcg.h
> @@ -1,5 +1,5 @@
>  /*
> - * Copyright (c) 2013, The Linux Foundation. All rights reserved.
> + * Copyright (c) 2013-2016 The Linux Foundation. All rights reserved.
>   *
>   * This software is licensed under the terms of the GNU General Public
>   * License version 2, as published by the Free Software Foundation, and
> @@ -20,7 +20,7 @@
>  struct freq_tbl {
>  	unsigned long freq;
>  	u8 src;
> -	u8 pre_div;
> +	u16 pre_div;

This needs explaining.

>  	u16 m;
>  	u16 n;
>  };
> @@ -68,6 +68,18 @@ struct pre_div {
>  };
>  
>  /**
> + * struct c_div - custom-divider used with Different Offsets

Why is Different and Offsets capitalized?

> + * @c_div_offset: offset of the CDIV in the ADDRESS Space

it's just called offset. And I have no idea why ADDRESS is caps
and Space is capitalized and why it isn't just "address offset".

> + * @c_div_shift: lowest bit of pre divider field
> + * @c_div_width: number of bits in pre divider
> + */
> +struct c_div {
> +	u32	offset;
> +	u8	shift;
> +	u32	mask;
> +};
> +
> +/**
>   * struct src_sel - source selector
>   * @src_sel_shift: lowest bit of source selection field
>   * @parent_map: map from software's parent index to hardware's src_sel field
> @@ -172,6 +184,55 @@ struct clk_rcg2 {
>  
>  #define to_clk_rcg2(_hw) container_of(to_clk_regmap(_hw), struct clk_rcg2, clkr)
>  
> +/**
> + * struct clk_cdiv_rcg2 - cdiv with root clock generator
> + *
> + * @cmd_rcgr: corresponds to *_CMD_RCGR
> + * @mnd_width: number of bits in m/n/d values
> + * @hid_width: number of bits in half integer divider
> + * @parent_map: map from software's parent index to hardware's src_sel field

missing cdiv

> + * @freq_tbl: frequency table
> + * @clkr: regmap clock handle
> + * @lock: register lock

No lock.

> + *
> + */
> +struct clk_cdiv_rcg2 {
> +	u32		cmd_rcgr;
> +	u8		mnd_width;
> +	u8		hid_width;
> +	struct c_div	cdiv;
> +	const struct parent_map	*parent_map;
> +	const struct freq_tbl	*freq_tbl;
> +	struct clk_regmap	clkr;
> +};
> +
> +#define to_clk_cdiv_rcg2(_hw) container_of(to_clk_regmap(_hw), \
> +						struct clk_cdiv_rcg2, clkr)
> +
> +
> +/**
> + * struct clk_muxr_misc - mux and misc register
> + *
> + * @cmd_rcgr: corresponds to *_CMD_RCGR
> + * @mnd_width: number of bits in m/n/d values
> + * @hid_width: number of bits in half integer divider

Huh?

> + * @parent_map: map from software's parent index to hardware's src_sel field
> + * @freq_tbl: frequency table
> + * @clkr: regmap clock handle
> + * @lock: register lock

Where?

> + *
> + */
> +struct clk_muxr_misc {
> +	struct c_div			muxr;
> +	struct c_div			misc;
> +	const struct parent_map		*parent_map;
> +	const struct freq_tbl	*freq_tbl;
> +	struct clk_regmap		clkr;
> +};
> +
> +#define to_clk_muxr_misc(_hw) container_of(to_clk_regmap(_hw), \
> +						struct clk_muxr_misc, clkr)
> +
>  extern const struct clk_ops clk_rcg2_ops;
>  extern const struct clk_ops clk_rcg2_shared_ops;
>  extern const struct clk_ops clk_edp_pixel_ops;
> diff --git a/drivers/clk/qcom/clk-rcg2.c b/drivers/clk/qcom/clk-rcg2.c
> index a071bba..000c423 100644
> --- a/drivers/clk/qcom/clk-rcg2.c
> +++ b/drivers/clk/qcom/clk-rcg2.c
> @@ -1,5 +1,5 @@
>  /*
> - * Copyright (c) 2013, The Linux Foundation. All rights reserved.
> + * Copyright (c) 2013-2016, The Linux Foundation. All rights reserved.
>   *
>   * This software is licensed under the terms of the GNU General Public
>   * License version 2, as published by the Free Software Foundation, and
> @@ -20,7 +20,6 @@
>  #include <linux/delay.h>
>  #include <linux/regmap.h>
>  #include <linux/math64.h>
> -
>  #include <asm/div64.h>

No.

>  
>  #include "clk-rcg.h"
> @@ -46,6 +45,7 @@
>  #define M_REG			0x8
>  #define N_REG			0xc
>  #define D_REG			0x10
> +#define FEPLL_500_SRC		0x2

No.

>  
>  static int clk_rcg2_is_enabled(struct clk_hw *hw)
>  {
> @@ -209,6 +209,7 @@ static int _freq_tbl_determine_rate(struct clk_hw *hw,
>  	} else {
>  		rate =  clk_hw_get_rate(p);
>  	}
> +
>  	req->best_parent_hw = p;
>  	req->best_parent_rate = rate;
>  	req->rate = f->freq;

Noise.

> @@ -810,3 +811,697 @@ const struct clk_ops clk_gfx3d_ops = {
>  	.determine_rate = clk_gfx3d_determine_rate,
>  };
>  EXPORT_SYMBOL_GPL(clk_gfx3d_ops);
> +
> +static int clk_cdiv_rcg2_is_enabled(struct clk_hw *hw)
> +{
> +	struct clk_cdiv_rcg2 *rcg = to_clk_cdiv_rcg2(hw);
> +	u32 cmd = 0;
> +	int ret;
> +
> +	ret = regmap_read(rcg->clkr.regmap, rcg->cmd_rcgr + CMD_REG, &cmd);
> +	if (ret < 0)
> +		return false;
> +
> +	return (cmd & CMD_ROOT_OFF) == 0;
> +}
> +
> +static u8 clk_cdiv_rcg2_get_parent(struct clk_hw *hw)
> +{
> +	struct clk_cdiv_rcg2 *rcg = to_clk_cdiv_rcg2(hw);
> +	int num_parents = clk_hw_get_num_parents(hw);
> +	u32 cfg;
> +	int i, ret;
> +
> +	ret = regmap_read(rcg->clkr.regmap, rcg->cmd_rcgr + CFG_REG, &cfg);
> +	if (ret)
> +		goto err;
> +
> +	cfg &= CFG_SRC_SEL_MASK;
> +	cfg >>= CFG_SRC_SEL_SHIFT;
> +
> +	for (i = 0; i < num_parents; i++)
> +		if (cfg == rcg->parent_map[i].cfg)
> +			return i;
> +err:
> +	pr_debug("%s: Cannot find parent of %s clock, using default.\n",
> +			__func__, __clk_get_name(hw->clk));
> +	return 0;
> +}
> +
> +static int cdiv_update_config(struct clk_cdiv_rcg2 *rcg)
> +{
> +	int count, ret;
> +	struct clk_hw *hw = &rcg->clkr.hw;
> +	const char *name = __clk_get_name(hw->clk);
> +
> +	ret = regmap_update_bits(rcg->clkr.regmap, rcg->cmd_rcgr + CMD_REG,
> +				 CMD_UPDATE, CMD_UPDATE);
> +	if (ret)
> +		return ret;
> +
> +	/* Wait for update to take effect */
> +	for (count = 500; count > 0; count--) {
> +		u32 cmd = ~0U;
> +
> +		/* ignore regmap errors - until we exhaust retry count. */

Why? Is a regmap error going to get better somehow?

> +		ret = regmap_read(rcg->clkr.regmap, rcg->cmd_rcgr + CMD_REG,
> +									&cmd);
> +
> +		if (ret >= 0 && !(cmd & CMD_UPDATE))
> +			return 0;
> +
> +		udelay(1);
> +	}
> +
> +	WARN(ret, "%s: rcg didn't update its configuration.", name);
> +	return ret ? ret : -ETIMEDOUT;
> +}
> +
> +static int clk_cdiv_rcg2_set_parent(struct clk_hw *hw, u8 index)
> +{
> +	struct clk_cdiv_rcg2 *rcg = to_clk_cdiv_rcg2(hw);
> +	int ret;
> +
> +	ret = regmap_update_bits(rcg->clkr.regmap, rcg->cmd_rcgr + CFG_REG,
> +				 CFG_SRC_SEL_MASK,
> +				 rcg->parent_map[index].cfg <<
> +				 CFG_SRC_SEL_SHIFT);
> +	if (ret)
> +		return ret;
> +
> +	return cdiv_update_config(rcg);
> +}
> +
> +static unsigned long
> +clk_cdiv_rcg2_recalc_rate(struct clk_hw *hw, unsigned long parent_rate)
> +{
> +	struct clk_cdiv_rcg2 *rcg = to_clk_cdiv_rcg2(hw);
> +	u32 cfg, hid_div, m = 0, n = 0, mode = 0, mask, rate, cdiv;
> +	int ret;
> +
> +	ret = regmap_read(rcg->clkr.regmap, rcg->cmd_rcgr + CFG_REG, &cfg);
> +	if (ret)
> +		return 0UL;
> +
> +	if (rcg->mnd_width) {
> +		mask = BIT(rcg->mnd_width) - 1;
> +		ret = regmap_read(rcg->clkr.regmap, rcg->cmd_rcgr + M_REG, &m);
> +		if (ret)
> +			return 0UL;
> +
> +		m &= mask;
> +		ret = regmap_read(rcg->clkr.regmap, rcg->cmd_rcgr + N_REG, &n);
> +		if (ret)
> +			return 0UL;
> +
> +		n =  ~n;
> +		n &= mask;
> +
> +		n += m;
> +		mode = cfg & CFG_MODE_MASK;
> +		mode >>= CFG_MODE_SHIFT;
> +	}
> +
> +	mask = BIT(rcg->hid_width) - 1;
> +	hid_div = cfg >> CFG_SRC_DIV_SHIFT;
> +	hid_div &= mask;
> +	rate = calc_rate(parent_rate, m, n, mode, hid_div);
> +
> +	ret = regmap_read(rcg->clkr.regmap, rcg->cdiv.offset, &cdiv);
> +	if (ret)
> +		return 0UL;
> +
> +	cdiv &= (rcg->cdiv.mask << rcg->cdiv.shift);
> +	cdiv =  (cdiv >> rcg->cdiv.shift);
> +	if (cdiv)
> +		rate *= cdiv + 1;
> +	return rate;
> +}
> +
> +static int _cdiv_rcg2_freq_tbl_determine_rate(struct clk_hw *hw,
> +		const struct freq_tbl *f,
> +		struct clk_rate_request *req)
> +{
> +	unsigned long clk_flags;
> +	struct clk_hw *p_hw;
> +	unsigned long rate = req->rate;
> +
> +	f = qcom_find_freq(f, rate);
> +	if (!f)
> +		return 0L;
> +
> +	clk_flags = __clk_get_flags(hw->clk);
> +	p_hw = clk_hw_get_parent_by_index(hw, f->src);
> +	if (clk_flags & CLK_SET_RATE_PARENT) {
> +		if (f->pre_div)
> +			rate *= f->pre_div;
> +		if (f->n) {
> +			u64 tmp = rate;
> +
> +			tmp = tmp * f->n;
> +			do_div(tmp, f->m);
> +			rate = tmp;
> +		}
> +	} else {
> +		rate =	clk_hw_get_rate(p_hw);
> +	}
> +
> +	req->best_parent_rate = rate;
> +	req->best_parent_hw = p_hw;
> +	req->rate = f->freq;
> +
> +	return 0;
> +}
> +
> +
> +static int clk_cdiv_rcg2_determine_rate(struct clk_hw *hw,
> +					struct clk_rate_request *req)
> +{
> +	struct clk_cdiv_rcg2 *rcg = to_clk_cdiv_rcg2(hw);
> +
> +	return _cdiv_rcg2_freq_tbl_determine_rate(hw, rcg->freq_tbl, req);
> +}
> +
> +static int clk_cdiv_rcg2_configure(struct clk_cdiv_rcg2 *rcg,
> +				const struct freq_tbl *f)
> +{
> +	u32 cfg = 0, mask;
> +	u32 i;
> +	int ret;
> +
> +	if (rcg->mnd_width && f->n) {
> +		mask = BIT(rcg->mnd_width) - 1;
> +		ret = regmap_update_bits(rcg->clkr.regmap,
> +				rcg->cmd_rcgr + M_REG, mask, f->m);
> +		if (ret)
> +			return ret;
> +
> +		ret = regmap_update_bits(rcg->clkr.regmap,
> +				rcg->cmd_rcgr + N_REG, mask, ~(f->n - f->m));
> +		if (ret)
> +			return ret;
> +
> +		ret = regmap_update_bits(rcg->clkr.regmap,
> +				rcg->cmd_rcgr + D_REG, mask, ~f->n);
> +		if (ret)
> +			return ret;
> +	}
> +
> +
> +	if (rcg->cdiv.mask && f->pre_div > 16) {
> +
> +		/* The division is handled by two dividers. Both of which can
> +		 * divide by a maximum value of 16. To achieve a division of
> +		 * 256 = 16 * 16, we use a divider of 16 in the RCGR and the
> +		 * other divider of 16 in the MISC Register.
> +		 */
> +		for (i = 2; i <= 16; i++) {
> +			if (f->pre_div % i == 0)
> +				cfg = i;
> +		}
> +
> +		if (f->pre_div/cfg > 16)
> +			return -EINVAL;
> +		mask = (rcg->cdiv.mask)<<rcg->cdiv.shift;
> +		ret = regmap_update_bits(rcg->clkr.regmap,
> +					rcg->cdiv.offset, mask,
> +				((cfg - 1) << rcg->cdiv.shift) & mask);
> +		if (ret)
> +			return ret;
> +		cfg = (2 * (f->pre_div / cfg)) - 1;
> +	} else {
> +		ret = regmap_write(rcg->clkr.regmap, rcg->cdiv.offset, 0x0);
> +		if (ret)
> +			return ret;
> +		cfg = ((2 * f->pre_div) - 1) << CFG_SRC_DIV_SHIFT;
> +	}
> +
> +	mask = BIT(rcg->hid_width) - 1;
> +	mask |= CFG_SRC_SEL_MASK | CFG_MODE_MASK;
> +	cfg |= rcg->parent_map[f->src].cfg << CFG_SRC_SEL_SHIFT;
> +	if (rcg->mnd_width && f->n)
> +		cfg |= CFG_MODE_DUAL_EDGE;
> +	ret = regmap_update_bits(rcg->clkr.regmap,
> +			rcg->cmd_rcgr + CFG_REG, mask, cfg);
> +	if (ret)
> +		return ret;
> +
> +	return cdiv_update_config(rcg);
> +}
> +
> +static int __clk_cdiv_rcg2_set_rate(struct clk_hw *hw, unsigned long rate)
> +{
> +	struct clk_cdiv_rcg2 *rcg = to_clk_cdiv_rcg2(hw);
> +	const struct freq_tbl *f;
> +
> +	f = qcom_find_freq(rcg->freq_tbl, rate);
> +	if (!f)
> +		return -EINVAL;
> +
> +	return clk_cdiv_rcg2_configure(rcg, f);
> +}
> +
> +static int clk_cdiv_rcg2_set_rate(struct clk_hw *hw, unsigned long rate,
> +			    unsigned long parent_rate)
> +{
> +	return __clk_cdiv_rcg2_set_rate(hw, rate);
> +}
> +
> +static int clk_cdiv_rcg2_set_rate_and_parent(struct clk_hw *hw,
> +		unsigned long rate, unsigned long parent_rate, u8 index)
> +{
> +	return __clk_cdiv_rcg2_set_rate(hw, rate);
> +}
> +
> +const struct clk_ops clk_cdiv_rcg2_ops = {
> +	.is_enabled			= clk_cdiv_rcg2_is_enabled,
> +	.get_parent			= clk_cdiv_rcg2_get_parent,
> +	.set_parent			= clk_cdiv_rcg2_set_parent,
> +	.recalc_rate			= clk_cdiv_rcg2_recalc_rate,
> +	.determine_rate			= clk_cdiv_rcg2_determine_rate,
> +	.set_rate			= clk_cdiv_rcg2_set_rate,
> +	.set_rate_and_parent		= clk_cdiv_rcg2_set_rate_and_parent,
> +};
> +EXPORT_SYMBOL_GPL(clk_cdiv_rcg2_ops);

There's a lot of copy paste going on here. Why? Is this a cdiv
in front of an RCG? Why not model that as two clks then?

> +
> +static int clk_muxr_is_enabled(struct clk_hw *hw)
> +{
> +	return 0;
> +}

Seems impossible.

> +
> +static u8 clk_muxr_get_parent(struct clk_hw *hw)
> +{
> +	struct clk_muxr_misc *rcg = to_clk_muxr_misc(hw);
> +	int num_parents = clk_hw_get_num_parents(hw);
> +	u32 cfg;
> +	int i, ret;
> +
> +	ret = regmap_read(rcg->clkr.regmap, rcg->muxr.offset, &cfg);
> +	if (ret)
> +		goto err;
> +
> +	cfg >>= rcg->muxr.shift;
> +	cfg &= rcg->muxr.mask;
> +
> +	for (i = 0; i < num_parents; i++)
> +		if (cfg == rcg->parent_map[i].cfg)
> +			return i;
> +
> +err:
> +	pr_debug("%s: Cannot find parent of %s clock, using default.\n",
> +			__func__, __clk_get_name(hw->clk));
> +	return 0;
> +}
> +
> +static int clk_muxr_set_parent(struct clk_hw *hw, u8 index)
> +{
> +	struct clk_muxr_misc *rcg = to_clk_muxr_misc(hw);
> +	int ret;
> +
> +	ret = regmap_update_bits(rcg->clkr.regmap, rcg->muxr.offset,
> +				 (rcg->muxr.mask<<rcg->muxr.shift),
> +				 rcg->parent_map[index].cfg << rcg->muxr.shift);
> +	if (ret)
> +		return ret;
> +
> +	return 0;
> +}
> +
> +static unsigned long
> +clk_muxr_recalc_rate(struct clk_hw *hw, unsigned long parent_rate)
> +{
> +	struct clk_muxr_misc *rcg = to_clk_muxr_misc(hw);
> +	u32 misc;
> +	int ret;
> +
> +	ret = regmap_read(rcg->clkr.regmap, rcg->misc.offset, &misc);
> +	if (ret)
> +		return 0UL;
> +
> +	misc &= rcg->misc.mask;
> +	misc >>= rcg->misc.shift;
> +
> +	return parent_rate * (misc + 1);
> +}
> +
> +static int clk_muxr_determine_rate(struct clk_hw *hw,
> +				   struct clk_rate_request *req)
> +{
> +	struct clk_muxr_misc *rcg = to_clk_muxr_misc(hw);
> +	const struct freq_tbl *f;
> +	unsigned long clk_flags;
> +	unsigned long rate = req->rate;
> +	struct clk_hw *p_hw;
> +
> +	f = qcom_find_freq(rcg->freq_tbl, rate);
> +	if (!f)
> +		return 0L;
> +
> +	clk_flags = __clk_get_flags(hw->clk);
> +	p_hw = clk_hw_get_parent_by_index(hw, f->src);
> +	if (clk_flags & CLK_SET_RATE_PARENT) {
> +		if (f->pre_div)
> +			rate *= f->pre_div;
> +	} else {
> +		rate =	clk_hw_get_rate(p_hw);
> +	}
> +
> +	req->best_parent_rate = rate;
> +	req->best_parent_hw = p_hw;
> +	req->rate = f->freq;
> +
> +	return 0;
> +}
> +
> +static int __clk_muxr_set_rate(struct clk_hw *hw, unsigned long rate)
> +{
> +	struct clk_muxr_misc *rcg = to_clk_muxr_misc(hw);
> +	const struct freq_tbl *f;
> +	int ret;
> +
> +	f = qcom_find_freq(rcg->freq_tbl, rate);
> +	if (!f)
> +		return -EINVAL;
> +
> +	ret = regmap_update_bits(rcg->clkr.regmap, rcg->muxr.offset,
> +				rcg->muxr.mask << rcg->muxr.shift,
> +				rcg->parent_map[f->src].cfg << rcg->muxr.shift);
> +	if (ret)
> +		return ret;
> +
> +	ret = regmap_update_bits(rcg->clkr.regmap, rcg->misc.offset,
> +				rcg->misc.mask << rcg->misc.shift,
> +				(f->pre_div - 1) << rcg->misc.shift);
> +	return ret;
> +}
> +
> +static int clk_muxr_set_rate(struct clk_hw *hw, unsigned long rate,
> +			    unsigned long parent_rate)
> +{
> +	return __clk_muxr_set_rate(hw, rate);
> +}
> +
> +static int clk_muxr_set_rate_and_parent(struct clk_hw *hw,
> +		unsigned long rate, unsigned long parent_rate, u8 index)
> +{
> +	return __clk_muxr_set_rate(hw, rate);
> +}
> +
> +const struct clk_ops clk_muxr_misc_ops = {
> +	.is_enabled	=	clk_muxr_is_enabled,
> +	.get_parent	=	clk_muxr_get_parent,
> +	.set_parent	=	clk_muxr_set_parent,
> +	.recalc_rate	=	clk_muxr_recalc_rate,
> +	.determine_rate	=	clk_muxr_determine_rate,
> +	.set_rate	=	clk_muxr_set_rate,
> +	.set_rate_and_parent	=	clk_muxr_set_rate_and_parent,
> +};
> +EXPORT_SYMBOL_GPL(clk_muxr_misc_ops);
> +
> +static int clk_cpu_rcg2_is_enabled(struct clk_hw *hw)
> +{
> +	struct clk_cdiv_rcg2 *rcg = to_clk_cdiv_rcg2(hw);
> +	u32 cmd;
> +	int ret;
> +
> +	ret = regmap_read(rcg->clkr.regmap, rcg->cmd_rcgr + CMD_REG, &cmd);
> +	if (ret)
> +		return 0;
> +
> +	return (cmd & CMD_ROOT_OFF) == 0;
> +
> +}
> +
> +static u8 clk_cpu_rcg2_get_parent(struct clk_hw *hw)
> +{
> +	struct clk_cdiv_rcg2 *rcg = to_clk_cdiv_rcg2(hw);
> +	int num_parents = clk_hw_get_num_parents(hw);
> +	u32 cfg;
> +	int i, ret;
> +
> +	ret = regmap_read(rcg->clkr.regmap, rcg->cmd_rcgr + CFG_REG, &cfg);
> +	if (ret)
> +		goto err;
> +
> +	cfg &= CFG_SRC_SEL_MASK;
> +	cfg >>= CFG_SRC_SEL_SHIFT;
> +
> +	for (i = 0; i < num_parents; i++)
> +		if (cfg == rcg->parent_map[i].cfg)
> +			return i;
> +
> +err:
> +	pr_debug("%s: Cannot find parent of %s clock, using default.\n",
> +			__func__, __clk_get_name(hw->clk));
> +	return 0;
> +}
> +
> +static int cpu_rcg2_update_config(struct clk_cdiv_rcg2 *rcg)
> +{
> +	int count, ret;
> +	u32 cmd;
> +	struct clk_hw *hw = &rcg->clkr.hw;
> +	const char *name = __clk_get_name(hw->clk);
> +
> +	ret = regmap_update_bits(rcg->clkr.regmap, rcg->cmd_rcgr + CMD_REG,
> +				 CMD_UPDATE, CMD_UPDATE);
> +	if (ret)
> +		return ret;
> +
> +	/* Wait for update to take effect */
> +	for (count = 500; count > 0; count--) {
> +		/* ignore regmap errors until we exhaust retry count.*/
> +		ret = regmap_read(rcg->clkr.regmap, rcg->cmd_rcgr + CMD_REG,
> +									&cmd);
> +		if (ret >= 0 && !(cmd & CMD_UPDATE))
> +			return 0;
> +
> +		udelay(1);
> +	}
> +
> +	WARN(1, "%s: rcg didn't update its configuration.", name);
> +	return ret ? ret : -ETIMEDOUT;
> +}
> +
> +static int clk_cpu_rcg2_set_parent(struct clk_hw *hw, u8 index)
> +{
> +	struct clk_cdiv_rcg2 *rcg = to_clk_cdiv_rcg2(hw);
> +	int ret;
> +
> +	ret = regmap_update_bits(rcg->clkr.regmap, rcg->cmd_rcgr + CFG_REG,
> +				 CFG_SRC_SEL_MASK,
> +				 rcg->parent_map[index].cfg <<
> +				 CFG_SRC_SEL_SHIFT);
> +	if (ret)
> +		return ret;
> +
> +	return cpu_rcg2_update_config(rcg);
> +}
> +
> +
> +/*
> + * These are used for looking up the actual divider ratios
> + * the divider used for DDR PLL Post divider is not linear,
> + * hence we need this look up table
> + */
> +static const unsigned char ddrpll_div[] = {

unsigned char... but they're numbers.

> +		12,
> +		13,
> +		14,
> +		15,
> +		16,
> +		17,
> +		18,
> +		19,
> +		20,
> +		21,
> +		22,
> +		24,
> +		26,
> +		28
> +};
> +
> +static unsigned long
> +clk_cpu_rcg2_recalc_rate(struct clk_hw *hw, unsigned long parent_rate)
> +{
> +	struct clk_cdiv_rcg2 *rcg = to_clk_cdiv_rcg2(hw);
> +	u32 cfg, hid_div, m = 0, n = 0, mode = 0, mask, cdiv;
> +	unsigned long rate;
> +	u32 src;
> +	int ret;
> +
> +	ret = regmap_read(rcg->clkr.regmap, rcg->cmd_rcgr + CFG_REG, &cfg);
> +	if (ret)
> +		return 0UL;
> +
> +	if (rcg->mnd_width) {
> +		mask = BIT(rcg->mnd_width) - 1;
> +		ret = regmap_read(rcg->clkr.regmap, rcg->cmd_rcgr + M_REG, &m);
> +		if (ret)
> +			return 0UL;
> +
> +		m &= mask;
> +
> +		ret = regmap_read(rcg->clkr.regmap, rcg->cmd_rcgr + N_REG, &n);
> +		if (ret)
> +			return 0UL;
> +
> +		n =  ~n;
> +		n &= mask;
> +
> +		n += m;
> +		mode = cfg & CFG_MODE_MASK;
> +		mode >>= CFG_MODE_SHIFT;
> +	}
> +
> +	mask = BIT(rcg->hid_width) - 1;
> +	hid_div = cfg >> CFG_SRC_DIV_SHIFT;
> +	hid_div &= mask;
> +	rate = calc_rate(parent_rate, m, n, mode, hid_div);
> +	src = (cfg >> CFG_SRC_SEL_SHIFT) & 0xf;
> +	if (src == 0x1) {

What does 1 mean?

> +		u64 tmp;
> +
> +		ret = regmap_read(rcg->clkr.regmap, rcg->cdiv.offset, &cdiv);
> +		if (ret)
> +			return 0UL;
> +
> +		cdiv &= (rcg->cdiv.mask << rcg->cdiv.shift);
> +		cdiv = cdiv >> rcg->cdiv.shift;
> +		tmp = rate;
> +		do_div(tmp, ddrpll_div[cdiv]);
> +		rate = tmp;
> +		rate *= 16;
> +		tmp = rate;
> +		do_div(tmp, 1000000);
> +		rate = tmp;
> +		rate = rate * 1000000;
> +	}
> +	return rate;
> +}
> +
> +static int _cpu_rcg2_freq_tbl_determine_rate(struct clk_hw *hw,
> +		const struct freq_tbl *f,
> +		struct clk_rate_request *req)
> +{
> +	unsigned long clk_flags;
> +	struct clk_hw *p_hw;
> +	unsigned long rate;
> +
> +	f = qcom_find_freq(f, req->rate);
> +	if (!f)
> +		return 0L;
> +
> +	clk_flags = __clk_get_flags(hw->clk);

Is this used?

> +	p_hw = clk_hw_get_parent_by_index(hw, f->src);
> +	rate = clk_hw_get_rate(p_hw);
> +
> +	req->best_parent_rate = rate;
> +	req->best_parent_hw = p_hw;
> +	req->rate = f->freq;
> +
> +	return 0;

Is this function any different from the one for rcg2?

> +}
> +
> +static int clk_cpu_rcg2_determine_rate(struct clk_hw *hw,
> +					struct clk_rate_request *req)
> +{
> +	struct clk_cdiv_rcg2 *rcg = to_clk_cdiv_rcg2(hw);
> +
> +	return _cpu_rcg2_freq_tbl_determine_rate(hw, rcg->freq_tbl, req);
> +}
> +
> +
> +static int clk_cpu_rcg2_configure(struct clk_cdiv_rcg2 *rcg,
> +						const struct freq_tbl *f)
> +{
> +	u32 cfg, mask;
> +	int ret;
> +
> +	if (rcg->mnd_width && f->n) {
> +		mask = BIT(rcg->mnd_width) - 1;
> +		ret = regmap_update_bits(rcg->clkr.regmap,
> +				rcg->cmd_rcgr + M_REG, mask, f->m);
> +		if (ret)
> +			return ret;
> +
> +		ret = regmap_update_bits(rcg->clkr.regmap,
> +				rcg->cmd_rcgr + N_REG, mask, ~(f->n - f->m));
> +		if (ret)
> +			return ret;
> +
> +		ret = regmap_update_bits(rcg->clkr.regmap,
> +				rcg->cmd_rcgr + D_REG, mask, ~f->n);
> +		if (ret)
> +			return ret;
> +	}
> +
> +	if ((rcg->parent_map[f->src].cfg == 0x01)) {

What is going on?

> +		mask = (BIT(rcg->hid_width) - 1);
> +		mask |= CFG_SRC_SEL_MASK | CFG_MODE_MASK;
> +		cfg = FEPLL_500_SRC << CFG_SRC_SEL_SHIFT;
> +		cfg |= (1 << CFG_SRC_DIV_SHIFT);
> +		ret = regmap_update_bits(rcg->clkr.regmap,
> +					rcg->cmd_rcgr + CFG_REG, mask, cfg);
> +		if (ret)
> +			return ret;
> +		cpu_rcg2_update_config(rcg);
> +		mask = (rcg->cdiv.mask)<<rcg->cdiv.shift;
> +		ret = regmap_update_bits(rcg->clkr.regmap,
> +					rcg->cdiv.offset, mask,
> +				(f->pre_div << rcg->cdiv.shift) & mask);
> +		udelay(1);
> +		mask = BIT(rcg->hid_width) - 1;
> +		mask |= CFG_SRC_SEL_MASK | CFG_MODE_MASK;
> +		cfg = 1 << CFG_SRC_DIV_SHIFT;
> +	} else {
> +		mask = BIT(rcg->hid_width) - 1;
> +		mask |= CFG_SRC_SEL_MASK | CFG_MODE_MASK;
> +		cfg = f->pre_div << CFG_SRC_DIV_SHIFT;
> +	}
> +
> +	cfg |= rcg->parent_map[f->src].cfg << CFG_SRC_SEL_SHIFT;
> +	if (rcg->mnd_width && f->n)
> +		cfg |= CFG_MODE_DUAL_EDGE;
> +	ret = regmap_update_bits(rcg->clkr.regmap,
> +					rcg->cmd_rcgr + CFG_REG, mask, cfg);
> +	if (ret)
> +		return ret;
> +
> +	return cpu_rcg2_update_config(rcg);
> +}
> +
> +static int __clk_cpu_rcg2_set_rate(struct clk_hw *hw, unsigned long rate)
> +{
> +	struct clk_cdiv_rcg2 *rcg = to_clk_cdiv_rcg2(hw);
> +	const struct freq_tbl *f;
> +
> +	f = qcom_find_freq(rcg->freq_tbl, rate);
> +	if (!f)
> +		return -EINVAL;
> +
> +	return clk_cpu_rcg2_configure(rcg, f);
> +}
> +
> +static int clk_cpu_rcg2_set_rate(struct clk_hw *hw, unsigned long rate,
> +			    unsigned long parent_rate)
> +{
> +	return __clk_cpu_rcg2_set_rate(hw, rate);
> +}
> +
> +static int clk_cpu_rcg2_set_rate_and_parent(struct clk_hw *hw,
> +		unsigned long rate, unsigned long parent_rate, u8 index)
> +{
> +	return __clk_cpu_rcg2_set_rate(hw, rate);
> +}
> +
> +const struct clk_ops clk_cpu_rcg2_ops = {
> +	.is_enabled	=	clk_cpu_rcg2_is_enabled,
> +	.get_parent	=	clk_cpu_rcg2_get_parent,
> +	.set_parent	=	clk_cpu_rcg2_set_parent,
> +	.recalc_rate	=	clk_cpu_rcg2_recalc_rate,
> +	.determine_rate	=	clk_cpu_rcg2_determine_rate,
> +	.set_rate	=	clk_cpu_rcg2_set_rate,
> +	.set_rate_and_parent	=	clk_cpu_rcg2_set_rate_and_parent,
> +};
> +EXPORT_SYMBOL_GPL(clk_cpu_rcg2_ops);

So a ton of stuff is duplicated. I don't even want to read it
because the same rcg code is copied a few times and then some
modifications are made and special cases are made in generic code
for SoC specific things.

> diff --git a/drivers/clk/qcom/common.c b/drivers/clk/qcom/common.c
> index f7c226a..0851122 100644
> --- a/drivers/clk/qcom/common.c
> +++ b/drivers/clk/qcom/common.c
> @@ -1,5 +1,5 @@
>  /*
> - * Copyright (c) 2013-2014, The Linux Foundation. All rights reserved.
> + * Copyright (c) 2013-2016, The Linux Foundation. All rights reserved.
>   *
>   * This software is licensed under the terms of the GNU General Public
>   * License version 2, as published by the Free Software Foundation, and
> @@ -269,4 +269,11 @@ int qcom_cc_probe(struct platform_device *pdev, const struct qcom_cc_desc *desc)
>  }
>  EXPORT_SYMBOL_GPL(qcom_cc_probe);
>  
> +void qcom_cc_remove(struct platform_device *pdev)
> +{
> +	of_clk_del_provider(pdev->dev.of_node);
> +	reset_controller_unregister(platform_get_drvdata(pdev));
> +}
> +EXPORT_SYMBOL_GPL(qcom_cc_remove);
> +

Nope.

>  MODULE_LICENSE("GPL v2");
> diff --git a/drivers/clk/qcom/common.h b/drivers/clk/qcom/common.h
> index ae9bdeb..ad66ae2 100644
> --- a/drivers/clk/qcom/common.h
> +++ b/drivers/clk/qcom/common.h
> @@ -1,5 +1,5 @@
>  /*
> - * Copyright (c) 2014, The Linux Foundation. All rights reserved.
> + * Copyright (c) 2014-2016 The Linux Foundation. All rights reserved.
>   *
>   * This software is licensed under the terms of the GNU General Public
>   * License version 2, as published by the Free Software Foundation, and
> @@ -48,5 +48,6 @@ extern int qcom_cc_really_probe(struct platform_device *pdev,
>  				struct regmap *regmap);
>  extern int qcom_cc_probe(struct platform_device *pdev,
>  			 const struct qcom_cc_desc *desc);
> +extern void qcom_cc_remove(struct platform_device *pdev);
>  

Nope.

>  #endif
> diff --git a/include/dt-bindings/clock/qcom,gcc-ipq4019.h b/include/dt-bindings/clock/qcom,gcc-ipq4019.h
> index 6240e5b..c75b98a 100644
> --- a/include/dt-bindings/clock/qcom,gcc-ipq4019.h
> +++ b/include/dt-bindings/clock/qcom,gcc-ipq4019.h
> @@ -1,4 +1,5 @@
> -/* Copyright (c) 2015 The Linux Foundation. All rights reserved.
> +/*
> + * Copyright (c) 2015-2016 The Linux Foundation. All rights reserved.
>   *
>   * Permission to use, copy, modify, and/or distribute this software for any
>   * purpose with or without fee is hereby granted, provided that the above
> @@ -154,5 +155,6 @@
>  #define GCC_QDSS_BCR					69
>  #define GCC_MPM_BCR					70
>  #define GCC_SPDM_BCR					71
> +#define AUDIO_BLK_ARES					GCC_AUDIO_BCR
>  
>  #endif
> diff --git a/include/dt-bindings/sound/ipq4019-audio.h b/include/dt-bindings/sound/ipq4019-audio.h
> new file mode 100644
> index 0000000..7bf8036
> --- /dev/null
> +++ b/include/dt-bindings/sound/ipq4019-audio.h

Why is this here?

-- 
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum,
a Linux Foundation Collaborative Project

^ permalink raw reply	[flat|nested] 24+ messages in thread

* [PATCH 2/4] qcom: ipq4019: ASoC clock driver support
@ 2016-08-16  1:00     ` Stephen Boyd
  0 siblings, 0 replies; 24+ messages in thread
From: Stephen Boyd @ 2016-08-16  1:00 UTC (permalink / raw)
  To: linux-arm-kernel

On 07/15, njaigane at codeaurora.org wrote:
> diff --git a/drivers/clk/qcom/Makefile b/drivers/clk/qcom/Makefile
> index 2a25f4e..aec6ab4 100644
> --- a/drivers/clk/qcom/Makefile
> +++ b/drivers/clk/qcom/Makefile
> @@ -4,6 +4,7 @@ clk-qcom-y += common.o
>  clk-qcom-y += clk-regmap.o
>  clk-qcom-y += clk-alpha-pll.o
>  clk-qcom-y += clk-pll.o
> +clk-qcom-y += clk-qcapll.o
>  clk-qcom-y += clk-rcg.o
>  clk-qcom-y += clk-rcg2.o
>  clk-qcom-y += clk-branch.o
> @@ -15,6 +16,7 @@ clk-qcom-$(CONFIG_QCOM_GDSC) += gdsc.o
>  obj-$(CONFIG_APQ_GCC_8084) += gcc-apq8084.o
>  obj-$(CONFIG_APQ_MMCC_8084) += mmcc-apq8084.o
>  obj-$(CONFIG_IPQ_GCC_4019) += gcc-ipq4019.o
> +obj-$(CONFIG_IPQ_ADCC_4019) += adcc-ipq4019.o

Alphabetize on config please.

>  obj-$(CONFIG_IPQ_GCC_806X) += gcc-ipq806x.o
>  obj-$(CONFIG_IPQ_LCC_806X) += lcc-ipq806x.o
>  obj-$(CONFIG_MSM_GCC_8660) += gcc-msm8660.o
> diff --git a/drivers/clk/qcom/adcc-ipq4019.c b/drivers/clk/qcom/adcc-ipq4019.c
> new file mode 100644
> index 0000000..0ed90e1
> --- /dev/null
> +++ b/drivers/clk/qcom/adcc-ipq4019.c
> @@ -0,0 +1,700 @@
> +/*
> + * Copyright (c) 2014 - 2016 The Linux Foundation. All rights reserved.
> + *
> + * This software is licensed under the terms of the GNU General Public
> + * License version 2, as published by the Free Software Foundation, and
> + * may be copied, distributed, and modified under those terms.
> + *
> + * 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 <linux/kernel.h>
> +#include <linux/err.h>
> +#include <linux/platform_device.h>
> +#include <linux/module.h>
> +#include <linux/of.h>
> +#include <linux/of_device.h>
> +#include <linux/clk-provider.h>
> +#include <linux/delay.h>
> +#include <linux/regmap.h>
> +#include <linux/reset-controller.h>
> +
> +#include <dt-bindings/clock/qca,adcc-ipq4019.h>
> +
> +#include "common.h"
> +#include "clk-regmap.h"
> +#include "clk-rcg.h"
> +#include "clk-qcapll.h"
> +#include "clk-branch.h"
> +#include "reset.h"
> +
> +#define AUDIO_PLL_CONFIG_REG				0x00000
> +#define AUDIO_PLL_MODULATION_REG			0x00004
> +#define AUDIO_PLL_MOD_STEP_REG				0x00008
> +#define CURRENT_AUDIO_PLL_MODULATION_REG		0x0000c
> +#define AUDIO_PLL_CONFIG1_REG				0x00010
> +#define AUDIO_ATB_SETTING_REG				0x00014
> +#define AUDIO_RXB_CFG_MUXR_REG				0x000cc
> +#define AUDIO_RXB_MISC_REG				0x000d0
> +#define AUDIO_RXB_CBCR_REG				0x000D4
> +#define AUDIO_RXM_CMD_RCGR_REG				0x000e8
> +#define AUDIO_RXM_CFG_RCGR_REG				0x000ec
> +#define AUDIO_RXM_MISC_REG				0x000f0
> +#define AUDIO_RXM_CBCR_REG				0x000F4
> +#define AUDIO_TXB_CFG_MUXR_REG				0x0010c
> +#define AUDIO_TXB_MISC_REG				0x00110
> +#define AUDIO_TXB_CBCR_REG				0x00114
> +#define AUDIO_SPDIF_MISC_REG				0x00118
> +#define AUDIO_SPDIF_CBCR_REG				0x0011c
> +#define AUDIO_SPDIFDIV2_MISC_REG			0x00120
> +#define AUDIO_SPDIFDIV2_CBCR_REG			0x00124
> +#define AUDIO_TXM_CMD_RCGR_REG				0x00128
> +#define AUDIO_TXM_CFG_RCGR_REG				0x0012c
> +#define AUDIO_TXM_MISC_REG				0x00130
> +#define AUDIO_TXM_CBCR_REG				0x00134
> +#define AUDIO_SAMPLE_CBCR_REG				0x00154
> +#define AUDIO_PCM_CMD_RCGR_REG				0x00168
> +#define AUDIO_PCM_CFG_RCGR_REG				0x0016C
> +#define AUDIO_PCM_MISC_REG				0x00170
> +#define AUDIO_PCM_CBCR_REG				0x00174
> +#define AUDIO_XO_CBCR_REG				0x00194
> +#define AUDIO_SPDIFINFAST_CMD_RCGR_REG			0x001A8
> +#define AUDIO_SPDIFINFAST_CFG_RCGR_REG			0x001AC
> +#define AUDIO_SPDIFINFAST_CBCR_REG			0x001B4
> +#define AUDIO_AHB_CBCR_REG				0x001c8
> +#define AUDIO_AHB_I2S0_CBCR_REG				0x001cc
> +#define AUDIO_AHB_I2S3_CBCR_REG				0x001d0
> +#define AUDIO_AHB_MBOX0_CBCR_REG			0x001D4
> +#define AUDIO_AHB_MBOX3_CBCR_REG			0x001d8

Lowercase hex only please. Also, just put the registers in the
structures directly. The defines are just a waste of lines.

> +
> +#define F(f, s, h, m, n) { (f), (s), (2 * (h) - 1), (m), (n) }

Is this used?

> +#define P_XO 0
> +#define ADSS_PLL 1
> +#define MCLK_MCLK_IN 2
> +#define BCLK_BCLK_IN 2
> +#define BCLK_MCLK_IN 3

Please preface all the sources with P_ so we know they're
"parents".

> +
> +static struct parent_map adcc_xo_adpll_padmclk_map[] = {
> +	{  P_XO, 0 },
> +	{  ADSS_PLL, 1 },
> +	{  MCLK_MCLK_IN, 2 },
> +};
> +
> +static const char * const adcc_xo_adpll_padmclk[] = {
> +	"xo",
> +	"adss_pll",
> +	"padmclk",
> +};
> +
> +static struct parent_map adcc_xo_adpll_padbclk_padmclk_map[] = {
> +	{  P_XO, 0 },
> +	{  ADSS_PLL, 1 },
> +	{  MCLK_MCLK_IN, 2 },
> +	{  BCLK_MCLK_IN, 3 },
> +};
> +
> +static const char * const adcc_xo_adpll_padbclk_padmclk[] = {
> +	"xo",
> +	"adss_pll",
> +	"padbclk",
> +	"padmclk",
> +};
> +
> +static struct parent_map adcc_xo_adpll_map[] = {
> +	{  P_XO, 0 },
> +	{  ADSS_PLL, 1 },
> +};
> +
> +static const char * const adcc_xo_adpll[] = {
> +	"xo",
> +	"adss_pll",
> +};
> +
> +static const struct pll_freq_tbl adss_freq_tbl[] = {
> +	{163840000, 1, 5, 40, 0x3D708},
> +	{180633600, 1, 5, 45, 0xA234},
> +	{184320000, 1, 5, 46, 0x51E9},
> +	{196608000, 1, 5, 49, 0x9bA6},
> +	{197568000, 1, 5, 49, 0x19168},

Spaces around braces please.

	{ 197568000, 1, 5, 49, 0x19168 },

> +	{}
> +};
> +
> +static struct clk_qcapll adss_pll_src = {
> +	.config_reg		= AUDIO_PLL_CONFIG_REG,
> +	.mod_reg		= AUDIO_PLL_MODULATION_REG,
> +	.modstep_reg		= AUDIO_PLL_MOD_STEP_REG,
> +	.current_mod_pll_reg	= CURRENT_AUDIO_PLL_MODULATION_REG,
> +	.config1_reg		= AUDIO_PLL_CONFIG1_REG,
> +	.freq_tbl = adss_freq_tbl,
> +	.clkr.hw.init = &(struct clk_init_data){
> +		.name = "adss_pll",
> +		.parent_names = (const char *[]){ "xo" },
> +		.num_parents = 1,
> +		.ops = &clk_qcapll_ops,
> +		.flags = CLK_IGNORE_UNUSED,
> +	},
> +};
> +
> +static const struct freq_tbl ftbl_m_clk[] = {
> +	{255, MCLK_MCLK_IN, 1, 0, 0},
> +	{2048000, ADSS_PLL, 96, 0, 0},
> +	{2822400, ADSS_PLL, 64, 0, 0},
> +	{4096000, ADSS_PLL, 48, 0, 0},
> +	{5644800, ADSS_PLL, 32, 0, 0},
> +	{6144000, ADSS_PLL, 32, 0, 0},
> +	{8192000, ADSS_PLL, 24, 0, 0},
> +	{11289600, ADSS_PLL, 16, 0, 0},
> +	{12288000, ADSS_PLL, 16, 0, 0},
> +	{14112000, ADSS_PLL, 14, 0, 0},
> +	{15360000, ADSS_PLL, 12, 0, 0},
> +	{16384000, ADSS_PLL, 12, 0, 0},
> +	{20480000, ADSS_PLL, 8, 0, 0},
> +	{22579200, ADSS_PLL, 8, 0, 0},
> +	{24576000, ADSS_PLL, 8, 0, 0},
> +	{30720000, ADSS_PLL, 6, 0, 0},
> +	{ }
> +};
> +
> +static struct clk_cdiv_rcg2 rxm_clk_src = {
> +	.cdiv.offset = AUDIO_RXM_MISC_REG,
> +	.cdiv.shift = 4,
> +	.cdiv.mask = 0xf,
> +	.cmd_rcgr = AUDIO_RXM_CMD_RCGR_REG,
> +	.hid_width = 5,
> +	.parent_map = adcc_xo_adpll_padmclk_map,
> +	.freq_tbl = ftbl_m_clk,
> +	.clkr.hw.init = &(struct clk_init_data){
> +		.name = "rxm_clk_src",
> +		.parent_names = adcc_xo_adpll_padmclk,
> +		.num_parents = 3,
> +		.ops = &clk_cdiv_rcg2_ops,
> +		.flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED,
> +	},
> +};
> +
> +static struct clk_branch adcc_rxm_clk_src = {
> +	.halt_reg = AUDIO_RXM_CBCR_REG,
> +	.clkr = {
> +		.enable_reg = AUDIO_RXM_CBCR_REG,
> +		.enable_mask = BIT(0),
> +		.hw.init = &(struct clk_init_data){
> +			.name = "adcc_rxm_clk_src",
> +			.parent_names = (const char *[]){"rxm_clk_src"},
> +			.num_parents = 1,
> +			.ops = &clk_branch2_ops,
> +			.flags = CLK_SET_RATE_PARENT,
> +		},
> +	},
> +};
> +
> +static struct clk_cdiv_rcg2 txm_clk_src = {
> +	.cdiv.offset = AUDIO_TXM_MISC_REG,
> +	.cdiv.shift = 4,
> +	.cdiv.mask = 0xf,
> +	.cmd_rcgr = AUDIO_TXM_CMD_RCGR_REG,
> +	.hid_width = 5,
> +	.parent_map = adcc_xo_adpll_padmclk_map,
> +	.freq_tbl = ftbl_m_clk,
> +	.clkr.hw.init = &(struct clk_init_data){
> +		.name = "txm_clk_src",
> +		.parent_names = adcc_xo_adpll_padmclk,
> +		.num_parents = 3,
> +		.ops = &clk_cdiv_rcg2_ops,
> +		.flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED,
> +	},
> +};
> +
> +static struct clk_branch adcc_txm_clk_src = {
> +	.halt_reg = AUDIO_TXM_CBCR_REG,
> +	.clkr = {
> +		.enable_reg = AUDIO_TXM_CBCR_REG,
> +		.enable_mask = BIT(0),
> +		.hw.init = &(struct clk_init_data){
> +			.name = "adcc_txm_clk_src",
> +			.parent_names = (const char *[]){
> +				"txm_clk_src",
> +			},
> +			.num_parents = 1,
> +			.ops = &clk_branch2_ops,
> +			.flags = CLK_SET_RATE_PARENT,
> +		},
> +	},
> +};
> +
> +static const struct freq_tbl ftbl_bclk_clk[] = {
> +	{254, BCLK_BCLK_IN, 1, 0, 0},
> +	{255, BCLK_MCLK_IN, 1, 0, 0},
> +	{512000, ADSS_PLL, 384, 0, 0},
> +	{705600, ADSS_PLL, 256, 0, 0},
> +	{1024000, ADSS_PLL, 192, 0, 0},
> +	{1411200, ADSS_PLL, 128, 0, 0},
> +	{1536000, ADSS_PLL, 128, 0, 0},
> +	{2048000, ADSS_PLL, 96, 0, 0},
> +	{2822400, ADSS_PLL, 64, 0, 0},
> +	{3072000, ADSS_PLL, 64, 0, 0},
> +	{4096000, ADSS_PLL, 48, 0, 0},
> +	{5120000, ADSS_PLL, 32, 0, 0},
> +	{5644800, ADSS_PLL, 32, 0, 0},
> +	{6144000, ADSS_PLL, 32, 0, 0},
> +	{7056000, ADSS_PLL, 24, 0, 0},
> +	{7680000, ADSS_PLL, 24, 0, 0},
> +	{8192000, ADSS_PLL, 24, 0, 0},
> +	{10240000, ADSS_PLL, 16, 0, 0},
> +	{11289600, ADSS_PLL, 16, 0, 0},
> +	{12288000, ADSS_PLL, 16, 0, 0},
> +	{14112000, ADSS_PLL, 16, 0, 0},
> +	{15360000, ADSS_PLL, 12, 0, 0},
> +	{16384000, ADSS_PLL, 12, 0, 0},
> +	{22579200, ADSS_PLL, 8, 0, 0},
> +	{24576000, ADSS_PLL,  8, 0, 0},
> +	{30720000, ADSS_PLL,  6, 0, 0},
> +	{ }
> +};
> +
> +static struct clk_muxr_misc txb_clk_src = {
> +	.misc.offset = AUDIO_TXB_MISC_REG,
> +	.misc.shift = 1,
> +	.misc.mask = 0x1FF,
> +	.muxr.offset = AUDIO_TXB_CFG_MUXR_REG,
> +	.muxr.shift = 8,
> +	.muxr.mask = 0x7,
> +	.parent_map = adcc_xo_adpll_padbclk_padmclk_map,
> +	.freq_tbl = ftbl_bclk_clk,
> +	.clkr.hw.init = &(struct clk_init_data){
> +		.name = "txb_clk_src",
> +		.parent_names = adcc_xo_adpll_padbclk_padmclk,
> +		.num_parents = 4,
> +		.ops = &clk_muxr_misc_ops,
> +		.flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED,
> +	},
> +};
> +
> +static struct clk_branch adcc_txb_clk_src = {
> +	.halt_reg = AUDIO_TXB_CBCR_REG,
> +	.clkr = {
> +		.enable_reg = AUDIO_TXB_CBCR_REG,
> +		.enable_mask = BIT(0),
> +		.hw.init = &(struct clk_init_data){
> +			.name = "adcc_txb_clk_src",
> +			.parent_names = (const char *[]){
> +				"txb_clk_src",
> +			},
> +			.num_parents = 1,
> +			.ops = &clk_branch2_ops,
> +			.flags = CLK_SET_RATE_PARENT,
> +		},
> +	},
> +};
> +
> +static struct clk_muxr_misc rxb_clk_src = {
> +	.misc.offset = AUDIO_RXB_MISC_REG,
> +	.misc.shift = 1,
> +	.misc.mask = 0x1FF,
> +	.muxr.offset = AUDIO_RXB_CFG_MUXR_REG,
> +	.muxr.shift = 8,
> +	.muxr.mask = 0x7,
> +	.parent_map = adcc_xo_adpll_padbclk_padmclk_map,
> +	.freq_tbl = ftbl_bclk_clk,
> +	.clkr.hw.init = &(struct clk_init_data){
> +		.name = "rxb_clk_src",
> +		.parent_names = adcc_xo_adpll_padbclk_padmclk,
> +		.num_parents = 4,
> +		.ops = &clk_muxr_misc_ops,
> +		.flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED,
> +	},
> +};
> +
> +
> +static struct clk_branch adcc_rxb_clk_src = {
> +	.halt_reg = AUDIO_RXB_CBCR_REG,
> +	.clkr = {
> +		.enable_reg = AUDIO_RXB_CBCR_REG,
> +		.enable_mask = BIT(0),
> +		.hw.init = &(struct clk_init_data){
> +			.name = "adcc_rxb_clk_src",
> +			.parent_names = (const char *[]){
> +				"rxb_clk_src",
> +			},
> +			.num_parents = 1,
> +			.ops = &clk_branch2_ops,
> +			.flags = CLK_SET_RATE_PARENT,
> +		},
> +	},
> +};
> +
> +
> +
> +static const struct freq_tbl ftbl_adcc_pcm_clk[] = {
> +	{8192000, ADSS_PLL, 24, 0, 0},
> +	{16384000, ADSS_PLL, 12, 0, 0},
> +	{ }
> +};
> +
> +static struct clk_cdiv_rcg2 pcm_clk_src = {
> +	.cdiv.offset = AUDIO_PCM_MISC_REG,
> +	.cdiv.shift = 4,
> +	.cdiv.mask = 0xf,
> +	.cmd_rcgr = AUDIO_PCM_CMD_RCGR_REG,
> +	.hid_width = 5,
> +	.parent_map = adcc_xo_adpll_map,
> +	.freq_tbl = ftbl_adcc_pcm_clk,
> +	.clkr.hw.init = &(struct clk_init_data){
> +		.name = "pcm_clk_src",
> +		.parent_names = adcc_xo_adpll,
> +		.num_parents = 2,
> +		.ops = &clk_cdiv_rcg2_ops,
> +		.flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED,
> +	},
> +};
> +
> +
> +
> +static struct clk_branch adcc_pcm_clk_src = {
> +	.halt_reg = AUDIO_PCM_CBCR_REG,
> +	.clkr = {
> +		.enable_reg = AUDIO_PCM_CBCR_REG,
> +		.enable_mask = BIT(0),
> +		.hw.init = &(struct clk_init_data){
> +			.name = "adcc_pcm_clk_src",
> +			.parent_names = (const char *[]){
> +				"pcm_clk_src",
> +			},
> +			.num_parents = 1,
> +			.ops = &clk_branch2_ops,
> +			.flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED,
> +		},
> +	},
> +};
> +
> +
> +

Remove all but one newline here.

> +static const struct freq_tbl ftbl_adcc_spdifinfast_clk[] = {
> +	F(49152000, ADSS_PLL, 0x04, 0, 0),
> +	{ }
> +};
> +
> +static struct clk_rcg2 spdifinfast_src = {
> +	.cmd_rcgr = AUDIO_SPDIFINFAST_CMD_RCGR_REG,
> +	.hid_width = 5,
> +	.parent_map = adcc_xo_adpll_map,
> +	.freq_tbl = ftbl_adcc_spdifinfast_clk,
> +	.clkr.hw.init = &(struct clk_init_data){
> +		.name = "spdifinfast_src",
> +		.parent_names = adcc_xo_adpll,
> +		.num_parents = 2,
> +		.ops = &clk_rcg2_ops,
> +		.flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED,
> +	},
> +};
> +
> +static struct clk_branch adcc_spdifinfast_src = {
> +	.halt_reg = AUDIO_SPDIFINFAST_CBCR_REG,
> +	.clkr = {
> +		.enable_reg = AUDIO_SPDIFINFAST_CBCR_REG,
> +		.enable_mask = BIT(0),
> +		.hw.init = &(struct clk_init_data){
> +			.name = "adcc_spdifinfast_src",
> +			.parent_names = (const char *[]){
> +				"spdifinfast_src",
> +			},
> +			.num_parents = 1,
> +			.ops = &clk_branch2_ops,
> +			.flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED,
> +		},
> +	},
> +};
> +
> +static struct clk_muxr_misc spdif_src = {
> +	.misc.offset = AUDIO_SPDIF_MISC_REG,
> +	.misc.shift = 1,
> +	.misc.mask = 0x1FF,
> +	.muxr.offset = AUDIO_TXB_CFG_MUXR_REG,
> +	.muxr.shift = 8,
> +	.muxr.mask = 0x7,
> +	.parent_map = adcc_xo_adpll_padbclk_padmclk_map,
> +	.freq_tbl = ftbl_m_clk,
> +	.clkr.hw.init = &(struct clk_init_data){
> +		.name = "spdif_src",
> +		.parent_names = adcc_xo_adpll_padbclk_padmclk,
> +		.num_parents = 4,
> +		.ops = &clk_muxr_misc_ops,
> +		.flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED,
> +	},
> +};
> +
> +static struct clk_branch adcc_spdif_src = {
> +	.halt_reg = AUDIO_SPDIF_CBCR_REG,
> +	.clkr = {
> +		.enable_reg = AUDIO_SPDIF_CBCR_REG,
> +		.enable_mask = BIT(0),
> +		.hw.init = &(struct clk_init_data){
> +			.name = "adcc_spdif_src",
> +			.parent_names = (const char *[]){
> +				"spdif_src",
> +			},
> +			.num_parents = 1,
> +			.ops = &clk_branch2_ops,
> +			.flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED,
> +		},
> +	},
> +};
> +
> +static struct clk_muxr_misc spdifdiv2_src = {
> +	.misc.offset = AUDIO_SPDIFDIV2_MISC_REG,
> +	.misc.shift = 1,
> +	.misc.mask = 0x1FF,
> +	.parent_map = adcc_xo_adpll_padbclk_padmclk_map,
> +	.muxr.offset = AUDIO_TXB_CFG_MUXR_REG,
> +	.muxr.shift = 8,
> +	.muxr.mask = 0x7,
> +	.freq_tbl = ftbl_bclk_clk,
> +	.clkr.hw.init = &(struct clk_init_data){
> +		.name = "spdifdiv2_src",
> +		.parent_names = adcc_xo_adpll_padbclk_padmclk,
> +		.num_parents = 4,
> +		.ops = &clk_muxr_misc_ops,
> +		.flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED,
> +	},
> +};
> +
> +static struct clk_branch adcc_spdifdiv2_src = {
> +	.halt_reg = AUDIO_SPDIFDIV2_CBCR_REG,
> +	.clkr = {
> +		.enable_reg = AUDIO_SPDIFDIV2_CBCR_REG,
> +		.enable_mask = BIT(0),
> +		.hw.init = &(struct clk_init_data){
> +			.name = "adcc_spdifdiv2_src",
> +			.parent_names = (const char *[]){
> +				"spdifdiv2_src",
> +			},
> +			.num_parents = 1,
> +			.ops = &clk_branch2_ops,
> +			.flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED,
> +		},
> +	},
> +};
> +
> +static struct clk_branch adcc_sample_src = {
> +	.halt_reg = AUDIO_SAMPLE_CBCR_REG,
> +	.clkr = {
> +		.enable_reg = AUDIO_SAMPLE_CBCR_REG,
> +		.enable_mask = BIT(0),
> +		.hw.init = &(struct clk_init_data){
> +			.name = "adcc_sample_src",
> +			.parent_names = (const char *[]){
> +				"pcnoc_clk_src",
> +			},
> +			.num_parents = 1,
> +			.ops = &clk_branch2_ops,
> +			.flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED,
> +		},
> +	},
> +};
> +
> +static struct clk_branch adcc_xo_src = {
> +	.halt_reg = AUDIO_XO_CBCR_REG,
> +	.clkr = {
> +		.enable_reg = AUDIO_XO_CBCR_REG,
> +		.enable_mask = BIT(0),
> +		.hw.init = &(struct clk_init_data){
> +			.name = "adcc_xo_src",
> +			.parent_names = (const char *[]){
> +				"XO",
> +			},
> +			.num_parents = 1,
> +			.ops = &clk_branch2_ops,
> +			.flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED,
> +		},
> +	},
> +};
> +
> +
> +static struct clk_branch adcc_ahb_src = {
> +	.halt_reg = AUDIO_AHB_CBCR_REG,
> +	.clkr = {
> +		.enable_reg = AUDIO_AHB_CBCR_REG,
> +		.enable_mask = BIT(0),
> +		.hw.init = &(struct clk_init_data){
> +			.name = "adcc_audio_ahb_src",
> +			.parent_names = (const char *[]){
> +				"pcnoc_clk_src",
> +			},
> +			.num_parents = 1,
> +			.ops = &clk_branch2_ops,
> +			.flags = CLK_IGNORE_UNUSED,
> +		},
> +	},
> +};
> +
> +static struct clk_branch adcc_ahb_i2s0_src = {
> +	.halt_reg = AUDIO_AHB_I2S0_CBCR_REG,
> +	.clkr = {
> +		.enable_reg = AUDIO_AHB_I2S0_CBCR_REG,
> +		.enable_mask = BIT(0),
> +		.hw.init = &(struct clk_init_data){
> +			.name = "adcc_audio_ahb_i2s0",
> +			.parent_names = (const char *[]){
> +				"pcnoc_clk_src",
> +			},
> +			.num_parents = 1,
> +			.ops = &clk_branch2_ops,
> +			.flags = CLK_IGNORE_UNUSED,
> +		},
> +	},
> +};
> +
> +static struct clk_branch adcc_ahb_i2s3_src = {
> +	.halt_reg = AUDIO_AHB_I2S3_CBCR_REG,
> +	.clkr = {
> +		.enable_reg = AUDIO_AHB_I2S3_CBCR_REG,
> +		.enable_mask = BIT(0),
> +		.hw.init = &(struct clk_init_data){
> +			.name = "adcc_audio_ahb_i2s3",
> +			.parent_names = (const char *[]){
> +				"pcnoc_clk_src",
> +			},
> +			.num_parents = 1,
> +			.ops = &clk_branch2_ops,
> +			.flags = CLK_IGNORE_UNUSED,
> +		},
> +	},
> +};
> +
> +static struct clk_branch adcc_ahb_mbox0_src = {
> +	.halt_reg = AUDIO_AHB_MBOX0_CBCR_REG,
> +	.clkr = {
> +		.enable_reg = AUDIO_AHB_MBOX0_CBCR_REG,
> +		.enable_mask = BIT(0),
> +		.hw.init = &(struct clk_init_data){
> +			.name = "adcc_audio_mbox0_src",
> +			.parent_names = (const char *[]){
> +				"pcnoc_clk_src",
> +			},
> +			.num_parents = 1,
> +			.ops = &clk_branch2_ops,
> +			.flags = CLK_IGNORE_UNUSED,
> +		},
> +	},
> +};
> +
> +static struct clk_branch adcc_ahb_mbox3_src = {
> +	.halt_reg = AUDIO_AHB_MBOX3_CBCR_REG,
> +	.clkr = {
> +		.enable_reg = AUDIO_AHB_MBOX3_CBCR_REG,
> +		.enable_mask = BIT(0),
> +		.hw.init = &(struct clk_init_data){
> +			.name = "adcc_ahb_mbox3_src",
> +			.parent_names = (const char *[]){
> +				"pcnoc_clk_src",
> +			},
> +			.num_parents = 1,
> +			.ops = &clk_branch2_ops,
> +			.flags = CLK_IGNORE_UNUSED,
> +		},
> +	},
> +};
> +
> +static struct clk_regmap *adcc_ipq4019_clocks[] = {
> +	[ADSS_PLL_SRC]				= &adss_pll_src.clkr,
> +	[RXM_CLK_SRC]				= &rxm_clk_src.clkr,
> +	[ADCC_RXM_CLK_SRC]			= &adcc_rxm_clk_src.clkr,
> +	[TXM_CLK_SRC]				= &txm_clk_src.clkr,
> +	[ADCC_TXM_CLK_SRC]			= &adcc_txm_clk_src.clkr,
> +	[TXB_CLK_SRC]				= &txb_clk_src.clkr,
> +	[ADCC_TXB_CLK_SRC]			= &adcc_txb_clk_src.clkr,
> +	[RXB_CLK_SRC]				= &rxb_clk_src.clkr,
> +	[ADCC_RXB_CLK_SRC]			= &adcc_rxb_clk_src.clkr,
> +	[PCM_CLK_SRC]				= &pcm_clk_src.clkr,
> +	[ADCC_PCM_CLK_SRC]			= &adcc_pcm_clk_src.clkr,
> +	[AUDIO_SPDIFINFAST_SRC]			= &spdifinfast_src.clkr,
> +	[ADCC_AUDIO_SPDIFINFAST_SRC]		= &adcc_spdifinfast_src.clkr,
> +	[ADCC_AUDIO_AHB_SRC]			= &adcc_ahb_src.clkr,
> +	[ADCC_AHB_I2S0]				= &adcc_ahb_i2s0_src.clkr,
> +	[ADCC_AHB_I2S3]				= &adcc_ahb_i2s3_src.clkr,
> +	[ADCC_AHB_MBOX0_SRC]			= &adcc_ahb_mbox0_src.clkr,
> +	[ADCC_AHB_MBOX3_SRC]			= &adcc_ahb_mbox3_src.clkr,
> +	[SPDIF_SRC]				= &spdif_src.clkr,
> +	[ADCC_SPDIF_SRC]			= &adcc_spdif_src.clkr,
> +	[SPDIFDIV2_SRC]				= &spdifdiv2_src.clkr,
> +	[ADCC_SPDIFDIV2_SRC]			= &adcc_spdifdiv2_src.clkr,
> +	[ADCC_SAMPLE_SRC]			= &adcc_sample_src.clkr,
> +	[ADCC_XO_SRC]				= &adcc_xo_src.clkr,
> +};
> +
> +static const struct qcom_reset_map adcc_ipq4019_resets[] = {
> +};

Are there any resets? If not, please update the common.c file to
handle that case and not register a reset provider.

> +
> +struct cdiv_fixed {

Is this structure used?

> +	char	*name;
> +	char	*pname;
> +	u32	flags;
> +	u32	mult;
> +	u32	div;
> +};
> +
> +static const struct regmap_config adcc_ipq4019_regmap_config = {
> +	.reg_bits	= 32,
> +	.reg_stride	= 4,
> +	.val_bits	= 32,
> +	.max_register	= 0x2ff,
> +	.fast_io	= true,
> +};
> +
> +static const struct qcom_cc_desc adcc_ipq4019_desc = {
> +	.config = &adcc_ipq4019_regmap_config,
> +	.clks = adcc_ipq4019_clocks,
> +	.num_clks = ARRAY_SIZE(adcc_ipq4019_clocks),
> +	.resets = adcc_ipq4019_resets,
> +	.num_resets = ARRAY_SIZE(adcc_ipq4019_resets),
> +};
> +
> +static const struct of_device_id adcc_ipq4019_match_table[] = {
> +	{ .compatible = "qcom,adcc-ipq4019" },
> +	{ }
> +};
> +MODULE_DEVICE_TABLE(of, gcc_ipq4019_match_table);
> +
> +static int adcc_ipq4019_probe(struct platform_device *pdev)
> +{
> +	struct device *dev = &pdev->dev;
> +	struct regmap *regmap;
> +
> +	/* High speed external clock */
> +	clk_register_fixed_rate(dev, "xo", NULL, CLK_IS_ROOT, 48000000);

This should come from the board, don't register it here.

> +
> +	/* External padbclk & padmclk clock.These [254 & 255] frequencies are

Multiline comments put the "/*" on a separate line from the rest
of the text.

> +	 * taken as tokens only to support the INPUTS from PADS.
> +	 * Reference: ADSS_HPG/HDD document for IPQ4019
> +	 */
> +	clk_register_fixed_rate(dev, "padbclk", NULL, CLK_IS_ROOT, 254);
> +	clk_register_fixed_rate(dev, "padmclk", NULL, CLK_IS_ROOT, 255);

This looks like a hack. What's going on?

> +
> +	regmap = qcom_cc_map(pdev, &adcc_ipq4019_desc);
> +	if (IS_ERR(regmap))
> +		return PTR_ERR(regmap);
> +
> +	return qcom_cc_really_probe(pdev, &adcc_ipq4019_desc, regmap);

You don't have to call qcom_cc_map() and qcom_cc_really_probe()
if you don't need to do anything with the mapping in this probe.
Just call qcom_cc_probe().

> +}
> +
> +static int adcc_ipq4019_remove(struct platform_device *pdev)
> +{
> +	qcom_cc_remove(pdev);
> +	return 0;

This is useless to call now, and in fact it's been deleted.

> +}

> diff --git a/drivers/clk/qcom/clk-qcapll.c b/drivers/clk/qcom/clk-qcapll.c
> new file mode 100644
> index 0000000..fac45c8
> --- /dev/null
> +++ b/drivers/clk/qcom/clk-qcapll.c
> @@ -0,0 +1,197 @@
> +/*
> + * Copyright (c) 2013, 2015-2016 The Linux Foundation. All rights reserved.
> + *
> + * This software is licensed under the terms of the GNU General Public
> + * License version 2, as published by the Free Software Foundation, and
> + * may be copied, distributed, and modified under those terms.
> + *
> + * 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 <linux/kernel.h>
> +#include <linux/bitops.h>
> +#include <linux/err.h>
> +#include <linux/delay.h>
> +#include <linux/export.h>
> +#include <linux/clk-provider.h>
> +#include <linux/regmap.h>
> +
> +#include <asm/div64.h>
> +
> +#include "clk-qcapll.h"
> +
> +#define PLL_CONFIG1_SRESET_L		BIT(0)
> +#define PLL_MODULATION_START		BIT(0)
> +#define PLL_CONFIG_PLLPWD		BIT(5)
> +
> +#define PLL_POSTDIV_MASK	0x380
> +#define PLL_POSTDIV_SHFT	7
> +#define PLL_PLLPWD_MASK         0x20
> +#define PLL_PLLPWD_SHFT         5
> +#define PLL_REFDIV_MASK		0x7
> +#define PLL_REFDIV_SHFT		0
> +#define PLL_TGT_INT_SHFT	1
> +#define PLL_TGT_INT_MASK	0x3FE
> +#define PLL_TGT_FRAC_MASK	0x1FFFF800
> +#define PLL_TGT_FRAC_SHFT	11
> +
> +
> +static int clk_qcapll_enable(struct clk_hw *hw)
> +{
> +	struct clk_qcapll *pll = to_clk_qcapll(hw);
> +	int ret;
> +
> +	/* Enable PLL bypass mode. */
> +	ret = regmap_update_bits(pll->clkr.regmap, pll->config_reg,
> +				 PLL_CONFIG_PLLPWD, 0);
> +	if (ret)
> +		return ret;
> +
> +	return 0;
> +}
> +
> +static void clk_qcapll_disable(struct clk_hw *hw)
> +{
> +	struct clk_qcapll *pll = to_clk_qcapll(hw);
> +
> +	/* Disable PLL bypass mode. */
> +	regmap_update_bits(pll->clkr.regmap, pll->config_reg, PLL_CONFIG_PLLPWD,
> +			   0x1);
> +}
> +
> +static int clk_qcapll_is_enabled(struct clk_hw *hw)
> +{
> +	u32 config;
> +	struct clk_qcapll *pll = to_clk_qcapll(hw);
> +
> +	regmap_read(pll->clkr.regmap, pll->config_reg, &config);
> +	return config & PLL_PLLPWD_MASK;
> +}
> +
> +static unsigned long
> +clk_qcapll_recalc_rate(struct clk_hw *hw, unsigned long parent_rate)
> +{
> +	struct clk_qcapll *pll = to_clk_qcapll(hw);
> +	u32 ref_div, post_plldiv, tgt_div_frac, tgt_div_int;
> +	u32 config, mod_reg;
> +
> +	regmap_read(pll->clkr.regmap, pll->config_reg, &config);
> +	regmap_read(pll->clkr.regmap, pll->mod_reg, &mod_reg);
> +
> +	ref_div = (config & PLL_REFDIV_MASK) >> PLL_REFDIV_SHFT;
> +	post_plldiv = (config & PLL_POSTDIV_SHFT) >> PLL_POSTDIV_SHFT;

Why did we read these if we don't do math?

> +	tgt_div_frac = (mod_reg & PLL_TGT_FRAC_MASK) >>  PLL_TGT_FRAC_SHFT;
> +	tgt_div_int = (mod_reg & PLL_TGT_INT_MASK) >> PLL_TGT_INT_SHFT;
> +
> +	/*
> +	 * FICO = (Fref / (refdiv+1)) * (Ninv + Nfrac[17:5]/2^13
> +	 *	   + Nfrac[4:0]/(25*2^13)).
> +	 *
> +	 * we use this Lookups to get the precise frequencies as we need

why is Lookups capitalized?

> +	 * the calculation would need use of some math functions to get
> +	 * precise values which will add to the complexity. Hence, a simple
> +	 * lookup table based on the Fract values

Why is Fract capitalized? What does Fract even mean?

> +	 */
> +
> +	if (tgt_div_frac == 0x3D708)
> +		return 163840000;
> +	else if (tgt_div_frac == 0xA234)
> +		return 180633600;
> +	else if (tgt_div_frac == 0x51E9)
> +		return 184320000;
> +	else if (tgt_div_frac == 0x9bA6)
> +		return 196608000;
> +	else if (tgt_div_frac == 0x19168)
> +		return 197568000;

Math is ok, this isn't performance sensitive code.

> +
> +	return 0;
> +}
> +
> +static const
> +struct pll_freq_tbl *find_freq(const struct pll_freq_tbl *f, unsigned long rate)
> +{
> +	if (!f)
> +		return NULL;
> +
> +	for (; f->freq; f++)
> +		if (rate <= f->freq)
> +			return f;
> +
> +	return NULL;
> +}

We have qcom_find_freq for this I thought? Ah I see that this is
the same named structure but qca pll specific. Please rename the
struct and function to be qca specific.

> +
> +static int
> +clk_qcapll_determine_rate(struct clk_hw *hw, struct clk_rate_request *req)
> +{
> +	struct clk_qcapll *pll = to_clk_qcapll(hw);
> +	const struct pll_freq_tbl *f;
> +	unsigned long rate;
> +
> +	f = find_freq(pll->freq_tbl, req->rate);
> +	if (!f)
> +		rate = clk_qcapll_recalc_rate(hw, req->best_parent_rate);
> +	else
> +		rate = f->freq;
> +
> +	req->best_parent_rate = req->rate = rate;
> +
> +	return 0;
> +}
> +
> +static int
> +clk_qcapll_set_rate(struct clk_hw *hw, unsigned long rate, unsigned long p_rate)
> +{
> +	struct clk_qcapll *pll = to_clk_qcapll(hw);
> +	const struct pll_freq_tbl *f;
> +	u32 val, mask;
> +
> +	f = find_freq(pll->freq_tbl, rate);
> +	if (!f)
> +		return -EINVAL;
> +
> +	if (clk_qcapll_is_enabled(hw))
> +		clk_qcapll_disable(hw);
> +
> +	regmap_write(pll->clkr.regmap, pll->config1_reg, 0xc);
> +	udelay(2);
> +	regmap_write(pll->clkr.regmap, pll->config1_reg, 0xd);
> +
> +	val = f->postplldiv << PLL_POSTDIV_SHFT;
> +	val |= f->refdiv << PLL_REFDIV_SHFT;
> +
> +	mask = PLL_POSTDIV_MASK | PLL_REFDIV_MASK;
> +	regmap_update_bits(pll->clkr.regmap, pll->config_reg, mask, val);
> +
> +	clk_qcapll_enable(hw);
> +
> +	val = f->tgt_div_int << PLL_TGT_INT_SHFT;
> +	val |= f->tgt_div_frac << PLL_TGT_FRAC_SHFT;
> +
> +	mask = PLL_TGT_FRAC_MASK | PLL_TGT_INT_MASK;
> +	regmap_update_bits(pll->clkr.regmap, pll->mod_reg, mask, val);
> +
> +	/* Start the PLL to initiate the Modulation. */

Please drop full stop.

> +	regmap_update_bits(pll->clkr.regmap, pll->mod_reg,
> +						PLL_MODULATION_START, 0);
> +
> +	/*
> +	 * Wait until PLL is locked. Refer DPLL document for IPQ4019.
> +	 * This is recommended settling time for the PLL.
> +	 */
> +	udelay(50);
> +
> +	return 0;
> +}
> +
> +const struct clk_ops clk_qcapll_ops = {
> +	.enable = clk_qcapll_enable,
> +	.disable = clk_qcapll_disable,
> +	.is_enabled = clk_qcapll_is_enabled,
> +	.recalc_rate = clk_qcapll_recalc_rate,
> +	.determine_rate = clk_qcapll_determine_rate,
> +	.set_rate = clk_qcapll_set_rate,
> +};
> +EXPORT_SYMBOL_GPL(clk_qcapll_ops);
> diff --git a/drivers/clk/qcom/clk-qcapll.h b/drivers/clk/qcom/clk-qcapll.h
> new file mode 100644
> index 0000000..c0304ac
> --- /dev/null
> +++ b/drivers/clk/qcom/clk-qcapll.h
> @@ -0,0 +1,60 @@
> +/*
> + * Copyright (c) 2013, 2015-2016 The Linux Foundation. All rights reserved.
> + *
> + * This software is licensed under the terms of the GNU General Public
> + * License version 2, as published by the Free Software Foundation, and
> + * may be copied, distributed, and modified under those terms.
> + *
> + * 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.
> + */
> +
> +#ifndef __QCOM_CLK_QCA_PLL_H__
> +#define __QCOM_CLK_QCA_PLL_H__
> +
> +#include <linux/clk-provider.h>
> +#include "clk-regmap.h"
> +
> +/**
> + * struct pll_freq_tbl - PLL frequency table

Missing freq. Perhaps we should expand the general pll_freq_tbl
structure with these parameters? Or use a union for different
types of pll settings? Or just rename it to be qca specific.

> + * @postplldiv: postplldiv value
> + * @refdiv: refdiv value
> + * @tgt_div_int: tgt_div_int value
> + * @tgt_div_frac: tgt_div_frac values
> + */
> +struct pll_freq_tbl {
> +	unsigned long freq;
> +	u8 postplldiv;
> +	u8 refdiv;
> +	u8 tgt_div_int;
> +	u32 tgt_div_frac;
> +};
> +
> +/**
> + * struct clk_pll - phase locked loop (PLL)

It isn't called that.

> + * @config_reg: config register
> + * @mode_reg: mode register
> + * @status_reg: status register
> + * @status_bit: ANDed with @status_reg to determine if PLL is enabled
> + * @freq_tbl: PLL frequency table
> + * @hw: handle between common and hardware-specific interfaces

This doesn't even exist. clkr instead?

> + */
> +struct clk_qcapll {
> +	u32 config_reg;
> +	u32 mod_reg;
> +	u32 modstep_reg;
> +	u32 current_mod_pll_reg;
> +	u32 config1_reg;
> +
> +	const struct pll_freq_tbl *freq_tbl;
> +	struct clk_regmap clkr;
> +};
> +
> +extern const struct clk_ops clk_qcapll_ops;
> +
> +#define to_clk_qcapll(_hw) container_of(to_clk_regmap(_hw), \
> +						struct clk_qcapll, clkr)
> +
> +#endif
> diff --git a/drivers/clk/qcom/clk-rcg.h b/drivers/clk/qcom/clk-rcg.h
> index b904c33..562207c 100644
> --- a/drivers/clk/qcom/clk-rcg.h
> +++ b/drivers/clk/qcom/clk-rcg.h
> @@ -1,5 +1,5 @@
>  /*
> - * Copyright (c) 2013, The Linux Foundation. All rights reserved.
> + * Copyright (c) 2013-2016 The Linux Foundation. All rights reserved.
>   *
>   * This software is licensed under the terms of the GNU General Public
>   * License version 2, as published by the Free Software Foundation, and
> @@ -20,7 +20,7 @@
>  struct freq_tbl {
>  	unsigned long freq;
>  	u8 src;
> -	u8 pre_div;
> +	u16 pre_div;

This needs explaining.

>  	u16 m;
>  	u16 n;
>  };
> @@ -68,6 +68,18 @@ struct pre_div {
>  };
>  
>  /**
> + * struct c_div - custom-divider used with Different Offsets

Why is Different and Offsets capitalized?

> + * @c_div_offset: offset of the CDIV in the ADDRESS Space

it's just called offset. And I have no idea why ADDRESS is caps
and Space is capitalized and why it isn't just "address offset".

> + * @c_div_shift: lowest bit of pre divider field
> + * @c_div_width: number of bits in pre divider
> + */
> +struct c_div {
> +	u32	offset;
> +	u8	shift;
> +	u32	mask;
> +};
> +
> +/**
>   * struct src_sel - source selector
>   * @src_sel_shift: lowest bit of source selection field
>   * @parent_map: map from software's parent index to hardware's src_sel field
> @@ -172,6 +184,55 @@ struct clk_rcg2 {
>  
>  #define to_clk_rcg2(_hw) container_of(to_clk_regmap(_hw), struct clk_rcg2, clkr)
>  
> +/**
> + * struct clk_cdiv_rcg2 - cdiv with root clock generator
> + *
> + * @cmd_rcgr: corresponds to *_CMD_RCGR
> + * @mnd_width: number of bits in m/n/d values
> + * @hid_width: number of bits in half integer divider
> + * @parent_map: map from software's parent index to hardware's src_sel field

missing cdiv

> + * @freq_tbl: frequency table
> + * @clkr: regmap clock handle
> + * @lock: register lock

No lock.

> + *
> + */
> +struct clk_cdiv_rcg2 {
> +	u32		cmd_rcgr;
> +	u8		mnd_width;
> +	u8		hid_width;
> +	struct c_div	cdiv;
> +	const struct parent_map	*parent_map;
> +	const struct freq_tbl	*freq_tbl;
> +	struct clk_regmap	clkr;
> +};
> +
> +#define to_clk_cdiv_rcg2(_hw) container_of(to_clk_regmap(_hw), \
> +						struct clk_cdiv_rcg2, clkr)
> +
> +
> +/**
> + * struct clk_muxr_misc - mux and misc register
> + *
> + * @cmd_rcgr: corresponds to *_CMD_RCGR
> + * @mnd_width: number of bits in m/n/d values
> + * @hid_width: number of bits in half integer divider

Huh?

> + * @parent_map: map from software's parent index to hardware's src_sel field
> + * @freq_tbl: frequency table
> + * @clkr: regmap clock handle
> + * @lock: register lock

Where?

> + *
> + */
> +struct clk_muxr_misc {
> +	struct c_div			muxr;
> +	struct c_div			misc;
> +	const struct parent_map		*parent_map;
> +	const struct freq_tbl	*freq_tbl;
> +	struct clk_regmap		clkr;
> +};
> +
> +#define to_clk_muxr_misc(_hw) container_of(to_clk_regmap(_hw), \
> +						struct clk_muxr_misc, clkr)
> +
>  extern const struct clk_ops clk_rcg2_ops;
>  extern const struct clk_ops clk_rcg2_shared_ops;
>  extern const struct clk_ops clk_edp_pixel_ops;
> diff --git a/drivers/clk/qcom/clk-rcg2.c b/drivers/clk/qcom/clk-rcg2.c
> index a071bba..000c423 100644
> --- a/drivers/clk/qcom/clk-rcg2.c
> +++ b/drivers/clk/qcom/clk-rcg2.c
> @@ -1,5 +1,5 @@
>  /*
> - * Copyright (c) 2013, The Linux Foundation. All rights reserved.
> + * Copyright (c) 2013-2016, The Linux Foundation. All rights reserved.
>   *
>   * This software is licensed under the terms of the GNU General Public
>   * License version 2, as published by the Free Software Foundation, and
> @@ -20,7 +20,6 @@
>  #include <linux/delay.h>
>  #include <linux/regmap.h>
>  #include <linux/math64.h>
> -
>  #include <asm/div64.h>

No.

>  
>  #include "clk-rcg.h"
> @@ -46,6 +45,7 @@
>  #define M_REG			0x8
>  #define N_REG			0xc
>  #define D_REG			0x10
> +#define FEPLL_500_SRC		0x2

No.

>  
>  static int clk_rcg2_is_enabled(struct clk_hw *hw)
>  {
> @@ -209,6 +209,7 @@ static int _freq_tbl_determine_rate(struct clk_hw *hw,
>  	} else {
>  		rate =  clk_hw_get_rate(p);
>  	}
> +
>  	req->best_parent_hw = p;
>  	req->best_parent_rate = rate;
>  	req->rate = f->freq;

Noise.

> @@ -810,3 +811,697 @@ const struct clk_ops clk_gfx3d_ops = {
>  	.determine_rate = clk_gfx3d_determine_rate,
>  };
>  EXPORT_SYMBOL_GPL(clk_gfx3d_ops);
> +
> +static int clk_cdiv_rcg2_is_enabled(struct clk_hw *hw)
> +{
> +	struct clk_cdiv_rcg2 *rcg = to_clk_cdiv_rcg2(hw);
> +	u32 cmd = 0;
> +	int ret;
> +
> +	ret = regmap_read(rcg->clkr.regmap, rcg->cmd_rcgr + CMD_REG, &cmd);
> +	if (ret < 0)
> +		return false;
> +
> +	return (cmd & CMD_ROOT_OFF) == 0;
> +}
> +
> +static u8 clk_cdiv_rcg2_get_parent(struct clk_hw *hw)
> +{
> +	struct clk_cdiv_rcg2 *rcg = to_clk_cdiv_rcg2(hw);
> +	int num_parents = clk_hw_get_num_parents(hw);
> +	u32 cfg;
> +	int i, ret;
> +
> +	ret = regmap_read(rcg->clkr.regmap, rcg->cmd_rcgr + CFG_REG, &cfg);
> +	if (ret)
> +		goto err;
> +
> +	cfg &= CFG_SRC_SEL_MASK;
> +	cfg >>= CFG_SRC_SEL_SHIFT;
> +
> +	for (i = 0; i < num_parents; i++)
> +		if (cfg == rcg->parent_map[i].cfg)
> +			return i;
> +err:
> +	pr_debug("%s: Cannot find parent of %s clock, using default.\n",
> +			__func__, __clk_get_name(hw->clk));
> +	return 0;
> +}
> +
> +static int cdiv_update_config(struct clk_cdiv_rcg2 *rcg)
> +{
> +	int count, ret;
> +	struct clk_hw *hw = &rcg->clkr.hw;
> +	const char *name = __clk_get_name(hw->clk);
> +
> +	ret = regmap_update_bits(rcg->clkr.regmap, rcg->cmd_rcgr + CMD_REG,
> +				 CMD_UPDATE, CMD_UPDATE);
> +	if (ret)
> +		return ret;
> +
> +	/* Wait for update to take effect */
> +	for (count = 500; count > 0; count--) {
> +		u32 cmd = ~0U;
> +
> +		/* ignore regmap errors - until we exhaust retry count. */

Why? Is a regmap error going to get better somehow?

> +		ret = regmap_read(rcg->clkr.regmap, rcg->cmd_rcgr + CMD_REG,
> +									&cmd);
> +
> +		if (ret >= 0 && !(cmd & CMD_UPDATE))
> +			return 0;
> +
> +		udelay(1);
> +	}
> +
> +	WARN(ret, "%s: rcg didn't update its configuration.", name);
> +	return ret ? ret : -ETIMEDOUT;
> +}
> +
> +static int clk_cdiv_rcg2_set_parent(struct clk_hw *hw, u8 index)
> +{
> +	struct clk_cdiv_rcg2 *rcg = to_clk_cdiv_rcg2(hw);
> +	int ret;
> +
> +	ret = regmap_update_bits(rcg->clkr.regmap, rcg->cmd_rcgr + CFG_REG,
> +				 CFG_SRC_SEL_MASK,
> +				 rcg->parent_map[index].cfg <<
> +				 CFG_SRC_SEL_SHIFT);
> +	if (ret)
> +		return ret;
> +
> +	return cdiv_update_config(rcg);
> +}
> +
> +static unsigned long
> +clk_cdiv_rcg2_recalc_rate(struct clk_hw *hw, unsigned long parent_rate)
> +{
> +	struct clk_cdiv_rcg2 *rcg = to_clk_cdiv_rcg2(hw);
> +	u32 cfg, hid_div, m = 0, n = 0, mode = 0, mask, rate, cdiv;
> +	int ret;
> +
> +	ret = regmap_read(rcg->clkr.regmap, rcg->cmd_rcgr + CFG_REG, &cfg);
> +	if (ret)
> +		return 0UL;
> +
> +	if (rcg->mnd_width) {
> +		mask = BIT(rcg->mnd_width) - 1;
> +		ret = regmap_read(rcg->clkr.regmap, rcg->cmd_rcgr + M_REG, &m);
> +		if (ret)
> +			return 0UL;
> +
> +		m &= mask;
> +		ret = regmap_read(rcg->clkr.regmap, rcg->cmd_rcgr + N_REG, &n);
> +		if (ret)
> +			return 0UL;
> +
> +		n =  ~n;
> +		n &= mask;
> +
> +		n += m;
> +		mode = cfg & CFG_MODE_MASK;
> +		mode >>= CFG_MODE_SHIFT;
> +	}
> +
> +	mask = BIT(rcg->hid_width) - 1;
> +	hid_div = cfg >> CFG_SRC_DIV_SHIFT;
> +	hid_div &= mask;
> +	rate = calc_rate(parent_rate, m, n, mode, hid_div);
> +
> +	ret = regmap_read(rcg->clkr.regmap, rcg->cdiv.offset, &cdiv);
> +	if (ret)
> +		return 0UL;
> +
> +	cdiv &= (rcg->cdiv.mask << rcg->cdiv.shift);
> +	cdiv =  (cdiv >> rcg->cdiv.shift);
> +	if (cdiv)
> +		rate *= cdiv + 1;
> +	return rate;
> +}
> +
> +static int _cdiv_rcg2_freq_tbl_determine_rate(struct clk_hw *hw,
> +		const struct freq_tbl *f,
> +		struct clk_rate_request *req)
> +{
> +	unsigned long clk_flags;
> +	struct clk_hw *p_hw;
> +	unsigned long rate = req->rate;
> +
> +	f = qcom_find_freq(f, rate);
> +	if (!f)
> +		return 0L;
> +
> +	clk_flags = __clk_get_flags(hw->clk);
> +	p_hw = clk_hw_get_parent_by_index(hw, f->src);
> +	if (clk_flags & CLK_SET_RATE_PARENT) {
> +		if (f->pre_div)
> +			rate *= f->pre_div;
> +		if (f->n) {
> +			u64 tmp = rate;
> +
> +			tmp = tmp * f->n;
> +			do_div(tmp, f->m);
> +			rate = tmp;
> +		}
> +	} else {
> +		rate =	clk_hw_get_rate(p_hw);
> +	}
> +
> +	req->best_parent_rate = rate;
> +	req->best_parent_hw = p_hw;
> +	req->rate = f->freq;
> +
> +	return 0;
> +}
> +
> +
> +static int clk_cdiv_rcg2_determine_rate(struct clk_hw *hw,
> +					struct clk_rate_request *req)
> +{
> +	struct clk_cdiv_rcg2 *rcg = to_clk_cdiv_rcg2(hw);
> +
> +	return _cdiv_rcg2_freq_tbl_determine_rate(hw, rcg->freq_tbl, req);
> +}
> +
> +static int clk_cdiv_rcg2_configure(struct clk_cdiv_rcg2 *rcg,
> +				const struct freq_tbl *f)
> +{
> +	u32 cfg = 0, mask;
> +	u32 i;
> +	int ret;
> +
> +	if (rcg->mnd_width && f->n) {
> +		mask = BIT(rcg->mnd_width) - 1;
> +		ret = regmap_update_bits(rcg->clkr.regmap,
> +				rcg->cmd_rcgr + M_REG, mask, f->m);
> +		if (ret)
> +			return ret;
> +
> +		ret = regmap_update_bits(rcg->clkr.regmap,
> +				rcg->cmd_rcgr + N_REG, mask, ~(f->n - f->m));
> +		if (ret)
> +			return ret;
> +
> +		ret = regmap_update_bits(rcg->clkr.regmap,
> +				rcg->cmd_rcgr + D_REG, mask, ~f->n);
> +		if (ret)
> +			return ret;
> +	}
> +
> +
> +	if (rcg->cdiv.mask && f->pre_div > 16) {
> +
> +		/* The division is handled by two dividers. Both of which can
> +		 * divide by a maximum value of 16. To achieve a division of
> +		 * 256 = 16 * 16, we use a divider of 16 in the RCGR and the
> +		 * other divider of 16 in the MISC Register.
> +		 */
> +		for (i = 2; i <= 16; i++) {
> +			if (f->pre_div % i == 0)
> +				cfg = i;
> +		}
> +
> +		if (f->pre_div/cfg > 16)
> +			return -EINVAL;
> +		mask = (rcg->cdiv.mask)<<rcg->cdiv.shift;
> +		ret = regmap_update_bits(rcg->clkr.regmap,
> +					rcg->cdiv.offset, mask,
> +				((cfg - 1) << rcg->cdiv.shift) & mask);
> +		if (ret)
> +			return ret;
> +		cfg = (2 * (f->pre_div / cfg)) - 1;
> +	} else {
> +		ret = regmap_write(rcg->clkr.regmap, rcg->cdiv.offset, 0x0);
> +		if (ret)
> +			return ret;
> +		cfg = ((2 * f->pre_div) - 1) << CFG_SRC_DIV_SHIFT;
> +	}
> +
> +	mask = BIT(rcg->hid_width) - 1;
> +	mask |= CFG_SRC_SEL_MASK | CFG_MODE_MASK;
> +	cfg |= rcg->parent_map[f->src].cfg << CFG_SRC_SEL_SHIFT;
> +	if (rcg->mnd_width && f->n)
> +		cfg |= CFG_MODE_DUAL_EDGE;
> +	ret = regmap_update_bits(rcg->clkr.regmap,
> +			rcg->cmd_rcgr + CFG_REG, mask, cfg);
> +	if (ret)
> +		return ret;
> +
> +	return cdiv_update_config(rcg);
> +}
> +
> +static int __clk_cdiv_rcg2_set_rate(struct clk_hw *hw, unsigned long rate)
> +{
> +	struct clk_cdiv_rcg2 *rcg = to_clk_cdiv_rcg2(hw);
> +	const struct freq_tbl *f;
> +
> +	f = qcom_find_freq(rcg->freq_tbl, rate);
> +	if (!f)
> +		return -EINVAL;
> +
> +	return clk_cdiv_rcg2_configure(rcg, f);
> +}
> +
> +static int clk_cdiv_rcg2_set_rate(struct clk_hw *hw, unsigned long rate,
> +			    unsigned long parent_rate)
> +{
> +	return __clk_cdiv_rcg2_set_rate(hw, rate);
> +}
> +
> +static int clk_cdiv_rcg2_set_rate_and_parent(struct clk_hw *hw,
> +		unsigned long rate, unsigned long parent_rate, u8 index)
> +{
> +	return __clk_cdiv_rcg2_set_rate(hw, rate);
> +}
> +
> +const struct clk_ops clk_cdiv_rcg2_ops = {
> +	.is_enabled			= clk_cdiv_rcg2_is_enabled,
> +	.get_parent			= clk_cdiv_rcg2_get_parent,
> +	.set_parent			= clk_cdiv_rcg2_set_parent,
> +	.recalc_rate			= clk_cdiv_rcg2_recalc_rate,
> +	.determine_rate			= clk_cdiv_rcg2_determine_rate,
> +	.set_rate			= clk_cdiv_rcg2_set_rate,
> +	.set_rate_and_parent		= clk_cdiv_rcg2_set_rate_and_parent,
> +};
> +EXPORT_SYMBOL_GPL(clk_cdiv_rcg2_ops);

There's a lot of copy paste going on here. Why? Is this a cdiv
in front of an RCG? Why not model that as two clks then?

> +
> +static int clk_muxr_is_enabled(struct clk_hw *hw)
> +{
> +	return 0;
> +}

Seems impossible.

> +
> +static u8 clk_muxr_get_parent(struct clk_hw *hw)
> +{
> +	struct clk_muxr_misc *rcg = to_clk_muxr_misc(hw);
> +	int num_parents = clk_hw_get_num_parents(hw);
> +	u32 cfg;
> +	int i, ret;
> +
> +	ret = regmap_read(rcg->clkr.regmap, rcg->muxr.offset, &cfg);
> +	if (ret)
> +		goto err;
> +
> +	cfg >>= rcg->muxr.shift;
> +	cfg &= rcg->muxr.mask;
> +
> +	for (i = 0; i < num_parents; i++)
> +		if (cfg == rcg->parent_map[i].cfg)
> +			return i;
> +
> +err:
> +	pr_debug("%s: Cannot find parent of %s clock, using default.\n",
> +			__func__, __clk_get_name(hw->clk));
> +	return 0;
> +}
> +
> +static int clk_muxr_set_parent(struct clk_hw *hw, u8 index)
> +{
> +	struct clk_muxr_misc *rcg = to_clk_muxr_misc(hw);
> +	int ret;
> +
> +	ret = regmap_update_bits(rcg->clkr.regmap, rcg->muxr.offset,
> +				 (rcg->muxr.mask<<rcg->muxr.shift),
> +				 rcg->parent_map[index].cfg << rcg->muxr.shift);
> +	if (ret)
> +		return ret;
> +
> +	return 0;
> +}
> +
> +static unsigned long
> +clk_muxr_recalc_rate(struct clk_hw *hw, unsigned long parent_rate)
> +{
> +	struct clk_muxr_misc *rcg = to_clk_muxr_misc(hw);
> +	u32 misc;
> +	int ret;
> +
> +	ret = regmap_read(rcg->clkr.regmap, rcg->misc.offset, &misc);
> +	if (ret)
> +		return 0UL;
> +
> +	misc &= rcg->misc.mask;
> +	misc >>= rcg->misc.shift;
> +
> +	return parent_rate * (misc + 1);
> +}
> +
> +static int clk_muxr_determine_rate(struct clk_hw *hw,
> +				   struct clk_rate_request *req)
> +{
> +	struct clk_muxr_misc *rcg = to_clk_muxr_misc(hw);
> +	const struct freq_tbl *f;
> +	unsigned long clk_flags;
> +	unsigned long rate = req->rate;
> +	struct clk_hw *p_hw;
> +
> +	f = qcom_find_freq(rcg->freq_tbl, rate);
> +	if (!f)
> +		return 0L;
> +
> +	clk_flags = __clk_get_flags(hw->clk);
> +	p_hw = clk_hw_get_parent_by_index(hw, f->src);
> +	if (clk_flags & CLK_SET_RATE_PARENT) {
> +		if (f->pre_div)
> +			rate *= f->pre_div;
> +	} else {
> +		rate =	clk_hw_get_rate(p_hw);
> +	}
> +
> +	req->best_parent_rate = rate;
> +	req->best_parent_hw = p_hw;
> +	req->rate = f->freq;
> +
> +	return 0;
> +}
> +
> +static int __clk_muxr_set_rate(struct clk_hw *hw, unsigned long rate)
> +{
> +	struct clk_muxr_misc *rcg = to_clk_muxr_misc(hw);
> +	const struct freq_tbl *f;
> +	int ret;
> +
> +	f = qcom_find_freq(rcg->freq_tbl, rate);
> +	if (!f)
> +		return -EINVAL;
> +
> +	ret = regmap_update_bits(rcg->clkr.regmap, rcg->muxr.offset,
> +				rcg->muxr.mask << rcg->muxr.shift,
> +				rcg->parent_map[f->src].cfg << rcg->muxr.shift);
> +	if (ret)
> +		return ret;
> +
> +	ret = regmap_update_bits(rcg->clkr.regmap, rcg->misc.offset,
> +				rcg->misc.mask << rcg->misc.shift,
> +				(f->pre_div - 1) << rcg->misc.shift);
> +	return ret;
> +}
> +
> +static int clk_muxr_set_rate(struct clk_hw *hw, unsigned long rate,
> +			    unsigned long parent_rate)
> +{
> +	return __clk_muxr_set_rate(hw, rate);
> +}
> +
> +static int clk_muxr_set_rate_and_parent(struct clk_hw *hw,
> +		unsigned long rate, unsigned long parent_rate, u8 index)
> +{
> +	return __clk_muxr_set_rate(hw, rate);
> +}
> +
> +const struct clk_ops clk_muxr_misc_ops = {
> +	.is_enabled	=	clk_muxr_is_enabled,
> +	.get_parent	=	clk_muxr_get_parent,
> +	.set_parent	=	clk_muxr_set_parent,
> +	.recalc_rate	=	clk_muxr_recalc_rate,
> +	.determine_rate	=	clk_muxr_determine_rate,
> +	.set_rate	=	clk_muxr_set_rate,
> +	.set_rate_and_parent	=	clk_muxr_set_rate_and_parent,
> +};
> +EXPORT_SYMBOL_GPL(clk_muxr_misc_ops);
> +
> +static int clk_cpu_rcg2_is_enabled(struct clk_hw *hw)
> +{
> +	struct clk_cdiv_rcg2 *rcg = to_clk_cdiv_rcg2(hw);
> +	u32 cmd;
> +	int ret;
> +
> +	ret = regmap_read(rcg->clkr.regmap, rcg->cmd_rcgr + CMD_REG, &cmd);
> +	if (ret)
> +		return 0;
> +
> +	return (cmd & CMD_ROOT_OFF) == 0;
> +
> +}
> +
> +static u8 clk_cpu_rcg2_get_parent(struct clk_hw *hw)
> +{
> +	struct clk_cdiv_rcg2 *rcg = to_clk_cdiv_rcg2(hw);
> +	int num_parents = clk_hw_get_num_parents(hw);
> +	u32 cfg;
> +	int i, ret;
> +
> +	ret = regmap_read(rcg->clkr.regmap, rcg->cmd_rcgr + CFG_REG, &cfg);
> +	if (ret)
> +		goto err;
> +
> +	cfg &= CFG_SRC_SEL_MASK;
> +	cfg >>= CFG_SRC_SEL_SHIFT;
> +
> +	for (i = 0; i < num_parents; i++)
> +		if (cfg == rcg->parent_map[i].cfg)
> +			return i;
> +
> +err:
> +	pr_debug("%s: Cannot find parent of %s clock, using default.\n",
> +			__func__, __clk_get_name(hw->clk));
> +	return 0;
> +}
> +
> +static int cpu_rcg2_update_config(struct clk_cdiv_rcg2 *rcg)
> +{
> +	int count, ret;
> +	u32 cmd;
> +	struct clk_hw *hw = &rcg->clkr.hw;
> +	const char *name = __clk_get_name(hw->clk);
> +
> +	ret = regmap_update_bits(rcg->clkr.regmap, rcg->cmd_rcgr + CMD_REG,
> +				 CMD_UPDATE, CMD_UPDATE);
> +	if (ret)
> +		return ret;
> +
> +	/* Wait for update to take effect */
> +	for (count = 500; count > 0; count--) {
> +		/* ignore regmap errors until we exhaust retry count.*/
> +		ret = regmap_read(rcg->clkr.regmap, rcg->cmd_rcgr + CMD_REG,
> +									&cmd);
> +		if (ret >= 0 && !(cmd & CMD_UPDATE))
> +			return 0;
> +
> +		udelay(1);
> +	}
> +
> +	WARN(1, "%s: rcg didn't update its configuration.", name);
> +	return ret ? ret : -ETIMEDOUT;
> +}
> +
> +static int clk_cpu_rcg2_set_parent(struct clk_hw *hw, u8 index)
> +{
> +	struct clk_cdiv_rcg2 *rcg = to_clk_cdiv_rcg2(hw);
> +	int ret;
> +
> +	ret = regmap_update_bits(rcg->clkr.regmap, rcg->cmd_rcgr + CFG_REG,
> +				 CFG_SRC_SEL_MASK,
> +				 rcg->parent_map[index].cfg <<
> +				 CFG_SRC_SEL_SHIFT);
> +	if (ret)
> +		return ret;
> +
> +	return cpu_rcg2_update_config(rcg);
> +}
> +
> +
> +/*
> + * These are used for looking up the actual divider ratios
> + * the divider used for DDR PLL Post divider is not linear,
> + * hence we need this look up table
> + */
> +static const unsigned char ddrpll_div[] = {

unsigned char... but they're numbers.

> +		12,
> +		13,
> +		14,
> +		15,
> +		16,
> +		17,
> +		18,
> +		19,
> +		20,
> +		21,
> +		22,
> +		24,
> +		26,
> +		28
> +};
> +
> +static unsigned long
> +clk_cpu_rcg2_recalc_rate(struct clk_hw *hw, unsigned long parent_rate)
> +{
> +	struct clk_cdiv_rcg2 *rcg = to_clk_cdiv_rcg2(hw);
> +	u32 cfg, hid_div, m = 0, n = 0, mode = 0, mask, cdiv;
> +	unsigned long rate;
> +	u32 src;
> +	int ret;
> +
> +	ret = regmap_read(rcg->clkr.regmap, rcg->cmd_rcgr + CFG_REG, &cfg);
> +	if (ret)
> +		return 0UL;
> +
> +	if (rcg->mnd_width) {
> +		mask = BIT(rcg->mnd_width) - 1;
> +		ret = regmap_read(rcg->clkr.regmap, rcg->cmd_rcgr + M_REG, &m);
> +		if (ret)
> +			return 0UL;
> +
> +		m &= mask;
> +
> +		ret = regmap_read(rcg->clkr.regmap, rcg->cmd_rcgr + N_REG, &n);
> +		if (ret)
> +			return 0UL;
> +
> +		n =  ~n;
> +		n &= mask;
> +
> +		n += m;
> +		mode = cfg & CFG_MODE_MASK;
> +		mode >>= CFG_MODE_SHIFT;
> +	}
> +
> +	mask = BIT(rcg->hid_width) - 1;
> +	hid_div = cfg >> CFG_SRC_DIV_SHIFT;
> +	hid_div &= mask;
> +	rate = calc_rate(parent_rate, m, n, mode, hid_div);
> +	src = (cfg >> CFG_SRC_SEL_SHIFT) & 0xf;
> +	if (src == 0x1) {

What does 1 mean?

> +		u64 tmp;
> +
> +		ret = regmap_read(rcg->clkr.regmap, rcg->cdiv.offset, &cdiv);
> +		if (ret)
> +			return 0UL;
> +
> +		cdiv &= (rcg->cdiv.mask << rcg->cdiv.shift);
> +		cdiv = cdiv >> rcg->cdiv.shift;
> +		tmp = rate;
> +		do_div(tmp, ddrpll_div[cdiv]);
> +		rate = tmp;
> +		rate *= 16;
> +		tmp = rate;
> +		do_div(tmp, 1000000);
> +		rate = tmp;
> +		rate = rate * 1000000;
> +	}
> +	return rate;
> +}
> +
> +static int _cpu_rcg2_freq_tbl_determine_rate(struct clk_hw *hw,
> +		const struct freq_tbl *f,
> +		struct clk_rate_request *req)
> +{
> +	unsigned long clk_flags;
> +	struct clk_hw *p_hw;
> +	unsigned long rate;
> +
> +	f = qcom_find_freq(f, req->rate);
> +	if (!f)
> +		return 0L;
> +
> +	clk_flags = __clk_get_flags(hw->clk);

Is this used?

> +	p_hw = clk_hw_get_parent_by_index(hw, f->src);
> +	rate = clk_hw_get_rate(p_hw);
> +
> +	req->best_parent_rate = rate;
> +	req->best_parent_hw = p_hw;
> +	req->rate = f->freq;
> +
> +	return 0;

Is this function any different from the one for rcg2?

> +}
> +
> +static int clk_cpu_rcg2_determine_rate(struct clk_hw *hw,
> +					struct clk_rate_request *req)
> +{
> +	struct clk_cdiv_rcg2 *rcg = to_clk_cdiv_rcg2(hw);
> +
> +	return _cpu_rcg2_freq_tbl_determine_rate(hw, rcg->freq_tbl, req);
> +}
> +
> +
> +static int clk_cpu_rcg2_configure(struct clk_cdiv_rcg2 *rcg,
> +						const struct freq_tbl *f)
> +{
> +	u32 cfg, mask;
> +	int ret;
> +
> +	if (rcg->mnd_width && f->n) {
> +		mask = BIT(rcg->mnd_width) - 1;
> +		ret = regmap_update_bits(rcg->clkr.regmap,
> +				rcg->cmd_rcgr + M_REG, mask, f->m);
> +		if (ret)
> +			return ret;
> +
> +		ret = regmap_update_bits(rcg->clkr.regmap,
> +				rcg->cmd_rcgr + N_REG, mask, ~(f->n - f->m));
> +		if (ret)
> +			return ret;
> +
> +		ret = regmap_update_bits(rcg->clkr.regmap,
> +				rcg->cmd_rcgr + D_REG, mask, ~f->n);
> +		if (ret)
> +			return ret;
> +	}
> +
> +	if ((rcg->parent_map[f->src].cfg == 0x01)) {

What is going on?

> +		mask = (BIT(rcg->hid_width) - 1);
> +		mask |= CFG_SRC_SEL_MASK | CFG_MODE_MASK;
> +		cfg = FEPLL_500_SRC << CFG_SRC_SEL_SHIFT;
> +		cfg |= (1 << CFG_SRC_DIV_SHIFT);
> +		ret = regmap_update_bits(rcg->clkr.regmap,
> +					rcg->cmd_rcgr + CFG_REG, mask, cfg);
> +		if (ret)
> +			return ret;
> +		cpu_rcg2_update_config(rcg);
> +		mask = (rcg->cdiv.mask)<<rcg->cdiv.shift;
> +		ret = regmap_update_bits(rcg->clkr.regmap,
> +					rcg->cdiv.offset, mask,
> +				(f->pre_div << rcg->cdiv.shift) & mask);
> +		udelay(1);
> +		mask = BIT(rcg->hid_width) - 1;
> +		mask |= CFG_SRC_SEL_MASK | CFG_MODE_MASK;
> +		cfg = 1 << CFG_SRC_DIV_SHIFT;
> +	} else {
> +		mask = BIT(rcg->hid_width) - 1;
> +		mask |= CFG_SRC_SEL_MASK | CFG_MODE_MASK;
> +		cfg = f->pre_div << CFG_SRC_DIV_SHIFT;
> +	}
> +
> +	cfg |= rcg->parent_map[f->src].cfg << CFG_SRC_SEL_SHIFT;
> +	if (rcg->mnd_width && f->n)
> +		cfg |= CFG_MODE_DUAL_EDGE;
> +	ret = regmap_update_bits(rcg->clkr.regmap,
> +					rcg->cmd_rcgr + CFG_REG, mask, cfg);
> +	if (ret)
> +		return ret;
> +
> +	return cpu_rcg2_update_config(rcg);
> +}
> +
> +static int __clk_cpu_rcg2_set_rate(struct clk_hw *hw, unsigned long rate)
> +{
> +	struct clk_cdiv_rcg2 *rcg = to_clk_cdiv_rcg2(hw);
> +	const struct freq_tbl *f;
> +
> +	f = qcom_find_freq(rcg->freq_tbl, rate);
> +	if (!f)
> +		return -EINVAL;
> +
> +	return clk_cpu_rcg2_configure(rcg, f);
> +}
> +
> +static int clk_cpu_rcg2_set_rate(struct clk_hw *hw, unsigned long rate,
> +			    unsigned long parent_rate)
> +{
> +	return __clk_cpu_rcg2_set_rate(hw, rate);
> +}
> +
> +static int clk_cpu_rcg2_set_rate_and_parent(struct clk_hw *hw,
> +		unsigned long rate, unsigned long parent_rate, u8 index)
> +{
> +	return __clk_cpu_rcg2_set_rate(hw, rate);
> +}
> +
> +const struct clk_ops clk_cpu_rcg2_ops = {
> +	.is_enabled	=	clk_cpu_rcg2_is_enabled,
> +	.get_parent	=	clk_cpu_rcg2_get_parent,
> +	.set_parent	=	clk_cpu_rcg2_set_parent,
> +	.recalc_rate	=	clk_cpu_rcg2_recalc_rate,
> +	.determine_rate	=	clk_cpu_rcg2_determine_rate,
> +	.set_rate	=	clk_cpu_rcg2_set_rate,
> +	.set_rate_and_parent	=	clk_cpu_rcg2_set_rate_and_parent,
> +};
> +EXPORT_SYMBOL_GPL(clk_cpu_rcg2_ops);

So a ton of stuff is duplicated. I don't even want to read it
because the same rcg code is copied a few times and then some
modifications are made and special cases are made in generic code
for SoC specific things.

> diff --git a/drivers/clk/qcom/common.c b/drivers/clk/qcom/common.c
> index f7c226a..0851122 100644
> --- a/drivers/clk/qcom/common.c
> +++ b/drivers/clk/qcom/common.c
> @@ -1,5 +1,5 @@
>  /*
> - * Copyright (c) 2013-2014, The Linux Foundation. All rights reserved.
> + * Copyright (c) 2013-2016, The Linux Foundation. All rights reserved.
>   *
>   * This software is licensed under the terms of the GNU General Public
>   * License version 2, as published by the Free Software Foundation, and
> @@ -269,4 +269,11 @@ int qcom_cc_probe(struct platform_device *pdev, const struct qcom_cc_desc *desc)
>  }
>  EXPORT_SYMBOL_GPL(qcom_cc_probe);
>  
> +void qcom_cc_remove(struct platform_device *pdev)
> +{
> +	of_clk_del_provider(pdev->dev.of_node);
> +	reset_controller_unregister(platform_get_drvdata(pdev));
> +}
> +EXPORT_SYMBOL_GPL(qcom_cc_remove);
> +

Nope.

>  MODULE_LICENSE("GPL v2");
> diff --git a/drivers/clk/qcom/common.h b/drivers/clk/qcom/common.h
> index ae9bdeb..ad66ae2 100644
> --- a/drivers/clk/qcom/common.h
> +++ b/drivers/clk/qcom/common.h
> @@ -1,5 +1,5 @@
>  /*
> - * Copyright (c) 2014, The Linux Foundation. All rights reserved.
> + * Copyright (c) 2014-2016 The Linux Foundation. All rights reserved.
>   *
>   * This software is licensed under the terms of the GNU General Public
>   * License version 2, as published by the Free Software Foundation, and
> @@ -48,5 +48,6 @@ extern int qcom_cc_really_probe(struct platform_device *pdev,
>  				struct regmap *regmap);
>  extern int qcom_cc_probe(struct platform_device *pdev,
>  			 const struct qcom_cc_desc *desc);
> +extern void qcom_cc_remove(struct platform_device *pdev);
>  

Nope.

>  #endif
> diff --git a/include/dt-bindings/clock/qcom,gcc-ipq4019.h b/include/dt-bindings/clock/qcom,gcc-ipq4019.h
> index 6240e5b..c75b98a 100644
> --- a/include/dt-bindings/clock/qcom,gcc-ipq4019.h
> +++ b/include/dt-bindings/clock/qcom,gcc-ipq4019.h
> @@ -1,4 +1,5 @@
> -/* Copyright (c) 2015 The Linux Foundation. All rights reserved.
> +/*
> + * Copyright (c) 2015-2016 The Linux Foundation. All rights reserved.
>   *
>   * Permission to use, copy, modify, and/or distribute this software for any
>   * purpose with or without fee is hereby granted, provided that the above
> @@ -154,5 +155,6 @@
>  #define GCC_QDSS_BCR					69
>  #define GCC_MPM_BCR					70
>  #define GCC_SPDM_BCR					71
> +#define AUDIO_BLK_ARES					GCC_AUDIO_BCR
>  
>  #endif
> diff --git a/include/dt-bindings/sound/ipq4019-audio.h b/include/dt-bindings/sound/ipq4019-audio.h
> new file mode 100644
> index 0000000..7bf8036
> --- /dev/null
> +++ b/include/dt-bindings/sound/ipq4019-audio.h

Why is this here?

-- 
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum,
a Linux Foundation Collaborative Project

^ permalink raw reply	[flat|nested] 24+ messages in thread

end of thread, other threads:[~2016-08-16  1:00 UTC | newest]

Thread overview: 24+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2016-07-15  7:07 [PATCH 0/4] Qualcomm IPQ4019 Audio driver addition njaigane-sgV2jX0FEOL9JmXXK+q4OQ
2016-07-15  7:07 ` njaigane at codeaurora.org
2016-07-15  7:07 ` njaigane
2016-07-15  7:07 ` [PATCH 1/4] qcom: ipq4019: Add ipq4019 ASoC device tree changes njaigane
2016-07-15  7:07   ` njaigane at codeaurora.org
2016-07-17 20:03   ` Rob Herring
2016-07-17 20:03     ` Rob Herring
2016-07-15  7:07 ` [PATCH 2/4] qcom: ipq4019: ASoC clock driver support njaigane
2016-07-15  7:07   ` njaigane at codeaurora.org
2016-08-16  1:00   ` Stephen Boyd
2016-08-16  1:00     ` Stephen Boyd
2016-07-15  7:07 ` [PATCH 3/4] qcom: ipq4019: ASoC tlmm/pinctrl support njaigane
2016-07-15  7:07   ` njaigane at codeaurora.org
     [not found]   ` <1468566426-19598-4-git-send-email-njaigane-sgV2jX0FEOL9JmXXK+q4OQ@public.gmane.org>
2016-07-15 19:15     ` Bjorn Andersson
2016-07-15 19:15       ` Bjorn Andersson
2016-07-15 19:15       ` Bjorn Andersson
2016-07-15 20:23   ` Andy Gross
2016-07-15 20:23     ` Andy Gross
2016-07-15  7:07 ` [PATCH 4/4] qcom: ipq4019: Add ASoC driver modules njaigane
2016-07-15 12:52   ` Mark Brown
2016-07-15 12:52     ` Mark Brown
     [not found] ` <1468566426-19598-1-git-send-email-njaigane-sgV2jX0FEOL9JmXXK+q4OQ@public.gmane.org>
2016-07-15 12:56   ` [PATCH 0/4] Qualcomm IPQ4019 Audio driver addition Mark Brown
2016-07-15 12:56     ` Mark Brown
2016-07-15 12:56     ` Mark Brown

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.