linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH v5 1/8] regulator: lochnagar: Move driver to binding from DT
@ 2018-11-20 14:16 Charles Keepax
  2018-11-20 14:16 ` [PATCH v5 2/8] mfd: lochnagar: Add initial binding documentation Charles Keepax
                   ` (6 more replies)
  0 siblings, 7 replies; 21+ messages in thread
From: Charles Keepax @ 2018-11-20 14:16 UTC (permalink / raw)
  To: lee.jones, mturquette, sboyd, broonie, linus.walleij, robh+dt
  Cc: mark.rutland, lgirdwood, devicetree, linux-kernel, patches,
	linux-clk, linux-gpio

Based on review comments on the MFD driver, move the child drivers for
the Lochnagar MFD over to binding through device tree.

Signed-off-by: Charles Keepax <ckeepax@opensource.cirrus.com>
---

Changes since v4:
 - Split out regulator binding for each regulator

Thanks,
Charles

 drivers/regulator/lochnagar-regulator.c | 48 +++++++++++++++++++++++++--------
 1 file changed, 37 insertions(+), 11 deletions(-)

diff --git a/drivers/regulator/lochnagar-regulator.c b/drivers/regulator/lochnagar-regulator.c
index 182198246479..5a89e6d4b9a6 100644
--- a/drivers/regulator/lochnagar-regulator.c
+++ b/drivers/regulator/lochnagar-regulator.c
@@ -13,6 +13,7 @@
 #include <linux/module.h>
 #include <linux/mutex.h>
 #include <linux/of.h>
+#include <linux/of_device.h>
 #include <linux/platform_device.h>
 #include <linux/regmap.h>
 #include <linux/regulator/driver.h>
@@ -214,28 +215,52 @@ static const struct regulator_desc lochnagar_regulators[] = {
 	},
 };
 
+static const struct of_device_id lochnagar_of_match[] = {
+	{
+		.compatible = "cirrus,lochnagar2-micvdd",
+		.data = &lochnagar_regulators[LOCHNAGAR_MICVDD],
+	},
+	{
+		.compatible = "cirrus,lochnagar2-mic1vdd",
+		.data = &lochnagar_regulators[LOCHNAGAR_MIC1VDD],
+	},
+	{
+		.compatible = "cirrus,lochnagar2-mic2vdd",
+		.data = &lochnagar_regulators[LOCHNAGAR_MIC1VDD],
+	},
+	{
+		.compatible = "cirrus,lochnagar2-vddcore",
+		.data = &lochnagar_regulators[LOCHNAGAR_VDDCORE],
+	},
+	{},
+};
+
 static int lochnagar_regulator_probe(struct platform_device *pdev)
 {
 	struct device *dev = &pdev->dev;
 	struct lochnagar *lochnagar = dev_get_drvdata(dev->parent);
 	struct regulator_config config = { };
+	const struct of_device_id *of_id;
+	const struct regulator_desc *desc;
 	struct regulator_dev *rdev;
-	int ret, i;
+	int ret;
 
-	config.dev = lochnagar->dev;
+	config.dev = dev;
 	config.regmap = lochnagar->regmap;
 	config.driver_data = lochnagar;
 
-	for (i = 0; i < ARRAY_SIZE(lochnagar_regulators); i++) {
-		const struct regulator_desc *desc = &lochnagar_regulators[i];
+	of_id = of_match_device(lochnagar_of_match, dev);
+	if (!of_id)
+		return -EINVAL;
 
-		rdev = devm_regulator_register(dev, desc, &config);
-		if (IS_ERR(rdev)) {
-			ret = PTR_ERR(rdev);
-			dev_err(dev, "Failed to register %s regulator: %d\n",
-				desc->name, ret);
-			return ret;
-		}
+	desc = of_id->data;
+
+	rdev = devm_regulator_register(dev, desc, &config);
+	if (IS_ERR(rdev)) {
+		ret = PTR_ERR(rdev);
+		dev_err(dev, "Failed to register %s regulator: %d\n",
+			desc->name, ret);
+		return ret;
 	}
 
 	return 0;
@@ -244,6 +269,7 @@ static int lochnagar_regulator_probe(struct platform_device *pdev)
 static struct platform_driver lochnagar_regulator_driver = {
 	.driver = {
 		.name = "lochnagar-regulator",
+		.of_match_table = of_match_ptr(lochnagar_of_match),
 	},
 
 	.probe = lochnagar_regulator_probe,
-- 
2.11.0


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

* [PATCH v5 2/8] mfd: lochnagar: Add initial binding documentation
  2018-11-20 14:16 [PATCH v5 1/8] regulator: lochnagar: Move driver to binding from DT Charles Keepax
@ 2018-11-20 14:16 ` Charles Keepax
  2018-11-28  9:18   ` Lee Jones
  2018-11-20 14:16 ` [PATCH v5 3/8] clk: " Charles Keepax
                   ` (5 subsequent siblings)
  6 siblings, 1 reply; 21+ messages in thread
From: Charles Keepax @ 2018-11-20 14:16 UTC (permalink / raw)
  To: lee.jones, mturquette, sboyd, broonie, linus.walleij, robh+dt
  Cc: mark.rutland, lgirdwood, devicetree, linux-kernel, patches,
	linux-clk, linux-gpio

Lochnagar is an evaluation and development board for Cirrus
Logic Smart CODEC and Amp devices. It allows the connection of
most Cirrus Logic devices on mini-cards, as well as allowing
connection of various application processor systems to provide a
full evaluation platform. This driver supports the board
controller chip on the Lochnagar board.

Signed-off-by: Charles Keepax <ckeepax@opensource.cirrus.com>
---

Changes since v4:
 - Move sub-bindings into separate documents

Again incase Rob missed v4 I have dropped his ack due to the large
changes introduced in v4, see:

 https://patchwork.kernel.org/patch/10673891/

Thanks,
Charles

 .../devicetree/bindings/mfd/cirrus,lochnagar.txt   |  71 +++++++++++
 include/dt-bindings/clk/lochnagar.h                |  26 ++++
 include/dt-bindings/pinctrl/lochnagar.h            | 132 +++++++++++++++++++++
 3 files changed, 229 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/mfd/cirrus,lochnagar.txt
 create mode 100644 include/dt-bindings/clk/lochnagar.h
 create mode 100644 include/dt-bindings/pinctrl/lochnagar.h

diff --git a/Documentation/devicetree/bindings/mfd/cirrus,lochnagar.txt b/Documentation/devicetree/bindings/mfd/cirrus,lochnagar.txt
new file mode 100644
index 000000000000..7a5f99fb489d
--- /dev/null
+++ b/Documentation/devicetree/bindings/mfd/cirrus,lochnagar.txt
@@ -0,0 +1,71 @@
+Cirrus Logic Lochnagar Audio Development Board
+
+Lochnagar is an evaluation and development board for Cirrus Logic
+Smart CODEC and Amp devices. It allows the connection of most Cirrus
+Logic devices on mini-cards, as well as allowing connection of
+various application processor systems to provide a full evaluation
+platform.  Audio system topology, clocking and power can all be
+controlled through the Lochnagar, allowing the device under test
+to be used in a variety of possible use cases.
+
+Also see these documents for generic binding information:
+  [1] GPIO : ../gpio/gpio.txt
+
+And these for relevant defines:
+  [2] include/dt-bindings/pinctrl/lochnagar.h
+  [3] include/dt-bindings/clock/lochnagar.h
+
+And these documents for the required sub-node binding details:
+  [4] Clock: ../clock/cirrus,lochnagar.txt
+  [5] Pinctrl: ../pinctrl/cirrus,lochnagar.txt
+  [6] Regulator: ../regulator/cirrus,lochnagar.txt
+
+Required properties:
+
+  - compatible : One of the following strings:
+                 "cirrus,lochnagar1"
+                 "cirrus,lochnagar2"
+
+  - reg : I2C slave address
+
+  - reset-gpios : Reset line to the Lochnagar, see [1].
+
+Required sub-nodes:
+
+  - lochnagar-clk : Binding for the clocking components, see [4].
+
+  - lochnagar-pinctrl : Binding for the pin control components, see [5].
+
+  - lochnagar-regulator : Binding for the regulator components, see [6].
+                          Only required for Lochnagar 2.
+
+Optional properties:
+
+  - present-gpios : Host present line, indicating the presence of a
+    host system, see [1]. This can be omitted if the present line is
+    tied in hardware.
+
+Example:
+
+lochnagar: lochnagar@22 {
+	compatible = "cirrus,lochnagar2";
+	reg = <0x22>;
+
+	reset-gpios = <&gpio0 55 0>;
+	present-gpios = <&gpio0 60 0>;
+
+	lochnagar-clk {
+		compatible = "cirrus,lochnagar2-clk";
+		...
+	};
+
+	lochnagar-pinctrl {
+		compatible = "cirrus,lochnagar-pinctrl";
+		...
+	};
+
+	lochnagar-regulator {
+		compatible = "cirrus,lochnagar-regulator";
+		...
+	};
+};
diff --git a/include/dt-bindings/clk/lochnagar.h b/include/dt-bindings/clk/lochnagar.h
new file mode 100644
index 000000000000..8fa20551ff17
--- /dev/null
+++ b/include/dt-bindings/clk/lochnagar.h
@@ -0,0 +1,26 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Device Tree defines for Lochnagar clocking
+ *
+ * Copyright (c) 2017-2018 Cirrus Logic, Inc. and
+ *                         Cirrus Logic International Semiconductor Ltd.
+ *
+ * Author: Charles Keepax <ckeepax@opensource.cirrus.com>
+ */
+
+#ifndef DT_BINDINGS_CLK_LOCHNAGAR_H
+#define DT_BINDINGS_CLK_LOCHNAGAR_H
+
+#define LOCHNAGAR_CDC_MCLK1		0
+#define LOCHNAGAR_CDC_MCLK2		1
+#define LOCHNAGAR_DSP_CLKIN		2
+#define LOCHNAGAR_GF_CLKOUT1		3
+#define LOCHNAGAR_GF_CLKOUT2		4
+#define LOCHNAGAR_PSIA1_MCLK		5
+#define LOCHNAGAR_PSIA2_MCLK		6
+#define LOCHNAGAR_SPDIF_MCLK		7
+#define LOCHNAGAR_ADAT_MCLK		8
+#define LOCHNAGAR_SOUNDCARD_MCLK	9
+#define LOCHNAGAR_SPDIF_CLKOUT		10
+
+#endif
diff --git a/include/dt-bindings/pinctrl/lochnagar.h b/include/dt-bindings/pinctrl/lochnagar.h
new file mode 100644
index 000000000000..644760bf5725
--- /dev/null
+++ b/include/dt-bindings/pinctrl/lochnagar.h
@@ -0,0 +1,132 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Device Tree defines for Lochnagar pinctrl
+ *
+ * Copyright (c) 2018 Cirrus Logic, Inc. and
+ *                    Cirrus Logic International Semiconductor Ltd.
+ *
+ * Author: Charles Keepax <ckeepax@opensource.cirrus.com>
+ */
+
+#ifndef DT_BINDINGS_PINCTRL_LOCHNAGAR_H
+#define DT_BINDINGS_PINCTRL_LOCHNAGAR_H
+
+#define LOCHNAGAR1_PIN_CDC_RESET		0
+#define LOCHNAGAR1_PIN_DSP_RESET		1
+#define LOCHNAGAR1_PIN_CDC_CIF1MODE		2
+#define LOCHNAGAR1_PIN_NUM_GPIOS		3
+
+#define LOCHNAGAR2_PIN_CDC_RESET		0
+#define LOCHNAGAR2_PIN_DSP_RESET		1
+#define LOCHNAGAR2_PIN_CDC_CIF1MODE		2
+#define LOCHNAGAR2_PIN_CDC_LDOENA		3
+#define LOCHNAGAR2_PIN_SPDIF_HWMODE		4
+#define LOCHNAGAR2_PIN_SPDIF_RESET		5
+#define LOCHNAGAR2_PIN_FPGA_GPIO1		6
+#define LOCHNAGAR2_PIN_FPGA_GPIO2		7
+#define LOCHNAGAR2_PIN_FPGA_GPIO3		8
+#define LOCHNAGAR2_PIN_FPGA_GPIO4		9
+#define LOCHNAGAR2_PIN_FPGA_GPIO5		10
+#define LOCHNAGAR2_PIN_FPGA_GPIO6		11
+#define LOCHNAGAR2_PIN_CDC_GPIO1		12
+#define LOCHNAGAR2_PIN_CDC_GPIO2		13
+#define LOCHNAGAR2_PIN_CDC_GPIO3		14
+#define LOCHNAGAR2_PIN_CDC_GPIO4		15
+#define LOCHNAGAR2_PIN_CDC_GPIO5		16
+#define LOCHNAGAR2_PIN_CDC_GPIO6		17
+#define LOCHNAGAR2_PIN_CDC_GPIO7		18
+#define LOCHNAGAR2_PIN_CDC_GPIO8		19
+#define LOCHNAGAR2_PIN_DSP_GPIO1		20
+#define LOCHNAGAR2_PIN_DSP_GPIO2		21
+#define LOCHNAGAR2_PIN_DSP_GPIO3		22
+#define LOCHNAGAR2_PIN_DSP_GPIO4		23
+#define LOCHNAGAR2_PIN_DSP_GPIO5		24
+#define LOCHNAGAR2_PIN_DSP_GPIO6		25
+#define LOCHNAGAR2_PIN_GF_GPIO2			26
+#define LOCHNAGAR2_PIN_GF_GPIO3			27
+#define LOCHNAGAR2_PIN_GF_GPIO7			28
+#define LOCHNAGAR2_PIN_CDC_AIF1_BCLK		29
+#define LOCHNAGAR2_PIN_CDC_AIF1_RXDAT		30
+#define LOCHNAGAR2_PIN_CDC_AIF1_LRCLK		31
+#define LOCHNAGAR2_PIN_CDC_AIF1_TXDAT		32
+#define LOCHNAGAR2_PIN_CDC_AIF2_BCLK		33
+#define LOCHNAGAR2_PIN_CDC_AIF2_RXDAT		34
+#define LOCHNAGAR2_PIN_CDC_AIF2_LRCLK		35
+#define LOCHNAGAR2_PIN_CDC_AIF2_TXDAT		36
+#define LOCHNAGAR2_PIN_CDC_AIF3_BCLK		37
+#define LOCHNAGAR2_PIN_CDC_AIF3_RXDAT		38
+#define LOCHNAGAR2_PIN_CDC_AIF3_LRCLK		39
+#define LOCHNAGAR2_PIN_CDC_AIF3_TXDAT		40
+#define LOCHNAGAR2_PIN_DSP_AIF1_BCLK		41
+#define LOCHNAGAR2_PIN_DSP_AIF1_RXDAT		42
+#define LOCHNAGAR2_PIN_DSP_AIF1_LRCLK		43
+#define LOCHNAGAR2_PIN_DSP_AIF1_TXDAT		44
+#define LOCHNAGAR2_PIN_DSP_AIF2_BCLK		45
+#define LOCHNAGAR2_PIN_DSP_AIF2_RXDAT		46
+#define LOCHNAGAR2_PIN_DSP_AIF2_LRCLK		47
+#define LOCHNAGAR2_PIN_DSP_AIF2_TXDAT		48
+#define LOCHNAGAR2_PIN_PSIA1_BCLK		49
+#define LOCHNAGAR2_PIN_PSIA1_RXDAT		50
+#define LOCHNAGAR2_PIN_PSIA1_LRCLK		51
+#define LOCHNAGAR2_PIN_PSIA1_TXDAT		52
+#define LOCHNAGAR2_PIN_PSIA2_BCLK		53
+#define LOCHNAGAR2_PIN_PSIA2_RXDAT		54
+#define LOCHNAGAR2_PIN_PSIA2_LRCLK		55
+#define LOCHNAGAR2_PIN_PSIA2_TXDAT		56
+#define LOCHNAGAR2_PIN_GF_AIF3_BCLK		57
+#define LOCHNAGAR2_PIN_GF_AIF3_RXDAT		58
+#define LOCHNAGAR2_PIN_GF_AIF3_LRCLK		59
+#define LOCHNAGAR2_PIN_GF_AIF3_TXDAT		60
+#define LOCHNAGAR2_PIN_GF_AIF4_BCLK		61
+#define LOCHNAGAR2_PIN_GF_AIF4_RXDAT		62
+#define LOCHNAGAR2_PIN_GF_AIF4_LRCLK		63
+#define LOCHNAGAR2_PIN_GF_AIF4_TXDAT		64
+#define LOCHNAGAR2_PIN_GF_AIF1_BCLK		65
+#define LOCHNAGAR2_PIN_GF_AIF1_RXDAT		66
+#define LOCHNAGAR2_PIN_GF_AIF1_LRCLK		67
+#define LOCHNAGAR2_PIN_GF_AIF1_TXDAT		68
+#define LOCHNAGAR2_PIN_GF_AIF2_BCLK		69
+#define LOCHNAGAR2_PIN_GF_AIF2_RXDAT		70
+#define LOCHNAGAR2_PIN_GF_AIF2_LRCLK		71
+#define LOCHNAGAR2_PIN_GF_AIF2_TXDAT		72
+#define LOCHNAGAR2_PIN_DSP_UART1_RX		73
+#define LOCHNAGAR2_PIN_DSP_UART1_TX		74
+#define LOCHNAGAR2_PIN_DSP_UART2_RX		75
+#define LOCHNAGAR2_PIN_DSP_UART2_TX		76
+#define LOCHNAGAR2_PIN_GF_UART2_RX		77
+#define LOCHNAGAR2_PIN_GF_UART2_TX		78
+#define LOCHNAGAR2_PIN_USB_UART_RX		79
+#define LOCHNAGAR2_PIN_CDC_PDMCLK1		80
+#define LOCHNAGAR2_PIN_CDC_PDMDAT1		81
+#define LOCHNAGAR2_PIN_CDC_PDMCLK2		82
+#define LOCHNAGAR2_PIN_CDC_PDMDAT2		83
+#define LOCHNAGAR2_PIN_CDC_DMICCLK1		84
+#define LOCHNAGAR2_PIN_CDC_DMICDAT1		85
+#define LOCHNAGAR2_PIN_CDC_DMICCLK2		86
+#define LOCHNAGAR2_PIN_CDC_DMICDAT2		87
+#define LOCHNAGAR2_PIN_CDC_DMICCLK3		88
+#define LOCHNAGAR2_PIN_CDC_DMICDAT3		89
+#define LOCHNAGAR2_PIN_CDC_DMICCLK4		90
+#define LOCHNAGAR2_PIN_CDC_DMICDAT4		91
+#define LOCHNAGAR2_PIN_DSP_DMICCLK1		92
+#define LOCHNAGAR2_PIN_DSP_DMICDAT1		93
+#define LOCHNAGAR2_PIN_DSP_DMICCLK2		94
+#define LOCHNAGAR2_PIN_DSP_DMICDAT2		95
+#define LOCHNAGAR2_PIN_I2C2_SCL			96
+#define LOCHNAGAR2_PIN_I2C2_SDA			97
+#define LOCHNAGAR2_PIN_I2C3_SCL			98
+#define LOCHNAGAR2_PIN_I2C3_SDA			99
+#define LOCHNAGAR2_PIN_I2C4_SCL			100
+#define LOCHNAGAR2_PIN_I2C4_SDA			101
+#define LOCHNAGAR2_PIN_DSP_STANDBY		102
+#define LOCHNAGAR2_PIN_CDC_MCLK1		103
+#define LOCHNAGAR2_PIN_CDC_MCLK2		104
+#define LOCHNAGAR2_PIN_DSP_CLKIN		105
+#define LOCHNAGAR2_PIN_PSIA1_MCLK		106
+#define LOCHNAGAR2_PIN_PSIA2_MCLK		107
+#define LOCHNAGAR2_PIN_GF_GPIO1			108
+#define LOCHNAGAR2_PIN_GF_GPIO5			109
+#define LOCHNAGAR2_PIN_DSP_GPIO20		110
+#define LOCHNAGAR2_PIN_NUM_GPIOS		111
+
+#endif
-- 
2.11.0


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

* [PATCH v5 3/8] clk: lochnagar: Add initial binding documentation
  2018-11-20 14:16 [PATCH v5 1/8] regulator: lochnagar: Move driver to binding from DT Charles Keepax
  2018-11-20 14:16 ` [PATCH v5 2/8] mfd: lochnagar: Add initial binding documentation Charles Keepax
@ 2018-11-20 14:16 ` Charles Keepax
  2018-11-26 20:16   ` Rob Herring
  2018-11-20 14:16 ` [PATCH v5 4/8] pinctrl: " Charles Keepax
                   ` (4 subsequent siblings)
  6 siblings, 1 reply; 21+ messages in thread
From: Charles Keepax @ 2018-11-20 14:16 UTC (permalink / raw)
  To: lee.jones, mturquette, sboyd, broonie, linus.walleij, robh+dt
  Cc: mark.rutland, lgirdwood, devicetree, linux-kernel, patches,
	linux-clk, linux-gpio

Lochnagar is an evaluation and development board for Cirrus
Logic Smart CODEC and Amp devices. It allows the connection of
most Cirrus Logic devices on mini-cards, as well as allowing
connection of various application processor systems to provide a
full evaluation platform. This driver supports the board
controller chip on the Lochnagar board.

Signed-off-by: Charles Keepax <ckeepax@opensource.cirrus.com>
---
 .../devicetree/bindings/clock/cirrus,lochnagar.txt | 89 ++++++++++++++++++++++
 1 file changed, 89 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/clock/cirrus,lochnagar.txt

diff --git a/Documentation/devicetree/bindings/clock/cirrus,lochnagar.txt b/Documentation/devicetree/bindings/clock/cirrus,lochnagar.txt
new file mode 100644
index 000000000000..c1b5478d5432
--- /dev/null
+++ b/Documentation/devicetree/bindings/clock/cirrus,lochnagar.txt
@@ -0,0 +1,89 @@
+Cirrus Logic Lochnagar Audio Development Board
+
+Lochnagar is an evaluation and development board for Cirrus Logic
+Smart CODEC and Amp devices. It allows the connection of most Cirrus
+Logic devices on mini-cards, as well as allowing connection of
+various application processor systems to provide a full evaluation
+platform.  Audio system topology, clocking and power can all be
+controlled through the Lochnagar, allowing the device under test
+to be used in a variety of possible use cases.
+
+This binding document describes the binding for the clock portion of
+the driver.
+
+Also see these documents for generic binding information:
+  [1] Clock : ../clock/clock-bindings.txt
+
+And these for relevant defines:
+  [2] include/dt-bindings/clock/lochnagar.h
+
+This binding must be part of the Lochnagar MFD binding:
+  [3] ../mfd/cirrus,lochnagar.txt
+
+Required properties:
+
+  - compatible : One of the following strings:
+                 "cirrus,lochnagar1-clk"
+                 "cirrus,lochnagar2-clk"
+
+  - #clock-cells : Must be 1. The first cell indicates the clock
+    number, see [2] for available clocks and [1].
+
+Optional properties:
+
+  - clocks : Must contain an entry for each clock in clock-names.
+  - clock-names : May contain entries for each of the following
+    clocks:
+     - ln-cdc-clkout : Output clock from CODEC card.
+     - ln-dsp-clkout : Output clock from DSP card.
+     - ln-gf-mclk1,ln-gf-mclk2,ln-gf-mclk3,ln-gf-mclk4 : Optional
+       input audio clocks from host system.
+     - ln-psia1-mclk, ln-psia2-mclk : Optional input audio clocks from
+       external connector.
+     - ln-spdif-clkout : Optional input audio clock from SPDIF.
+     - ln-adat-clkout : Optional input audio clock from ADAT.
+     - ln-pmic-32k : On board fixed regulator.
+     - ln-clk-12m : On board fixed regulator.
+     - ln-clk-11m : On board fixed regulator.
+     - ln-clk-24m : On board fixed regulator.
+     - ln-clk-22m : On board fixed regulator.
+     - ln-usb-clk-24m : On board fixed regulator.
+     - ln-usb-clk-12m : On board fixed regulator.
+
+  - assigned-clocks : A list of Lochnagar clocks to be reparented, see
+    [2] for available clocks.
+  - assigned-clock-parents : Parents to be assigned to the clocks
+    listed in "assigned-clocks".
+
+Optional sub-nodes:
+
+  - fixed-clock nodes may be registered for the following on board clocks:
+     - ln-pmic-32k : 32768 kHz
+     - ln-clk-12m : 12288000 kHz
+     - ln-clk-11m : 11298600 kHz
+     - ln-clk-24m : 24576000 kHz
+     - ln-clk-22m : 22579200 kHz
+     - ln-usb-clk-24m : 24576000 kHz
+     - ln-usb-clk-12m : 12288000 kHz
+
+Example:
+
+lochnagar-clk {
+	compatible = "cirrus,lochnagar2-clk";
+
+	#clock-cells = <1>;
+
+	clocks = <&clk-audio>, <&clk_pmic>;
+	clock-names = "ln-gf-mclk2", "ln-pmic-32k";
+
+	assigned-clocks = <&lochnagar-clk LOCHNAGAR_CDC_MCLK1>,
+			  <&lochnagar-clk LOCHNAGAR_CDC_MCLK2>;
+	assigned-clock-parents = <&clk-audio>,
+				 <&clk-pmic>;
+
+	clk-pmic: clk-pmic {
+		compatible = "fixed-clock";
+		clock-cells = <0>;
+		clock-frequency = <32768>;
+	};
+};
-- 
2.11.0


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

* [PATCH v5 4/8] pinctrl: lochnagar: Add initial binding documentation
  2018-11-20 14:16 [PATCH v5 1/8] regulator: lochnagar: Move driver to binding from DT Charles Keepax
  2018-11-20 14:16 ` [PATCH v5 2/8] mfd: lochnagar: Add initial binding documentation Charles Keepax
  2018-11-20 14:16 ` [PATCH v5 3/8] clk: " Charles Keepax
@ 2018-11-20 14:16 ` Charles Keepax
  2018-12-07 17:07   ` Rob Herring
  2018-12-16  0:16   ` Linus Walleij
  2018-11-20 14:16 ` [PATCH v5 5/8] regulator: " Charles Keepax
                   ` (3 subsequent siblings)
  6 siblings, 2 replies; 21+ messages in thread
From: Charles Keepax @ 2018-11-20 14:16 UTC (permalink / raw)
  To: lee.jones, mturquette, sboyd, broonie, linus.walleij, robh+dt
  Cc: mark.rutland, lgirdwood, devicetree, linux-kernel, patches,
	linux-clk, linux-gpio

Lochnagar is an evaluation and development board for Cirrus
Logic Smart CODEC and Amp devices. It allows the connection of
most Cirrus Logic devices on mini-cards, as well as allowing
connection of various application processor systems to provide a
full evaluation platform. This driver supports the board
controller chip on the Lochnagar board.

Signed-off-by: Charles Keepax <ckeepax@opensource.cirrus.com>
---
 .../bindings/pinctrl/cirrus,lochnagar.txt          | 141 +++++++++++++++++++++
 1 file changed, 141 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/pinctrl/cirrus,lochnagar.txt

diff --git a/Documentation/devicetree/bindings/pinctrl/cirrus,lochnagar.txt b/Documentation/devicetree/bindings/pinctrl/cirrus,lochnagar.txt
new file mode 100644
index 000000000000..36de6b0555f2
--- /dev/null
+++ b/Documentation/devicetree/bindings/pinctrl/cirrus,lochnagar.txt
@@ -0,0 +1,141 @@
+Cirrus Logic Lochnagar Audio Development Board
+
+Lochnagar is an evaluation and development board for Cirrus Logic
+Smart CODEC and Amp devices. It allows the connection of most Cirrus
+Logic devices on mini-cards, as well as allowing connection of
+various application processor systems to provide a full evaluation
+platform.  Audio system topology, clocking and power can all be
+controlled through the Lochnagar, allowing the device under test
+to be used in a variety of possible use cases.
+
+This binding document describes the binding for the pinctrl portion
+of the driver.
+
+Also see these documents for generic binding information:
+  [1] GPIO : ../gpio/gpio.txt
+  [2] Pinctrl: ../pinctrl/pinctrl-bindings.txt
+
+And these for relevant defines:
+  [3] include/dt-bindings/pinctrl/lochnagar.h
+
+This binding must be part of the Lochnagar MFD binding:
+  [4] ../mfd/cirrus,lochnagar.txt
+
+Required properties:
+
+  - compatible : One of the following strings:
+                 "cirrus,lochnagar-pinctrl"
+
+  - gpio-controller : Indicates this device is a GPIO controller.
+  - #gpio-cells : Must be 2. The first cell is the pin number, see
+    [3] for available pins and the second cell is used to specify
+    optional parameters, see [1].
+  - gpio-ranges : Range of pins managed by the GPIO controller, see
+    [1]. Both the GPIO and Pinctrl base should be set to zero and the
+    count to the appropriate of the LOCHNAGARx_PIN_NUM_GPIOS define,
+    see [3].
+
+  - pinctrl-names : A pinctrl state named "default" must be defined.
+  - pinctrl-0 : A phandle to the default pinctrl state.
+
+Required sub-nodes:
+
+The pin configurations are defined as a child of the pinctrl states
+node, see [2]. Each sub-node can have the following properties:
+  - groups : A list of groups to select (either this or "pins" must be
+    specified), available groups:
+      codec-aif1, codec-aif2, codec-aif3, dsp-aif1, dsp-aif2, psia1,
+      psia2, gf-aif1, gf-aif2, gf-aif3, gf-aif4, spdif-aif, usb-aif1,
+      usb-aif2, adat-aif, soundcard-aif
+  - pins : A list of pin names to select (either this or "groups" must
+    be specified), available pins:
+      fgpa-gpio1, fgpa-gpio2, fgpa-gpio3, fgpa-gpio4, fgpa-gpio5,
+      fgpa-gpio6, codec-gpio1, codec-gpio2, codec-gpio3, codec-gpio4,
+      codec-gpio5, codec-gpio6, codec-gpio7, codec-gpio8, dsp-gpio1,
+      dsp-gpio2, dsp-gpio3, dsp-gpio4, dsp-gpio5, dsp-gpio6, gf-gpio2,
+      gf-gpio3, gf-gpio7, codec-aif1-bclk, codec-aif1-rxdat,
+      codec-aif1-lrclk, codec-aif1-txdat, codec-aif2-bclk,
+      codec-aif2-rxdat, codec-aif2-lrclk, codec-aif2-txdat,
+      codec-aif3-bclk, codec-aif3-rxdat, codec-aif3-lrclk,
+      codec-aif3-txdat, dsp-aif1-bclk, dsp-aif1-rxdat, dsp-aif1-lrclk,
+      dsp-aif1-txdat, dsp-aif2-bclk, dsp-aif2-rxdat,
+      dsp-aif2-lrclk, dsp-aif2-txdat, psia1-bclk, psia1-rxdat,
+      psia1-lrclk, psia1-txdat, psia2-bclk, psia2-rxdat, psia2-lrclk,
+      psia2-txdat, gf-aif3-bclk, gf-aif3-rxdat, gf-aif3-lrclk,
+      gf-aif3-txdat, gf-aif4-bclk, gf-aif4-rxdat, gf-aif4-lrclk,
+      gf-aif4-txdat, gf-aif1-bclk, gf-aif1-rxdat, gf-aif1-lrclk,
+      gf-aif1-txdat, gf-aif2-bclk, gf-aif2-rxdat, gf-aif2-lrclk,
+      gf-aif2-txdat, dsp-uart1-rx, dsp-uart1-tx, dsp-uart2-rx,
+      dsp-uart2-tx, gf-uart2-rx, gf-uart2-tx, usb-uart-rx,
+      codec-pdmclk1, codec-pdmdat1, codec-pdmclk2, codec-pdmdat2,
+      codec-dmicclk1, codec-dmicdat1, codec-dmicclk2, codec-dmicdat2,
+      codec-dmicclk3, codec-dmicdat3, codec-dmicclk4, codec-dmicdat4,
+      dsp-dmicclk1, dsp-dmicdat1, dsp-dmicclk2, dsp-dmicdat2, i2c2-scl,
+      i2c2-sda, i2c3-scl, i2c3-sda, i2c4-scl, i2c4-sda, dsp-standby,
+      codec-mclk1, codec-mclk2, dsp-clkin, psia1-mclk, psia2-mclk,
+      gf-gpio1, gf-gpio5, dsp-gpio20, led1, led2
+  - function : The mux function to select, available functions:
+      aif, fgpa-gpio1, fgpa-gpio2, fgpa-gpio3, fgpa-gpio4, fgpa-gpio5,
+      fgpa-gpio6, codec-gpio1, codec-gpio2, codec-gpio3, codec-gpio4,
+      codec-gpio5, codec-gpio6, codec-gpio7, codec-gpio8, dsp-gpio1,
+      dsp-gpio2, dsp-gpio3, dsp-gpio4, dsp-gpio5, dsp-gpio6, gf-gpio2,
+      gf-gpio3, gf-gpio7, gf-gpio1, gf-gpio5, dsp-gpio20, codec-clkout,
+      dsp-clkout, pmic-32k, spdif-clkout, clk-12m288, clk-11m2986,
+      clk-24m576, clk-22m5792, xmos-mclk, gf-clkout1, gf-mclk1,
+      gf-mclk3, gf-mclk2, gf-clkout2, codec-mclk1, codec-mclk2,
+      dsp-clkin, psia1-mclk, psia2-mclk, spdif-mclk, codec-irq,
+      codec-reset, dsp-reset, dsp-irq, dsp-standby, codec-pdmclk1,
+      codec-pdmdat1, codec-pdmclk2, codec-pdmdat2, codec-dmicclk1,
+      codec-dmicdat1, codec-dmicclk2, codec-dmicdat2, codec-dmicclk3,
+      codec-dmicdat3, codec-dmicclk4, codec-dmicdat4, dsp-dmicclk1,
+      dsp-dmicdat1, dsp-dmicclk2, dsp-dmicdat2, dsp-uart1-rx,
+      dsp-uart1-tx, dsp-uart2-rx, dsp-uart2-tx, gf-uart2-rx,
+      gf-uart2-tx, usb-uart-rx, usb-uart-tx, i2c2-scl, i2c2-sda,
+      i2c3-scl, i2c3-sda, i2c4-scl, i2c4-sda, gpio, spdif-aif, psia1,
+      psia1-bclk, psia1-lrclk, psia1-rxdat, psia1-txdat, psia2,
+      psia2-bclk, psia2-lrclk, psia2-rxdat, psia2-txdat, codec-aif1,
+      codec-aif1-bclk, codec-aif1-lrclk, codec-aif1-rxdat,
+      codec-aif1-txdat, codec-aif2, codec-aif2-bclk, codec-aif2-lrclk,
+      codec-aif2-rxdat, codec-aif2-txdat, codec-aif3, codec-aif3-bclk,
+      codec-aif3-lrclk, codec-aif3-rxdat, codec-aif3-txdat, dsp-aif1,
+      dsp-aif1-bclk, dsp-aif1-lrclk, dsp-aif1-rxdat, dsp-aif1-txdat,
+      dsp-aif2, dsp-aif2-bclk, dsp-aif2-lrclk, dsp-aif2-rxdat,
+      dsp-aif2-txdat, gf-aif3, gf-aif3-bclk, gf-aif3-lrclk,
+      gf-aif3-rxdat, gf-aif3-txdat, gf-aif4, gf-aif4-bclk,
+      gf-aif4-lrclk, gf-aif4-rxdat, gf-aif4-txdat, gf-aif1,
+      gf-aif1-bclk, gf-aif1-lrclk, gf-aif1-rxdat, gf-aif1-txdat,
+      gf-aif2, gf-aif2-bclk, gf-aif2-lrclk, gf-aif2-rxdat,
+      gf-aif2-txdat, usb-aif1, usb-aif2, adat-aif, soundcard-aif,
+
+  - output-enable : Specifies that an AIF group will be used as a master
+    interface (either this or input-enable is required if a group is
+    being muxed to an AIF)
+  - input-enable : Specifies that an AIF group will be used as a slave
+    interface (either this or output-enable is required if a group is
+    being muxed to an AIF)
+
+Example:
+
+lochnagar-pinctrl {
+	compatible = "cirrus,lochnagar-pinctrl";
+
+	gpio-controller;
+	#gpio-cells = <2>;
+	gpio-ranges = <&lochnagar 0 0 LOCHNAGAR2_PIN_NUM_GPIOS>;
+
+	pinctrl-names = "default";
+	pinctrl-0 = <&pin-settings>;
+
+	pin-settings: pin-settings {
+		ap-aif {
+			input-enable;
+			groups = "gf-aif1";
+			function = "codec-aif3";
+		};
+		codec-aif {
+			output-enable;
+			groups = "codec-aif3";
+			function = "gf-aif1";
+		};
+	};
+};
-- 
2.11.0


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

* [PATCH v5 5/8] regulator: lochnagar: Add initial binding documentation
  2018-11-20 14:16 [PATCH v5 1/8] regulator: lochnagar: Move driver to binding from DT Charles Keepax
                   ` (2 preceding siblings ...)
  2018-11-20 14:16 ` [PATCH v5 4/8] pinctrl: " Charles Keepax
@ 2018-11-20 14:16 ` Charles Keepax
  2018-11-20 14:16 ` [PATCH v5 6/8] mfd: lochnagar: Add support for the Cirrus Logic Lochnagar Charles Keepax
                   ` (2 subsequent siblings)
  6 siblings, 0 replies; 21+ messages in thread
From: Charles Keepax @ 2018-11-20 14:16 UTC (permalink / raw)
  To: lee.jones, mturquette, sboyd, broonie, linus.walleij, robh+dt
  Cc: mark.rutland, lgirdwood, devicetree, linux-kernel, patches,
	linux-clk, linux-gpio

Lochnagar is an evaluation and development board for Cirrus
Logic Smart CODEC and Amp devices. It allows the connection of
most Cirrus Logic devices on mini-cards, as well as allowing
connection of various application processor systems to provide a
full evaluation platform. This driver supports the board
controller chip on the Lochnagar board.

Signed-off-by: Charles Keepax <ckeepax@opensource.cirrus.com>
---
 .../bindings/regulator/cirrus,lochnagar.txt        | 82 ++++++++++++++++++++++
 1 file changed, 82 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/regulator/cirrus,lochnagar.txt

diff --git a/Documentation/devicetree/bindings/regulator/cirrus,lochnagar.txt b/Documentation/devicetree/bindings/regulator/cirrus,lochnagar.txt
new file mode 100644
index 000000000000..91974e6ee251
--- /dev/null
+++ b/Documentation/devicetree/bindings/regulator/cirrus,lochnagar.txt
@@ -0,0 +1,82 @@
+Cirrus Logic Lochnagar Audio Development Board
+
+Lochnagar is an evaluation and development board for Cirrus Logic
+Smart CODEC and Amp devices. It allows the connection of most Cirrus
+Logic devices on mini-cards, as well as allowing connection of
+various application processor systems to provide a full evaluation
+platform.  Audio system topology, clocking and power can all be
+controlled through the Lochnagar, allowing the device under test
+to be used in a variety of possible use cases.
+
+This binding document describes the binding for the regulator portion
+of the driver.
+
+Also see these documents for generic binding information:
+  [1] Regulator: ../regulator/regulator.txt
+
+This binding must be part of the Lochnagar MFD binding:
+  [2] ../mfd/cirrus,lochnagar.txt
+
+Optional sub-nodes:
+
+  - VDDCORE : Initialisation data for the VDDCORE regulator, which
+    supplies the CODECs digital core if it has no build regulator for that
+    purpose.
+      Required Properties:
+      - compatible : One of the following strings:
+                     "cirrus,lochnagar2-vddcore"
+      - SYSVDD-supply: Primary power supply for the Lochnagar.
+
+  - MICVDD : Initialisation data for the MICVDD regulator, which
+    supplies the CODECs MICVDD.
+      Required Properties:
+      - compatible : One of the following strings:
+                     "cirrus,lochnagar2-micvdd"
+      - SYSVDD-supply: Primary power supply for the Lochnagar.
+
+  - MIC1VDD, MIC2VDD : Initialisation data for the MICxVDD supplies.
+      Required Properties:
+      - compatible : One of the following strings:
+                     "cirrus,lochnagar2-mic1vdd", "cirrus,lochnagar2-mic2vdd"
+      Optional Properties:
+      - cirrus,micbias-input : A property selecting which of the CODEC
+        minicard micbias outputs should be used, valid values are 1 - 4.
+      - MICBIAS1-supply, MICBIAS2-supply: Regulator supplies for the
+        MICxVDD outputs, supplying the digital microphones, normally
+        supplied from the attached CODEC.
+
+  - VDD1V8 : Recommended fixed regulator for the VDD1V8 regulator, which supplies the
+    CODECs analog and 1.8V digital supplies.
+      Required Properties:
+      - compatible : Should be set to "regulator-fixed"
+      - regulator-min-microvolt : Should be set to 1.8V
+      - regulator-max-microvolt : Should be set to 1.8V
+      - regulator-boot-on
+      - regulator-always-on
+      - vin-supply : Should be set to same supply as SYSVDD
+
+Example:
+
+lochnagar {
+	lochnagar-micvdd: MICVDD {
+		compatible = "cirrus,lochnagar2-micvdd";
+
+		SYSVDD-supply = <&wallvdd>;
+
+		regulator-min-microvolt = <3300000>;
+		regulator-max-microvolt = <3300000>;
+	};
+
+	lochnagar-vdd1v8: VDD1V8 {
+		compatible = "regulator-fixed";
+
+		regulator-name = "VDD1V8";
+		regulator-min-microvolt = <1800000>;
+		regulator-max-microvolt = <1800000>;
+		regulator-boot-on;
+		regulator-always-on;
+
+		vin-supply = <&wallvdd>;
+	};
+};
+
-- 
2.11.0


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

* [PATCH v5 6/8] mfd: lochnagar: Add support for the Cirrus Logic Lochnagar
  2018-11-20 14:16 [PATCH v5 1/8] regulator: lochnagar: Move driver to binding from DT Charles Keepax
                   ` (3 preceding siblings ...)
  2018-11-20 14:16 ` [PATCH v5 5/8] regulator: " Charles Keepax
@ 2018-11-20 14:16 ` Charles Keepax
  2018-11-23  9:00   ` kbuild test robot
  2018-11-28  9:22   ` Lee Jones
  2018-11-20 14:16 ` [PATCH v5 7/8] clk: " Charles Keepax
  2018-11-20 14:16 ` [PATCH v5 8/8] pinctrl: " Charles Keepax
  6 siblings, 2 replies; 21+ messages in thread
From: Charles Keepax @ 2018-11-20 14:16 UTC (permalink / raw)
  To: lee.jones, mturquette, sboyd, broonie, linus.walleij, robh+dt
  Cc: mark.rutland, lgirdwood, devicetree, linux-kernel, patches,
	linux-clk, linux-gpio

Lochnagar is an evaluation and development board for Cirrus
Logic Smart CODEC and Amp devices. It allows the connection of
most Cirrus Logic devices on mini-cards, as well as allowing
connection of various application processor systems to provide a
full evaluation platform. This driver supports the board
controller chip on the Lochnagar board. Audio system topology,
clocking and power can all be controlled through the Lochnagar
controller chip, allowing the device under test to be used in
a variety of possible use cases.

As the Lochnagar is a fairly complex device this MFD driver
allows the drivers for the various features to be bound
in. Initially clocking, regulator and pinctrl will be added as
these are necessary to configure the system. But in time at least
audio and voltage/current monitoring will also be added.

Signed-off-by: Charles Keepax <ckeepax@opensource.cirrus.com>
---

No change since v4.

Thanks,
Charles

 MAINTAINERS                         |  17 ++
 drivers/mfd/Kconfig                 |   8 +
 drivers/mfd/Makefile                |   2 +
 drivers/mfd/lochnagar-i2c.c         | 394 ++++++++++++++++++++++++++++++++++++
 include/linux/mfd/lochnagar.h       |  55 +++++
 include/linux/mfd/lochnagar1_regs.h | 157 ++++++++++++++
 include/linux/mfd/lochnagar2_regs.h | 253 +++++++++++++++++++++++
 7 files changed, 886 insertions(+)
 create mode 100644 drivers/mfd/lochnagar-i2c.c
 create mode 100644 include/linux/mfd/lochnagar.h
 create mode 100644 include/linux/mfd/lochnagar1_regs.h
 create mode 100644 include/linux/mfd/lochnagar2_regs.h

diff --git a/MAINTAINERS b/MAINTAINERS
index f4855974f325..dc60dd491757 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -3567,6 +3567,23 @@ L:	netdev@vger.kernel.org
 S:	Maintained
 F:	drivers/net/ethernet/cirrus/ep93xx_eth.c
 
+CIRRUS LOGIC LOCHNAGAR DRIVER
+M:	Charles Keepax <ckeepax@opensource.cirrus.com>
+M:	Richard Fitzgerald <rf@opensource.cirrus.com>
+L:	patches@opensource.cirrus.com
+S:	Supported
+F:	drivers/clk/clk-lochnagar.c
+F:	drivers/mfd/lochnagar-i2c.c
+F:	drivers/pinctrl/cirrus/pinctrl-lochnagar.c
+F:	drivers/regulator/lochnagar-regulator.c
+F:	include/dt-bindings/clk/lochnagar.h
+F:	include/dt-bindings/pinctrl/lochnagar.h
+F:	include/linux/mfd/lochnagar*
+F:	Documentation/devicetree/bindings/mfd/cirrus,lochnagar.txt
+F:	Documentation/devicetree/bindings/clock/cirrus,lochnagar.txt
+F:	Documentation/devicetree/bindings/pinctrl/cirrus,lochnagar.txt
+F:	Documentation/devicetree/bindings/regulator/cirrus,lochnagar.txt
+
 CISCO FCOE HBA DRIVER
 M:	Satish Kharat <satishkh@cisco.com>
 M:	Sesidhar Baddela <sebaddel@cisco.com>
diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig
index f461460a2aeb..f68ce6f38ceb 100644
--- a/drivers/mfd/Kconfig
+++ b/drivers/mfd/Kconfig
@@ -1686,6 +1686,14 @@ config MFD_VX855
 	  VIA VX855/VX875 south bridge. You will need to enable the vx855_spi
 	  and/or vx855_gpio drivers for this to do anything useful.
 
+config MFD_LOCHNAGAR
+	bool "Cirrus Logic Lochnagar Audio Development Board"
+	select MFD_CORE
+	select REGMAP_I2C
+	depends on I2C=y && OF
+	help
+	  Support for Cirrus Logic Lochnagar audio development board.
+
 config MFD_ARIZONA
 	select REGMAP
 	select REGMAP_IRQ
diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile
index 12980a4ad460..93284316d530 100644
--- a/drivers/mfd/Makefile
+++ b/drivers/mfd/Makefile
@@ -37,6 +37,8 @@ obj-$(CONFIG_MFD_T7L66XB)	+= t7l66xb.o tmio_core.o
 obj-$(CONFIG_MFD_TC6387XB)	+= tc6387xb.o tmio_core.o
 obj-$(CONFIG_MFD_TC6393XB)	+= tc6393xb.o tmio_core.o
 
+obj-$(CONFIG_MFD_LOCHNAGAR)	+= lochnagar-i2c.o
+
 obj-$(CONFIG_MFD_ARIZONA)	+= arizona-core.o
 obj-$(CONFIG_MFD_ARIZONA)	+= arizona-irq.o
 obj-$(CONFIG_MFD_ARIZONA_I2C)	+= arizona-i2c.o
diff --git a/drivers/mfd/lochnagar-i2c.c b/drivers/mfd/lochnagar-i2c.c
new file mode 100644
index 000000000000..133159d7646e
--- /dev/null
+++ b/drivers/mfd/lochnagar-i2c.c
@@ -0,0 +1,394 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Lochnagar I2C bus interface
+ *
+ * Copyright (c) 2012-2018 Cirrus Logic, Inc. and
+ *                         Cirrus Logic International Semiconductor Ltd.
+ *
+ * Author: Charles Keepax <ckeepax@opensource.cirrus.com>
+ */
+
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/err.h>
+#include <linux/gpio/consumer.h>
+#include <linux/i2c.h>
+#include <linux/lockdep.h>
+#include <linux/mfd/core.h>
+#include <linux/mutex.h>
+#include <linux/of.h>
+#include <linux/of_platform.h>
+#include <linux/regmap.h>
+
+#include <linux/mfd/lochnagar.h>
+#include <linux/mfd/lochnagar1_regs.h>
+#include <linux/mfd/lochnagar2_regs.h>
+
+#define LOCHNAGAR_BOOT_RETRIES		10
+#define LOCHNAGAR_BOOT_DELAY_MS		350
+
+#define LOCHNAGAR_CONFIG_POLL_US	10000
+
+static bool lochnagar1_readable_register(struct device *dev, unsigned int reg)
+{
+	switch (reg) {
+	case LOCHNAGAR_SOFTWARE_RESET:
+	case LOCHNAGAR_FIRMWARE_ID1...LOCHNAGAR_FIRMWARE_ID2:
+	case LOCHNAGAR1_CDC_AIF1_SEL...LOCHNAGAR1_CDC_AIF3_SEL:
+	case LOCHNAGAR1_CDC_MCLK1_SEL...LOCHNAGAR1_CDC_MCLK2_SEL:
+	case LOCHNAGAR1_CDC_AIF_CTRL1...LOCHNAGAR1_CDC_AIF_CTRL2:
+	case LOCHNAGAR1_EXT_AIF_CTRL:
+	case LOCHNAGAR1_DSP_AIF1_SEL...LOCHNAGAR1_DSP_AIF2_SEL:
+	case LOCHNAGAR1_DSP_CLKIN_SEL:
+	case LOCHNAGAR1_DSP_AIF:
+	case LOCHNAGAR1_GF_AIF1...LOCHNAGAR1_GF_AIF2:
+	case LOCHNAGAR1_PSIA_AIF:
+	case LOCHNAGAR1_PSIA1_SEL...LOCHNAGAR1_PSIA2_SEL:
+	case LOCHNAGAR1_SPDIF_AIF_SEL:
+	case LOCHNAGAR1_GF_AIF3_SEL...LOCHNAGAR1_GF_AIF4_SEL:
+	case LOCHNAGAR1_GF_CLKOUT1_SEL:
+	case LOCHNAGAR1_GF_AIF1_SEL...LOCHNAGAR1_GF_AIF2_SEL:
+	case LOCHNAGAR1_GF_GPIO2...LOCHNAGAR1_GF_GPIO7:
+	case LOCHNAGAR1_RST:
+	case LOCHNAGAR1_LED1...LOCHNAGAR1_LED2:
+	case LOCHNAGAR1_I2C_CTRL:
+		return true;
+	default:
+		return false;
+	}
+}
+
+static const struct regmap_config lochnagar1_i2c_regmap = {
+	.reg_bits = 8,
+	.val_bits = 8,
+	.reg_format_endian = REGMAP_ENDIAN_BIG,
+	.val_format_endian = REGMAP_ENDIAN_BIG,
+
+	.max_register = 0x50,
+	.readable_reg = lochnagar1_readable_register,
+
+	.use_single_read = true,
+	.use_single_write = true,
+
+	.cache_type = REGCACHE_RBTREE,
+};
+
+static const struct reg_sequence lochnagar1_patch[] = {
+	{ 0x40, 0x0083 },
+	{ 0x47, 0x0018 },
+	{ 0x50, 0x0000 },
+};
+
+static bool lochnagar2_readable_register(struct device *dev, unsigned int reg)
+{
+	switch (reg) {
+	case LOCHNAGAR_SOFTWARE_RESET:
+	case LOCHNAGAR_FIRMWARE_ID1...LOCHNAGAR_FIRMWARE_ID2:
+	case LOCHNAGAR2_CDC_AIF1_CTRL...LOCHNAGAR2_CDC_AIF3_CTRL:
+	case LOCHNAGAR2_DSP_AIF1_CTRL...LOCHNAGAR2_DSP_AIF2_CTRL:
+	case LOCHNAGAR2_PSIA1_CTRL...LOCHNAGAR2_PSIA2_CTRL:
+	case LOCHNAGAR2_GF_AIF3_CTRL...LOCHNAGAR2_GF_AIF4_CTRL:
+	case LOCHNAGAR2_GF_AIF1_CTRL...LOCHNAGAR2_GF_AIF2_CTRL:
+	case LOCHNAGAR2_SPDIF_AIF_CTRL:
+	case LOCHNAGAR2_USB_AIF1_CTRL...LOCHNAGAR2_USB_AIF2_CTRL:
+	case LOCHNAGAR2_ADAT_AIF_CTRL:
+	case LOCHNAGAR2_CDC_MCLK1_CTRL...LOCHNAGAR2_CDC_MCLK2_CTRL:
+	case LOCHNAGAR2_DSP_CLKIN_CTRL:
+	case LOCHNAGAR2_PSIA1_MCLK_CTRL...LOCHNAGAR2_PSIA2_MCLK_CTRL:
+	case LOCHNAGAR2_SPDIF_MCLK_CTRL:
+	case LOCHNAGAR2_GF_CLKOUT1_CTRL...LOCHNAGAR2_GF_CLKOUT2_CTRL:
+	case LOCHNAGAR2_ADAT_MCLK_CTRL:
+	case LOCHNAGAR2_SOUNDCARD_MCLK_CTRL:
+	case LOCHNAGAR2_GPIO_FPGA_GPIO1...LOCHNAGAR2_GPIO_FPGA_GPIO6:
+	case LOCHNAGAR2_GPIO_CDC_GPIO1...LOCHNAGAR2_GPIO_CDC_GPIO8:
+	case LOCHNAGAR2_GPIO_DSP_GPIO1...LOCHNAGAR2_GPIO_DSP_GPIO6:
+	case LOCHNAGAR2_GPIO_GF_GPIO2...LOCHNAGAR2_GPIO_GF_GPIO7:
+	case LOCHNAGAR2_GPIO_CDC_AIF1_BCLK...LOCHNAGAR2_GPIO_CDC_AIF3_TXDAT:
+	case LOCHNAGAR2_GPIO_DSP_AIF1_BCLK...LOCHNAGAR2_GPIO_DSP_AIF2_TXDAT:
+	case LOCHNAGAR2_GPIO_PSIA1_BCLK...LOCHNAGAR2_GPIO_PSIA2_TXDAT:
+	case LOCHNAGAR2_GPIO_GF_AIF3_BCLK...LOCHNAGAR2_GPIO_GF_AIF4_TXDAT:
+	case LOCHNAGAR2_GPIO_GF_AIF1_BCLK...LOCHNAGAR2_GPIO_GF_AIF2_TXDAT:
+	case LOCHNAGAR2_GPIO_DSP_UART1_RX...LOCHNAGAR2_GPIO_DSP_UART2_TX:
+	case LOCHNAGAR2_GPIO_GF_UART2_RX...LOCHNAGAR2_GPIO_GF_UART2_TX:
+	case LOCHNAGAR2_GPIO_USB_UART_RX:
+	case LOCHNAGAR2_GPIO_CDC_PDMCLK1...LOCHNAGAR2_GPIO_CDC_PDMDAT2:
+	case LOCHNAGAR2_GPIO_CDC_DMICCLK1...LOCHNAGAR2_GPIO_CDC_DMICDAT4:
+	case LOCHNAGAR2_GPIO_DSP_DMICCLK1...LOCHNAGAR2_GPIO_DSP_DMICDAT2:
+	case LOCHNAGAR2_GPIO_I2C2_SCL...LOCHNAGAR2_GPIO_I2C4_SDA:
+	case LOCHNAGAR2_GPIO_DSP_STANDBY:
+	case LOCHNAGAR2_GPIO_CDC_MCLK1...LOCHNAGAR2_GPIO_CDC_MCLK2:
+	case LOCHNAGAR2_GPIO_DSP_CLKIN:
+	case LOCHNAGAR2_GPIO_PSIA1_MCLK...LOCHNAGAR2_GPIO_PSIA2_MCLK:
+	case LOCHNAGAR2_GPIO_GF_GPIO1...LOCHNAGAR2_GPIO_GF_GPIO5:
+	case LOCHNAGAR2_GPIO_DSP_GPIO20:
+	case LOCHNAGAR2_GPIO_CHANNEL1...LOCHNAGAR2_GPIO_CHANNEL16:
+	case LOCHNAGAR2_MINICARD_RESETS:
+	case LOCHNAGAR2_ANALOGUE_PATH_CTRL1...LOCHNAGAR2_ANALOGUE_PATH_CTRL2:
+	case LOCHNAGAR2_COMMS_CTRL4:
+	case LOCHNAGAR2_SPDIF_CTRL:
+	case LOCHNAGAR2_POWER_CTRL:
+	case LOCHNAGAR2_MICVDD_CTRL1:
+	case LOCHNAGAR2_MICVDD_CTRL2:
+	case LOCHNAGAR2_VDDCORE_CDC_CTRL1:
+	case LOCHNAGAR2_VDDCORE_CDC_CTRL2:
+	case LOCHNAGAR2_SOUNDCARD_AIF_CTRL:
+		return true;
+	default:
+		return false;
+	}
+}
+
+static bool lochnagar2_volatile_register(struct device *dev, unsigned int reg)
+{
+	switch (reg) {
+	case LOCHNAGAR2_GPIO_CHANNEL1...LOCHNAGAR2_GPIO_CHANNEL16:
+	case LOCHNAGAR2_ANALOGUE_PATH_CTRL1:
+		return true;
+	default:
+		return false;
+	}
+}
+
+static const struct regmap_config lochnagar2_i2c_regmap = {
+	.reg_bits = 16,
+	.val_bits = 16,
+	.reg_format_endian = REGMAP_ENDIAN_BIG,
+	.val_format_endian = REGMAP_ENDIAN_BIG,
+
+	.max_register = 0x1F1F,
+	.readable_reg = lochnagar2_readable_register,
+	.volatile_reg = lochnagar2_volatile_register,
+
+	.cache_type = REGCACHE_RBTREE,
+};
+
+static const struct reg_sequence lochnagar2_patch[] = {
+	{ 0x00EE, 0x0000 },
+};
+
+struct lochnagar_config {
+	int id;
+	const char * const name;
+	enum lochnagar_type type;
+	const struct regmap_config *regmap;
+	const struct reg_sequence *patch;
+	int npatch;
+};
+
+static struct lochnagar_config lochnagar_configs[] = {
+	{
+		.id = 0x50,
+		.name = "lochnagar1",
+		.type = LOCHNAGAR1,
+		.regmap = &lochnagar1_i2c_regmap,
+		.patch = lochnagar1_patch,
+		.npatch = ARRAY_SIZE(lochnagar1_patch),
+	},
+	{
+		.id = 0xCB58,
+		.name = "lochnagar2",
+		.type = LOCHNAGAR2,
+		.regmap = &lochnagar2_i2c_regmap,
+		.patch = lochnagar2_patch,
+		.npatch = ARRAY_SIZE(lochnagar2_patch),
+	},
+};
+
+static const struct of_device_id lochnagar_of_match[] = {
+	{ .compatible = "cirrus,lochnagar1", .data = &lochnagar_configs[0] },
+	{ .compatible = "cirrus,lochnagar2", .data = &lochnagar_configs[1] },
+	{},
+};
+
+static int lochnagar_wait_for_boot(struct regmap *regmap, unsigned int *id)
+{
+	int i, ret;
+
+	for (i = 0; i < LOCHNAGAR_BOOT_RETRIES; ++i) {
+		msleep(LOCHNAGAR_BOOT_DELAY_MS);
+
+		/* The reset register will return the device ID when read */
+		ret = regmap_read(regmap, LOCHNAGAR_SOFTWARE_RESET, id);
+		if (!ret)
+			return ret;
+	}
+
+	return -ETIMEDOUT;
+}
+
+/**
+ * lochnagar_update_config - Synchronise the boards analogue configuration to
+ *                           the hardware.
+ *
+ * @lochnagar: A pointer to the primary core data structure.
+ *
+ * Return: Zero on success or an appropriate negative error code on failure.
+ */
+int lochnagar_update_config(struct lochnagar *lochnagar)
+{
+	struct regmap *regmap = lochnagar->regmap;
+	unsigned int done = LOCHNAGAR2_ANALOGUE_PATH_UPDATE_STS_MASK;
+	int timeout_ms = LOCHNAGAR_BOOT_DELAY_MS * LOCHNAGAR_BOOT_RETRIES;
+	unsigned int val = 0;
+	int ret;
+
+	lockdep_assert_held(&lochnagar->analogue_config_lock);
+
+	if (lochnagar->type != LOCHNAGAR2)
+		return 0;
+
+	/*
+	 * Toggle the ANALOGUE_PATH_UPDATE bit and wait for the device to
+	 * acknowledge that any outstanding changes to the analogue
+	 * configuration have been applied.
+	 */
+	ret = regmap_write(regmap, LOCHNAGAR2_ANALOGUE_PATH_CTRL1, 0);
+	if (ret < 0)
+		return ret;
+
+	ret = regmap_write(regmap, LOCHNAGAR2_ANALOGUE_PATH_CTRL1,
+			   LOCHNAGAR2_ANALOGUE_PATH_UPDATE_MASK);
+	if (ret < 0)
+		return ret;
+
+	ret = regmap_read_poll_timeout(regmap,
+				       LOCHNAGAR2_ANALOGUE_PATH_CTRL1, val,
+				       (val & done), LOCHNAGAR_CONFIG_POLL_US,
+				       timeout_ms * 1000);
+	if (ret < 0)
+		return ret;
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(lochnagar_update_config);
+
+static int lochnagar_i2c_probe(struct i2c_client *i2c)
+{
+	struct device *dev = &i2c->dev;
+	const struct lochnagar_config *config = NULL;
+	const struct of_device_id *of_id;
+	struct lochnagar *lochnagar;
+	struct gpio_desc *reset, *present;
+	unsigned int val;
+	unsigned int firmwareid;
+	unsigned int devid, rev;
+	int ret;
+
+	lochnagar = devm_kzalloc(dev, sizeof(*lochnagar), GFP_KERNEL);
+	if (!lochnagar)
+		return -ENOMEM;
+
+	of_id = of_match_device(lochnagar_of_match, dev);
+	if (!of_id)
+		return -EINVAL;
+
+	config = of_id->data;
+
+	lochnagar->dev = dev;
+	mutex_init(&lochnagar->analogue_config_lock);
+
+	dev_set_drvdata(dev, lochnagar);
+
+	reset = devm_gpiod_get(dev, "reset", GPIOD_OUT_LOW);
+	if (IS_ERR(reset)) {
+		ret = PTR_ERR(reset);
+		dev_err(dev, "Failed to get reset GPIO: %d\n", ret);
+		return ret;
+	}
+
+	present = devm_gpiod_get_optional(dev, "present", GPIOD_OUT_HIGH);
+	if (IS_ERR(present)) {
+		ret = PTR_ERR(present);
+		dev_err(dev, "Failed to get present GPIO: %d\n", ret);
+		return ret;
+	}
+
+	/* Leave the Lochnagar in reset for a reasonable amount of time */
+	msleep(20);
+
+	/* Bring Lochnagar out of reset */
+	gpiod_set_value_cansleep(reset, 1);
+
+	/* Identify Lochnagar */
+	lochnagar->type = config->type;
+
+	lochnagar->regmap = devm_regmap_init_i2c(i2c, config->regmap);
+	if (IS_ERR(lochnagar->regmap)) {
+		ret = PTR_ERR(lochnagar->regmap);
+		dev_err(dev, "Failed to allocate register map: %d\n", ret);
+		return ret;
+	}
+
+	/* Wait for Lochnagar to boot */
+	ret = lochnagar_wait_for_boot(lochnagar->regmap, &val);
+	if (ret < 0) {
+		dev_err(dev, "Failed to read device ID: %d\n", ret);
+		return ret;
+	}
+
+	devid = val & LOCHNAGAR_DEVICE_ID_MASK;
+	rev = val & LOCHNAGAR_REV_ID_MASK;
+
+	if (devid != config->id) {
+		dev_err(dev,
+			"ID does not match %s (expected 0x%x got 0x%x)\n",
+			config->name, config->id, devid);
+		return -ENODEV;
+	}
+
+	/* Identify firmware */
+	ret = regmap_read(lochnagar->regmap, LOCHNAGAR_FIRMWARE_ID1, &val);
+	if (ret < 0) {
+		dev_err(dev, "Failed to read firmware id 1: %d\n", ret);
+		return ret;
+	}
+
+	firmwareid = val;
+
+	ret = regmap_read(lochnagar->regmap, LOCHNAGAR_FIRMWARE_ID2, &val);
+	if (ret < 0) {
+		dev_err(dev, "Failed to read firmware id 2: %d\n", ret);
+		return ret;
+	}
+
+	firmwareid |= (val << config->regmap->val_bits);
+
+	dev_info(dev, "Found %s (0x%x) revision %u firmware 0x%.6x\n",
+		 config->name, devid, rev + 1, firmwareid);
+
+	ret = regmap_register_patch(lochnagar->regmap, config->patch,
+				    config->npatch);
+	if (ret < 0) {
+		dev_err(dev, "Failed to register patch: %d\n", ret);
+		return ret;
+	}
+
+	ret = devm_of_platform_populate(dev);
+	if (ret < 0) {
+		dev_err(dev, "Failed to populate child nodes: %d\n", ret);
+		return ret;
+	}
+
+	return ret;
+}
+
+static struct i2c_driver lochnagar_i2c_driver = {
+	.driver = {
+		.name = "lochnagar",
+		.of_match_table = of_match_ptr(lochnagar_of_match),
+		.suppress_bind_attrs = true,
+	},
+	.probe_new = lochnagar_i2c_probe,
+};
+
+static int __init lochnagar_i2c_init(void)
+{
+	int ret;
+
+	ret = i2c_add_driver(&lochnagar_i2c_driver);
+	if (ret)
+		pr_err("Failed to register Lochnagar driver: %d\n", ret);
+
+	return ret;
+}
+subsys_initcall(lochnagar_i2c_init);
diff --git a/include/linux/mfd/lochnagar.h b/include/linux/mfd/lochnagar.h
new file mode 100644
index 000000000000..ff9e64cfc9fb
--- /dev/null
+++ b/include/linux/mfd/lochnagar.h
@@ -0,0 +1,55 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Lochnagar internals
+ *
+ * Copyright (c) 2013-2018 Cirrus Logic, Inc. and
+ *                         Cirrus Logic International Semiconductor Ltd.
+ *
+ * Author: Charles Keepax <ckeepax@opensource.cirrus.com>
+ */
+
+#include <linux/device.h>
+#include <linux/mutex.h>
+#include <linux/regmap.h>
+
+#ifndef CIRRUS_LOCHNAGAR_H
+#define CIRRUS_LOCHNAGAR_H
+
+enum lochnagar_type {
+	LOCHNAGAR1,
+	LOCHNAGAR2,
+};
+
+/**
+ * struct lochnagar - Core data for the Lochnagar audio board driver.
+ *
+ * @type: The type of Lochnagar device connected.
+ * @dev: A pointer to the struct device for the main MFD.
+ * @regmap: The devices main register map.
+ * @analogue_config_lock: Lock used to protect updates in the analogue
+ * configuration as these must not be changed whilst the hardware is processing
+ * the last update.
+ */
+struct lochnagar {
+	enum lochnagar_type type;
+	struct device *dev;
+	struct regmap *regmap;
+
+	/* Lock to protect updates to the analogue configuration */
+	struct mutex analogue_config_lock;
+};
+
+/* Register Addresses */
+#define LOCHNAGAR_SOFTWARE_RESET                             0x00
+#define LOCHNAGAR_FIRMWARE_ID1                               0x01
+#define LOCHNAGAR_FIRMWARE_ID2                               0x02
+
+/* (0x0000)  Software Reset */
+#define LOCHNAGAR_DEVICE_ID_MASK                           0xFFFC
+#define LOCHNAGAR_DEVICE_ID_SHIFT                               2
+#define LOCHNAGAR_REV_ID_MASK                              0x0003
+#define LOCHNAGAR_REV_ID_SHIFT                                  0
+
+int lochnagar_update_config(struct lochnagar *lochnagar);
+
+#endif
diff --git a/include/linux/mfd/lochnagar1_regs.h b/include/linux/mfd/lochnagar1_regs.h
new file mode 100644
index 000000000000..114b846245d9
--- /dev/null
+++ b/include/linux/mfd/lochnagar1_regs.h
@@ -0,0 +1,157 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Lochnagar1 register definitions
+ *
+ * Copyright (c) 2017-2018 Cirrus Logic, Inc. and
+ *                         Cirrus Logic International Semiconductor Ltd.
+ *
+ * Author: Charles Keepax <ckeepax@opensource.cirrus.com>
+ */
+
+#ifndef LOCHNAGAR1_REGISTERS_H
+#define LOCHNAGAR1_REGISTERS_H
+
+/* Register Addresses */
+#define LOCHNAGAR1_CDC_AIF1_SEL                       0x0008
+#define LOCHNAGAR1_CDC_AIF2_SEL                       0x0009
+#define LOCHNAGAR1_CDC_AIF3_SEL                       0x000A
+#define LOCHNAGAR1_CDC_MCLK1_SEL                      0x000B
+#define LOCHNAGAR1_CDC_MCLK2_SEL                      0x000C
+#define LOCHNAGAR1_CDC_AIF_CTRL1                      0x000D
+#define LOCHNAGAR1_CDC_AIF_CTRL2                      0x000E
+#define LOCHNAGAR1_EXT_AIF_CTRL                       0x000F
+#define LOCHNAGAR1_DSP_AIF1_SEL                       0x0010
+#define LOCHNAGAR1_DSP_AIF2_SEL                       0x0011
+#define LOCHNAGAR1_DSP_CLKIN_SEL                      0x0012
+#define LOCHNAGAR1_DSP_AIF                            0x0013
+#define LOCHNAGAR1_GF_AIF1                            0x0014
+#define LOCHNAGAR1_GF_AIF2                            0x0015
+#define LOCHNAGAR1_PSIA_AIF                           0x0016
+#define LOCHNAGAR1_PSIA1_SEL                          0x0017
+#define LOCHNAGAR1_PSIA2_SEL                          0x0018
+#define LOCHNAGAR1_SPDIF_AIF_SEL                      0x0019
+#define LOCHNAGAR1_GF_AIF3_SEL                        0x001C
+#define LOCHNAGAR1_GF_AIF4_SEL                        0x001D
+#define LOCHNAGAR1_GF_CLKOUT1_SEL                     0x001E
+#define LOCHNAGAR1_GF_AIF1_SEL                        0x001F
+#define LOCHNAGAR1_GF_AIF2_SEL                        0x0020
+#define LOCHNAGAR1_GF_GPIO2                           0x0026
+#define LOCHNAGAR1_GF_GPIO3                           0x0027
+#define LOCHNAGAR1_GF_GPIO7                           0x0028
+#define LOCHNAGAR1_RST                                0x0029
+#define LOCHNAGAR1_LED1                               0x002A
+#define LOCHNAGAR1_LED2                               0x002B
+#define LOCHNAGAR1_I2C_CTRL                           0x0046
+
+/*
+ * (0x0008 - 0x000C, 0x0010 - 0x0012, 0x0017 - 0x0020)
+ * CDC_AIF1_SEL - GF_AIF2_SEL
+ */
+#define LOCHNAGAR1_SRC_MASK                             0xFF
+#define LOCHNAGAR1_SRC_SHIFT                               0
+
+/* (0x000D)  CDC_AIF_CTRL1 */
+#define LOCHNAGAR1_CDC_AIF2_LRCLK_DIR_MASK              0x40
+#define LOCHNAGAR1_CDC_AIF2_LRCLK_DIR_SHIFT                6
+#define LOCHNAGAR1_CDC_AIF2_BCLK_DIR_MASK               0x20
+#define LOCHNAGAR1_CDC_AIF2_BCLK_DIR_SHIFT                 5
+#define LOCHNAGAR1_CDC_AIF2_ENA_MASK                    0x10
+#define LOCHNAGAR1_CDC_AIF2_ENA_SHIFT                      4
+#define LOCHNAGAR1_CDC_AIF1_LRCLK_DIR_MASK              0x04
+#define LOCHNAGAR1_CDC_AIF1_LRCLK_DIR_SHIFT                2
+#define LOCHNAGAR1_CDC_AIF1_BCLK_DIR_MASK               0x02
+#define LOCHNAGAR1_CDC_AIF1_BCLK_DIR_SHIFT                 1
+#define LOCHNAGAR1_CDC_AIF1_ENA_MASK                    0x01
+#define LOCHNAGAR1_CDC_AIF1_ENA_SHIFT                      0
+
+/* (0x000E)  CDC_AIF_CTRL2 */
+#define LOCHNAGAR1_CDC_AIF3_LRCLK_DIR_MASK              0x40
+#define LOCHNAGAR1_CDC_AIF3_LRCLK_DIR_SHIFT                6
+#define LOCHNAGAR1_CDC_AIF3_BCLK_DIR_MASK               0x20
+#define LOCHNAGAR1_CDC_AIF3_BCLK_DIR_SHIFT                 5
+#define LOCHNAGAR1_CDC_AIF3_ENA_MASK                    0x10
+#define LOCHNAGAR1_CDC_AIF3_ENA_SHIFT                      4
+#define LOCHNAGAR1_CDC_MCLK1_ENA_MASK                   0x02
+#define LOCHNAGAR1_CDC_MCLK1_ENA_SHIFT                     1
+#define LOCHNAGAR1_CDC_MCLK2_ENA_MASK                   0x01
+#define LOCHNAGAR1_CDC_MCLK2_ENA_SHIFT                     0
+
+/* (0x000F)  EXT_AIF_CTRL */
+#define LOCHNAGAR1_SPDIF_AIF_LRCLK_DIR_MASK             0x20
+#define LOCHNAGAR1_SPDIF_AIF_LRCLK_DIR_SHIFT               5
+#define LOCHNAGAR1_SPDIF_AIF_BCLK_DIR_MASK              0x10
+#define LOCHNAGAR1_SPDIF_AIF_BCLK_DIR_SHIFT                4
+#define LOCHNAGAR1_SPDIF_AIF_ENA_MASK                   0x08
+#define LOCHNAGAR1_SPDIF_AIF_ENA_SHIFT                     3
+
+/* (0x0013)  DSP_AIF */
+#define LOCHNAGAR1_DSP_AIF2_LRCLK_DIR_MASK              0x40
+#define LOCHNAGAR1_DSP_AIF2_LRCLK_DIR_SHIFT                6
+#define LOCHNAGAR1_DSP_AIF2_BCLK_DIR_MASK               0x20
+#define LOCHNAGAR1_DSP_AIF2_BCLK_DIR_SHIFT                 5
+#define LOCHNAGAR1_DSP_AIF2_ENA_MASK                    0x10
+#define LOCHNAGAR1_DSP_AIF2_ENA_SHIFT                      4
+#define LOCHNAGAR1_DSP_CLKIN_ENA_MASK                   0x08
+#define LOCHNAGAR1_DSP_CLKIN_ENA_SHIFT                     3
+#define LOCHNAGAR1_DSP_AIF1_LRCLK_DIR_MASK              0x04
+#define LOCHNAGAR1_DSP_AIF1_LRCLK_DIR_SHIFT                2
+#define LOCHNAGAR1_DSP_AIF1_BCLK_DIR_MASK               0x02
+#define LOCHNAGAR1_DSP_AIF1_BCLK_DIR_SHIFT                 1
+#define LOCHNAGAR1_DSP_AIF1_ENA_MASK                    0x01
+#define LOCHNAGAR1_DSP_AIF1_ENA_SHIFT                      0
+
+/* (0x0014)  GF_AIF1 */
+#define LOCHNAGAR1_GF_CLKOUT1_ENA_MASK                  0x40
+#define LOCHNAGAR1_GF_CLKOUT1_ENA_SHIFT                    6
+#define LOCHNAGAR1_GF_AIF3_LRCLK_DIR_MASK               0x20
+#define LOCHNAGAR1_GF_AIF3_LRCLK_DIR_SHIFT                 5
+#define LOCHNAGAR1_GF_AIF3_BCLK_DIR_MASK                0x10
+#define LOCHNAGAR1_GF_AIF3_BCLK_DIR_SHIFT                  4
+#define LOCHNAGAR1_GF_AIF3_ENA_MASK                     0x08
+#define LOCHNAGAR1_GF_AIF3_ENA_SHIFT                       3
+#define LOCHNAGAR1_GF_AIF1_LRCLK_DIR_MASK               0x04
+#define LOCHNAGAR1_GF_AIF1_LRCLK_DIR_SHIFT                 2
+#define LOCHNAGAR1_GF_AIF1_BCLK_DIR_MASK                0x02
+#define LOCHNAGAR1_GF_AIF1_BCLK_DIR_SHIFT                  1
+#define LOCHNAGAR1_GF_AIF1_ENA_MASK                     0x01
+#define LOCHNAGAR1_GF_AIF1_ENA_SHIFT                       0
+
+/* (0x0015)  GF_AIF2 */
+#define LOCHNAGAR1_GF_AIF4_LRCLK_DIR_MASK               0x20
+#define LOCHNAGAR1_GF_AIF4_LRCLK_DIR_SHIFT                 5
+#define LOCHNAGAR1_GF_AIF4_BCLK_DIR_MASK                0x10
+#define LOCHNAGAR1_GF_AIF4_BCLK_DIR_SHIFT                  4
+#define LOCHNAGAR1_GF_AIF4_ENA_MASK                     0x08
+#define LOCHNAGAR1_GF_AIF4_ENA_SHIFT                       3
+#define LOCHNAGAR1_GF_AIF2_LRCLK_DIR_MASK               0x04
+#define LOCHNAGAR1_GF_AIF2_LRCLK_DIR_SHIFT                 2
+#define LOCHNAGAR1_GF_AIF2_BCLK_DIR_MASK                0x02
+#define LOCHNAGAR1_GF_AIF2_BCLK_DIR_SHIFT                  1
+#define LOCHNAGAR1_GF_AIF2_ENA_MASK                     0x01
+#define LOCHNAGAR1_GF_AIF2_ENA_SHIFT                       0
+
+/* (0x0016)  PSIA_AIF */
+#define LOCHNAGAR1_PSIA2_LRCLK_DIR_MASK                 0x40
+#define LOCHNAGAR1_PSIA2_LRCLK_DIR_SHIFT                   6
+#define LOCHNAGAR1_PSIA2_BCLK_DIR_MASK                  0x20
+#define LOCHNAGAR1_PSIA2_BCLK_DIR_SHIFT                    5
+#define LOCHNAGAR1_PSIA2_ENA_MASK                       0x10
+#define LOCHNAGAR1_PSIA2_ENA_SHIFT                         4
+#define LOCHNAGAR1_PSIA1_LRCLK_DIR_MASK                 0x04
+#define LOCHNAGAR1_PSIA1_LRCLK_DIR_SHIFT                   2
+#define LOCHNAGAR1_PSIA1_BCLK_DIR_MASK                  0x02
+#define LOCHNAGAR1_PSIA1_BCLK_DIR_SHIFT                    1
+#define LOCHNAGAR1_PSIA1_ENA_MASK                       0x01
+#define LOCHNAGAR1_PSIA1_ENA_SHIFT                         0
+
+/* (0x0029)  RST */
+#define LOCHNAGAR1_DSP_RESET_MASK                       0x02
+#define LOCHNAGAR1_DSP_RESET_SHIFT                         1
+#define LOCHNAGAR1_CDC_RESET_MASK                       0x01
+#define LOCHNAGAR1_CDC_RESET_SHIFT                         0
+
+/* (0x0046)  I2C_CTRL */
+#define LOCHNAGAR1_CDC_CIF_MODE_MASK                    0x01
+#define LOCHNAGAR1_CDC_CIF_MODE_SHIFT                      0
+
+#endif
diff --git a/include/linux/mfd/lochnagar2_regs.h b/include/linux/mfd/lochnagar2_regs.h
new file mode 100644
index 000000000000..2c6340c3006b
--- /dev/null
+++ b/include/linux/mfd/lochnagar2_regs.h
@@ -0,0 +1,253 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Lochnagar2 register definitions
+ *
+ * Copyright (c) 2017-2018 Cirrus Logic, Inc. and
+ *                         Cirrus Logic International Semiconductor Ltd.
+ *
+ * Author: Charles Keepax <ckeepax@opensource.cirrus.com>
+ */
+
+#ifndef LOCHNAGAR2_REGISTERS_H
+#define LOCHNAGAR2_REGISTERS_H
+
+/* Register Addresses */
+#define LOCHNAGAR2_CDC_AIF1_CTRL                      0x000D
+#define LOCHNAGAR2_CDC_AIF2_CTRL                      0x000E
+#define LOCHNAGAR2_CDC_AIF3_CTRL                      0x000F
+#define LOCHNAGAR2_DSP_AIF1_CTRL                      0x0010
+#define LOCHNAGAR2_DSP_AIF2_CTRL                      0x0011
+#define LOCHNAGAR2_PSIA1_CTRL                         0x0012
+#define LOCHNAGAR2_PSIA2_CTRL                         0x0013
+#define LOCHNAGAR2_GF_AIF3_CTRL                       0x0014
+#define LOCHNAGAR2_GF_AIF4_CTRL                       0x0015
+#define LOCHNAGAR2_GF_AIF1_CTRL                       0x0016
+#define LOCHNAGAR2_GF_AIF2_CTRL                       0x0017
+#define LOCHNAGAR2_SPDIF_AIF_CTRL                     0x0018
+#define LOCHNAGAR2_USB_AIF1_CTRL                      0x0019
+#define LOCHNAGAR2_USB_AIF2_CTRL                      0x001A
+#define LOCHNAGAR2_ADAT_AIF_CTRL                      0x001B
+#define LOCHNAGAR2_CDC_MCLK1_CTRL                     0x001E
+#define LOCHNAGAR2_CDC_MCLK2_CTRL                     0x001F
+#define LOCHNAGAR2_DSP_CLKIN_CTRL                     0x0020
+#define LOCHNAGAR2_PSIA1_MCLK_CTRL                    0x0021
+#define LOCHNAGAR2_PSIA2_MCLK_CTRL                    0x0022
+#define LOCHNAGAR2_SPDIF_MCLK_CTRL                    0x0023
+#define LOCHNAGAR2_GF_CLKOUT1_CTRL                    0x0024
+#define LOCHNAGAR2_GF_CLKOUT2_CTRL                    0x0025
+#define LOCHNAGAR2_ADAT_MCLK_CTRL                     0x0026
+#define LOCHNAGAR2_SOUNDCARD_MCLK_CTRL                0x0027
+#define LOCHNAGAR2_GPIO_FPGA_GPIO1                    0x0031
+#define LOCHNAGAR2_GPIO_FPGA_GPIO2                    0x0032
+#define LOCHNAGAR2_GPIO_FPGA_GPIO3                    0x0033
+#define LOCHNAGAR2_GPIO_FPGA_GPIO4                    0x0034
+#define LOCHNAGAR2_GPIO_FPGA_GPIO5                    0x0035
+#define LOCHNAGAR2_GPIO_FPGA_GPIO6                    0x0036
+#define LOCHNAGAR2_GPIO_CDC_GPIO1                     0x0037
+#define LOCHNAGAR2_GPIO_CDC_GPIO2                     0x0038
+#define LOCHNAGAR2_GPIO_CDC_GPIO3                     0x0039
+#define LOCHNAGAR2_GPIO_CDC_GPIO4                     0x003A
+#define LOCHNAGAR2_GPIO_CDC_GPIO5                     0x003B
+#define LOCHNAGAR2_GPIO_CDC_GPIO6                     0x003C
+#define LOCHNAGAR2_GPIO_CDC_GPIO7                     0x003D
+#define LOCHNAGAR2_GPIO_CDC_GPIO8                     0x003E
+#define LOCHNAGAR2_GPIO_DSP_GPIO1                     0x003F
+#define LOCHNAGAR2_GPIO_DSP_GPIO2                     0x0040
+#define LOCHNAGAR2_GPIO_DSP_GPIO3                     0x0041
+#define LOCHNAGAR2_GPIO_DSP_GPIO4                     0x0042
+#define LOCHNAGAR2_GPIO_DSP_GPIO5                     0x0043
+#define LOCHNAGAR2_GPIO_DSP_GPIO6                     0x0044
+#define LOCHNAGAR2_GPIO_GF_GPIO2                      0x0045
+#define LOCHNAGAR2_GPIO_GF_GPIO3                      0x0046
+#define LOCHNAGAR2_GPIO_GF_GPIO7                      0x0047
+#define LOCHNAGAR2_GPIO_CDC_AIF1_BCLK                 0x0048
+#define LOCHNAGAR2_GPIO_CDC_AIF1_RXDAT                0x0049
+#define LOCHNAGAR2_GPIO_CDC_AIF1_LRCLK                0x004A
+#define LOCHNAGAR2_GPIO_CDC_AIF1_TXDAT                0x004B
+#define LOCHNAGAR2_GPIO_CDC_AIF2_BCLK                 0x004C
+#define LOCHNAGAR2_GPIO_CDC_AIF2_RXDAT                0x004D
+#define LOCHNAGAR2_GPIO_CDC_AIF2_LRCLK                0x004E
+#define LOCHNAGAR2_GPIO_CDC_AIF2_TXDAT                0x004F
+#define LOCHNAGAR2_GPIO_CDC_AIF3_BCLK                 0x0050
+#define LOCHNAGAR2_GPIO_CDC_AIF3_RXDAT                0x0051
+#define LOCHNAGAR2_GPIO_CDC_AIF3_LRCLK                0x0052
+#define LOCHNAGAR2_GPIO_CDC_AIF3_TXDAT                0x0053
+#define LOCHNAGAR2_GPIO_DSP_AIF1_BCLK                 0x0054
+#define LOCHNAGAR2_GPIO_DSP_AIF1_RXDAT                0x0055
+#define LOCHNAGAR2_GPIO_DSP_AIF1_LRCLK                0x0056
+#define LOCHNAGAR2_GPIO_DSP_AIF1_TXDAT                0x0057
+#define LOCHNAGAR2_GPIO_DSP_AIF2_BCLK                 0x0058
+#define LOCHNAGAR2_GPIO_DSP_AIF2_RXDAT                0x0059
+#define LOCHNAGAR2_GPIO_DSP_AIF2_LRCLK                0x005A
+#define LOCHNAGAR2_GPIO_DSP_AIF2_TXDAT                0x005B
+#define LOCHNAGAR2_GPIO_PSIA1_BCLK                    0x005C
+#define LOCHNAGAR2_GPIO_PSIA1_RXDAT                   0x005D
+#define LOCHNAGAR2_GPIO_PSIA1_LRCLK                   0x005E
+#define LOCHNAGAR2_GPIO_PSIA1_TXDAT                   0x005F
+#define LOCHNAGAR2_GPIO_PSIA2_BCLK                    0x0060
+#define LOCHNAGAR2_GPIO_PSIA2_RXDAT                   0x0061
+#define LOCHNAGAR2_GPIO_PSIA2_LRCLK                   0x0062
+#define LOCHNAGAR2_GPIO_PSIA2_TXDAT                   0x0063
+#define LOCHNAGAR2_GPIO_GF_AIF3_BCLK                  0x0064
+#define LOCHNAGAR2_GPIO_GF_AIF3_RXDAT                 0x0065
+#define LOCHNAGAR2_GPIO_GF_AIF3_LRCLK                 0x0066
+#define LOCHNAGAR2_GPIO_GF_AIF3_TXDAT                 0x0067
+#define LOCHNAGAR2_GPIO_GF_AIF4_BCLK                  0x0068
+#define LOCHNAGAR2_GPIO_GF_AIF4_RXDAT                 0x0069
+#define LOCHNAGAR2_GPIO_GF_AIF4_LRCLK                 0x006A
+#define LOCHNAGAR2_GPIO_GF_AIF4_TXDAT                 0x006B
+#define LOCHNAGAR2_GPIO_GF_AIF1_BCLK                  0x006C
+#define LOCHNAGAR2_GPIO_GF_AIF1_RXDAT                 0x006D
+#define LOCHNAGAR2_GPIO_GF_AIF1_LRCLK                 0x006E
+#define LOCHNAGAR2_GPIO_GF_AIF1_TXDAT                 0x006F
+#define LOCHNAGAR2_GPIO_GF_AIF2_BCLK                  0x0070
+#define LOCHNAGAR2_GPIO_GF_AIF2_RXDAT                 0x0071
+#define LOCHNAGAR2_GPIO_GF_AIF2_LRCLK                 0x0072
+#define LOCHNAGAR2_GPIO_GF_AIF2_TXDAT                 0x0073
+#define LOCHNAGAR2_GPIO_DSP_UART1_RX                  0x0074
+#define LOCHNAGAR2_GPIO_DSP_UART1_TX                  0x0075
+#define LOCHNAGAR2_GPIO_DSP_UART2_RX                  0x0076
+#define LOCHNAGAR2_GPIO_DSP_UART2_TX                  0x0077
+#define LOCHNAGAR2_GPIO_GF_UART2_RX                   0x0078
+#define LOCHNAGAR2_GPIO_GF_UART2_TX                   0x0079
+#define LOCHNAGAR2_GPIO_USB_UART_RX                   0x007A
+#define LOCHNAGAR2_GPIO_CDC_PDMCLK1                   0x007C
+#define LOCHNAGAR2_GPIO_CDC_PDMDAT1                   0x007D
+#define LOCHNAGAR2_GPIO_CDC_PDMCLK2                   0x007E
+#define LOCHNAGAR2_GPIO_CDC_PDMDAT2                   0x007F
+#define LOCHNAGAR2_GPIO_CDC_DMICCLK1                  0x0080
+#define LOCHNAGAR2_GPIO_CDC_DMICDAT1                  0x0081
+#define LOCHNAGAR2_GPIO_CDC_DMICCLK2                  0x0082
+#define LOCHNAGAR2_GPIO_CDC_DMICDAT2                  0x0083
+#define LOCHNAGAR2_GPIO_CDC_DMICCLK3                  0x0084
+#define LOCHNAGAR2_GPIO_CDC_DMICDAT3                  0x0085
+#define LOCHNAGAR2_GPIO_CDC_DMICCLK4                  0x0086
+#define LOCHNAGAR2_GPIO_CDC_DMICDAT4                  0x0087
+#define LOCHNAGAR2_GPIO_DSP_DMICCLK1                  0x0088
+#define LOCHNAGAR2_GPIO_DSP_DMICDAT1                  0x0089
+#define LOCHNAGAR2_GPIO_DSP_DMICCLK2                  0x008A
+#define LOCHNAGAR2_GPIO_DSP_DMICDAT2                  0x008B
+#define LOCHNAGAR2_GPIO_I2C2_SCL                      0x008C
+#define LOCHNAGAR2_GPIO_I2C2_SDA                      0x008D
+#define LOCHNAGAR2_GPIO_I2C3_SCL                      0x008E
+#define LOCHNAGAR2_GPIO_I2C3_SDA                      0x008F
+#define LOCHNAGAR2_GPIO_I2C4_SCL                      0x0090
+#define LOCHNAGAR2_GPIO_I2C4_SDA                      0x0091
+#define LOCHNAGAR2_GPIO_DSP_STANDBY                   0x0092
+#define LOCHNAGAR2_GPIO_CDC_MCLK1                     0x0093
+#define LOCHNAGAR2_GPIO_CDC_MCLK2                     0x0094
+#define LOCHNAGAR2_GPIO_DSP_CLKIN                     0x0095
+#define LOCHNAGAR2_GPIO_PSIA1_MCLK                    0x0096
+#define LOCHNAGAR2_GPIO_PSIA2_MCLK                    0x0097
+#define LOCHNAGAR2_GPIO_GF_GPIO1                      0x0098
+#define LOCHNAGAR2_GPIO_GF_GPIO5                      0x0099
+#define LOCHNAGAR2_GPIO_DSP_GPIO20                    0x009A
+#define LOCHNAGAR2_GPIO_CHANNEL1                      0x00B9
+#define LOCHNAGAR2_GPIO_CHANNEL2                      0x00BA
+#define LOCHNAGAR2_GPIO_CHANNEL3                      0x00BB
+#define LOCHNAGAR2_GPIO_CHANNEL4                      0x00BC
+#define LOCHNAGAR2_GPIO_CHANNEL5                      0x00BD
+#define LOCHNAGAR2_GPIO_CHANNEL6                      0x00BE
+#define LOCHNAGAR2_GPIO_CHANNEL7                      0x00BF
+#define LOCHNAGAR2_GPIO_CHANNEL8                      0x00C0
+#define LOCHNAGAR2_GPIO_CHANNEL9                      0x00C1
+#define LOCHNAGAR2_GPIO_CHANNEL10                     0x00C2
+#define LOCHNAGAR2_GPIO_CHANNEL11                     0x00C3
+#define LOCHNAGAR2_GPIO_CHANNEL12                     0x00C4
+#define LOCHNAGAR2_GPIO_CHANNEL13                     0x00C5
+#define LOCHNAGAR2_GPIO_CHANNEL14                     0x00C6
+#define LOCHNAGAR2_GPIO_CHANNEL15                     0x00C7
+#define LOCHNAGAR2_GPIO_CHANNEL16                     0x00C8
+#define LOCHNAGAR2_MINICARD_RESETS                    0x00DF
+#define LOCHNAGAR2_ANALOGUE_PATH_CTRL1                0x00E3
+#define LOCHNAGAR2_ANALOGUE_PATH_CTRL2                0x00E4
+#define LOCHNAGAR2_COMMS_CTRL4                        0x00F0
+#define LOCHNAGAR2_SPDIF_CTRL                         0x00FE
+#define LOCHNAGAR2_POWER_CTRL                         0x0116
+#define LOCHNAGAR2_MICVDD_CTRL1                       0x0119
+#define LOCHNAGAR2_MICVDD_CTRL2                       0x011B
+#define LOCHNAGAR2_VDDCORE_CDC_CTRL1                  0x011E
+#define LOCHNAGAR2_VDDCORE_CDC_CTRL2                  0x0120
+#define LOCHNAGAR2_SOUNDCARD_AIF_CTRL                 0x0180
+
+/* (0x000D-0x001B, 0x0180)  CDC_AIF1_CTRL - SOUNCARD_AIF_CTRL */
+#define LOCHNAGAR2_AIF_ENA_MASK                       0x8000
+#define LOCHNAGAR2_AIF_ENA_SHIFT                          15
+#define LOCHNAGAR2_AIF_LRCLK_DIR_MASK                 0x4000
+#define LOCHNAGAR2_AIF_LRCLK_DIR_SHIFT                    14
+#define LOCHNAGAR2_AIF_BCLK_DIR_MASK                  0x2000
+#define LOCHNAGAR2_AIF_BCLK_DIR_SHIFT                     13
+#define LOCHNAGAR2_AIF_SRC_MASK                       0x00FF
+#define LOCHNAGAR2_AIF_SRC_SHIFT                           0
+
+/* (0x001E - 0x0027)  CDC_MCLK1_CTRL - SOUNDCARD_MCLK_CTRL */
+#define LOCHNAGAR2_CLK_ENA_MASK                       0x8000
+#define LOCHNAGAR2_CLK_ENA_SHIFT                          15
+#define LOCHNAGAR2_CLK_DIR_MASK                       0x4000
+#define LOCHNAGAR2_CLK_DIR_SHIFT                          14
+#define LOCHNAGAR2_CLK_SRC_MASK                       0x00FF
+#define LOCHNAGAR2_CLK_SRC_SHIFT                           0
+
+/* (0x0031 - 0x009A)  GPIO_FPGA_GPIO1 - GPIO_DSP_GPIO20 */
+#define LOCHNAGAR2_GPIO_SRC_MASK                      0x00FF
+#define LOCHNAGAR2_GPIO_SRC_SHIFT                          0
+
+/* (0x00B9 - 0x00C8)  GPIO_CHANNEL1 - GPIO_CHANNEL16 */
+#define LOCHNAGAR2_GPIO_CHANNEL_STS_MASK              0x8000
+#define LOCHNAGAR2_GPIO_CHANNEL_STS_SHIFT                 15
+#define LOCHNAGAR2_GPIO_CHANNEL_SRC_MASK              0x00FF
+#define LOCHNAGAR2_GPIO_CHANNEL_SRC_SHIFT                  0
+
+/* (0x00DF)  MINICARD_RESETS */
+#define LOCHNAGAR2_DSP_RESET_MASK                     0x0002
+#define LOCHNAGAR2_DSP_RESET_SHIFT                         1
+#define LOCHNAGAR2_CDC_RESET_MASK                     0x0001
+#define LOCHNAGAR2_CDC_RESET_SHIFT                         0
+
+/* (0x00E3)  ANALOGUE_PATH_CTRL1 */
+#define LOCHNAGAR2_ANALOGUE_PATH_UPDATE_MASK          0x8000
+#define LOCHNAGAR2_ANALOGUE_PATH_UPDATE_SHIFT             15
+#define LOCHNAGAR2_ANALOGUE_PATH_UPDATE_STS_MASK      0x4000
+#define LOCHNAGAR2_ANALOGUE_PATH_UPDATE_STS_SHIFT         14
+
+/* (0x00E4)  ANALOGUE_PATH_CTRL2 */
+#define LOCHNAGAR2_P2_INPUT_BIAS_ENA_MASK             0x0080
+#define LOCHNAGAR2_P2_INPUT_BIAS_ENA_SHIFT                 7
+#define LOCHNAGAR2_P1_INPUT_BIAS_ENA_MASK             0x0040
+#define LOCHNAGAR2_P1_INPUT_BIAS_ENA_SHIFT                 6
+#define LOCHNAGAR2_P2_MICBIAS_SRC_MASK                0x0038
+#define LOCHNAGAR2_P2_MICBIAS_SRC_SHIFT                    3
+#define LOCHNAGAR2_P1_MICBIAS_SRC_MASK                0x0007
+#define LOCHNAGAR2_P1_MICBIAS_SRC_SHIFT                    0
+
+/* (0x00F0)  COMMS_CTRL4 */
+#define LOCHNAGAR2_CDC_CIF1MODE_MASK                  0x0001
+#define LOCHNAGAR2_CDC_CIF1MODE_SHIFT                      0
+
+/* (0x00FE)  SPDIF_CTRL */
+#define LOCHNAGAR2_SPDIF_HWMODE_MASK                  0x0008
+#define LOCHNAGAR2_SPDIF_HWMODE_SHIFT                      3
+#define LOCHNAGAR2_SPDIF_RESET_MASK                   0x0001
+#define LOCHNAGAR2_SPDIF_RESET_SHIFT                       0
+
+/* (0x0116)  POWER_CTRL */
+#define LOCHNAGAR2_PWR_ENA_MASK                       0x0001
+#define LOCHNAGAR2_PWR_ENA_SHIFT                           0
+
+/* (0x0119)  MICVDD_CTRL1 */
+#define LOCHNAGAR2_MICVDD_REG_ENA_MASK                0x8000
+#define LOCHNAGAR2_MICVDD_REG_ENA_SHIFT                   15
+
+/* (0x011B)  MICVDD_CTRL2 */
+#define LOCHNAGAR2_MICVDD_VSEL_MASK                   0x001F
+#define LOCHNAGAR2_MICVDD_VSEL_SHIFT                       0
+
+/* (0x011E)  VDDCORE_CDC_CTRL1 */
+#define LOCHNAGAR2_VDDCORE_CDC_REG_ENA_MASK           0x8000
+#define LOCHNAGAR2_VDDCORE_CDC_REG_ENA_SHIFT              15
+
+/* (0x0120)  VDDCORE_CDC_CTRL2 */
+#define LOCHNAGAR2_VDDCORE_CDC_VSEL_MASK              0x007F
+#define LOCHNAGAR2_VDDCORE_CDC_VSEL_SHIFT                  0
+
+#endif
-- 
2.11.0


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

* [PATCH v5 7/8] clk: lochnagar: Add support for the Cirrus Logic Lochnagar
  2018-11-20 14:16 [PATCH v5 1/8] regulator: lochnagar: Move driver to binding from DT Charles Keepax
                   ` (4 preceding siblings ...)
  2018-11-20 14:16 ` [PATCH v5 6/8] mfd: lochnagar: Add support for the Cirrus Logic Lochnagar Charles Keepax
@ 2018-11-20 14:16 ` Charles Keepax
  2018-11-30  7:53   ` Stephen Boyd
  2018-11-20 14:16 ` [PATCH v5 8/8] pinctrl: " Charles Keepax
  6 siblings, 1 reply; 21+ messages in thread
From: Charles Keepax @ 2018-11-20 14:16 UTC (permalink / raw)
  To: lee.jones, mturquette, sboyd, broonie, linus.walleij, robh+dt
  Cc: mark.rutland, lgirdwood, devicetree, linux-kernel, patches,
	linux-clk, linux-gpio

Lochnagar is an evaluation and development board for Cirrus
Logic Smart CODEC and Amp devices. It allows the connection of
most Cirrus Logic devices on mini-cards, as well as allowing
connection of various application processor systems to provide a
full evaluation platform. This driver supports the board
controller chip on the Lochnagar board.

The Lochnagar can take several input clocks from the host system,
provides several of its own clock sources, and provides extensive
routing options for those clocks to be supplied to the attached
CODEC/Amp device.

Signed-off-by: Charles Keepax <ckeepax@opensource.cirrus.com>
---

No change since v4.

Thanks,
Charles

 drivers/clk/Kconfig         |   7 +
 drivers/clk/Makefile        |   1 +
 drivers/clk/clk-lochnagar.c | 360 ++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 368 insertions(+)
 create mode 100644 drivers/clk/clk-lochnagar.c

diff --git a/drivers/clk/Kconfig b/drivers/clk/Kconfig
index 81cdb4eaca07..2c63c431879f 100644
--- a/drivers/clk/Kconfig
+++ b/drivers/clk/Kconfig
@@ -219,6 +219,13 @@ config COMMON_CLK_XGENE
 	---help---
 	  Sypport for the APM X-Gene SoC reference, PLL, and device clocks.
 
+config COMMON_CLK_LOCHNAGAR
+	tristate "Cirrus Logic Lochnagar clock driver"
+	depends on MFD_LOCHNAGAR
+	help
+	  This driver supports the clocking features of the Cirrus Logic
+	  Lochnagar audio development board.
+
 config COMMON_CLK_NXP
 	def_bool COMMON_CLK && (ARCH_LPC18XX || ARCH_LPC32XX)
 	select REGMAP_MMIO if ARCH_LPC32XX
diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile
index 72be7a38cff1..2354f0c8c8f1 100644
--- a/drivers/clk/Makefile
+++ b/drivers/clk/Makefile
@@ -30,6 +30,7 @@ obj-$(CONFIG_COMMON_CLK_GEMINI)		+= clk-gemini.o
 obj-$(CONFIG_COMMON_CLK_ASPEED)		+= clk-aspeed.o
 obj-$(CONFIG_ARCH_HIGHBANK)		+= clk-highbank.o
 obj-$(CONFIG_CLK_HSDK)			+= clk-hsdk-pll.o
+obj-$(CONFIG_COMMON_CLK_LOCHNAGAR)	+= clk-lochnagar.o
 obj-$(CONFIG_COMMON_CLK_MAX77686)	+= clk-max77686.o
 obj-$(CONFIG_COMMON_CLK_MAX9485)	+= clk-max9485.o
 obj-$(CONFIG_ARCH_MOXART)		+= clk-moxart.o
diff --git a/drivers/clk/clk-lochnagar.c b/drivers/clk/clk-lochnagar.c
new file mode 100644
index 000000000000..8b2a78689715
--- /dev/null
+++ b/drivers/clk/clk-lochnagar.c
@@ -0,0 +1,360 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Lochnagar clock control
+ *
+ * Copyright (c) 2017-2018 Cirrus Logic, Inc. and
+ *                         Cirrus Logic International Semiconductor Ltd.
+ *
+ * Author: Charles Keepax <ckeepax@opensource.cirrus.com>
+ */
+
+#include <linux/clk-provider.h>
+#include <linux/device.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+
+#include <linux/mfd/lochnagar.h>
+#include <linux/mfd/lochnagar1_regs.h>
+#include <linux/mfd/lochnagar2_regs.h>
+
+#include <dt-bindings/clk/lochnagar.h>
+
+#define LOCHNAGAR_NUM_CLOCKS	(LOCHNAGAR_SPDIF_CLKOUT + 1)
+
+struct lochnagar_clk {
+	const char * const name;
+	struct clk_hw hw;
+
+	struct lochnagar_clk_priv *priv;
+
+	u16 cfg_reg;
+	u16 ena_mask;
+	u16 dir_mask; /* Control bit to set clock as a source or sink */
+
+	u16 src_reg;
+	u16 src_mask;
+};
+
+struct lochnagar_clk_priv {
+	struct device *dev;
+	struct regmap *regmap;
+	enum lochnagar_type type;
+
+	const char **parents;
+	unsigned int nparents;
+
+	struct lochnagar_clk lclks[LOCHNAGAR_NUM_CLOCKS];
+
+	struct clk_hw_onecell_data *clk_data;
+};
+
+static const char * const lochnagar1_clk_parents[] = {
+	"ln-none",
+	"ln-spdif-mclk",
+	"ln-psia1-mclk",
+	"ln-psia2-mclk",
+	"ln-cdc-clkout",
+	"ln-dsp-clkout",
+	"ln-pmic-32k",
+	"ln-gf-mclk1",
+	"ln-gf-mclk3",
+	"ln-gf-mclk2",
+	"ln-gf-mclk4",
+};
+
+static const char * const lochnagar2_clk_parents[] = {
+	"ln-none",
+	"ln-cdc-clkout",
+	"ln-dsp-clkout",
+	"ln-pmic-32k",
+	"ln-spdif-mclk",
+	"ln-clk-12m",
+	"ln-clk-11m",
+	"ln-clk-24m",
+	"ln-clk-22m",
+	"ln-reserved",
+	"ln-usb-clk-24m",
+	"ln-gf-mclk1",
+	"ln-gf-mclk3",
+	"ln-gf-mclk2",
+	"ln-psia1-mclk",
+	"ln-psia2-mclk",
+	"ln-spdif-clkout",
+	"ln-adat-clkout",
+	"ln-usb-clk-12m",
+};
+
+#define LN1_CLK(ID, NAME, REG) \
+	[LOCHNAGAR_##ID] = { \
+		.name = NAME, \
+		.cfg_reg = LOCHNAGAR1_##REG, \
+		.ena_mask = LOCHNAGAR1_##ID##_ENA_MASK, \
+		.src_reg = LOCHNAGAR1_##ID##_SEL, \
+		.src_mask = LOCHNAGAR1_SRC_MASK, \
+	}
+
+#define LN2_CLK(ID, NAME) \
+	[LOCHNAGAR_##ID] = { \
+		.name = NAME, \
+		.cfg_reg = LOCHNAGAR2_##ID##_CTRL, \
+		.src_reg = LOCHNAGAR2_##ID##_CTRL, \
+		.ena_mask = LOCHNAGAR2_CLK_ENA_MASK, \
+		.dir_mask = LOCHNAGAR2_CLK_DIR_MASK, \
+		.src_mask = LOCHNAGAR2_CLK_SRC_MASK, \
+	}
+
+static const struct lochnagar_clk lochnagar1_clks[LOCHNAGAR_NUM_CLOCKS] = {
+	LN1_CLK(CDC_MCLK1,      "ln-cdc-mclk1",  CDC_AIF_CTRL2),
+	LN1_CLK(CDC_MCLK2,      "ln-cdc-mclk2",  CDC_AIF_CTRL2),
+	LN1_CLK(DSP_CLKIN,      "ln-dsp-clkin",  DSP_AIF),
+	LN1_CLK(GF_CLKOUT1,     "ln-gf-clkout1", GF_AIF1),
+};
+
+static const struct lochnagar_clk lochnagar2_clks[LOCHNAGAR_NUM_CLOCKS] = {
+	LN2_CLK(CDC_MCLK1,      "ln-cdc-mclk1"),
+	LN2_CLK(CDC_MCLK2,      "ln-cdc-mclk2"),
+	LN2_CLK(DSP_CLKIN,      "ln-dsp-clkin"),
+	LN2_CLK(GF_CLKOUT1,     "ln-gf-clkout1"),
+	LN2_CLK(GF_CLKOUT2,     "ln-gf-clkout2"),
+	LN2_CLK(PSIA1_MCLK,     "ln-psia1-mclk"),
+	LN2_CLK(PSIA2_MCLK,     "ln-psia2-mclk"),
+	LN2_CLK(SPDIF_MCLK,     "ln-spdif-mclk"),
+	LN2_CLK(ADAT_MCLK,      "ln-adat-mclk"),
+	LN2_CLK(SOUNDCARD_MCLK, "ln-soundcard-mclk"),
+};
+
+static inline struct lochnagar_clk *lochnagar_hw_to_lclk(struct clk_hw *hw)
+{
+	return container_of(hw, struct lochnagar_clk, hw);
+}
+
+static int lochnagar_regmap_prepare(struct clk_hw *hw)
+{
+	struct lochnagar_clk *lclk = lochnagar_hw_to_lclk(hw);
+	struct lochnagar_clk_priv *priv = lclk->priv;
+	struct regmap *regmap = priv->regmap;
+	int ret;
+
+	ret = regmap_update_bits(regmap, lclk->cfg_reg,
+				 lclk->ena_mask, lclk->ena_mask);
+	if (ret < 0)
+		dev_err(priv->dev, "Failed to prepare %s: %d\n",
+			lclk->name, ret);
+
+	return ret;
+}
+
+static void lochnagar_regmap_unprepare(struct clk_hw *hw)
+{
+	struct lochnagar_clk *lclk = lochnagar_hw_to_lclk(hw);
+	struct lochnagar_clk_priv *priv = lclk->priv;
+	struct regmap *regmap = priv->regmap;
+	int ret;
+
+	ret = regmap_update_bits(regmap, lclk->cfg_reg, lclk->ena_mask, 0);
+	if (ret < 0)
+		dev_err(priv->dev, "Failed to unprepare %s: %d\n",
+			lclk->name, ret);
+}
+
+static int lochnagar_regmap_set_parent(struct clk_hw *hw, u8 index)
+{
+	struct lochnagar_clk *lclk = lochnagar_hw_to_lclk(hw);
+	struct lochnagar_clk_priv *priv = lclk->priv;
+	struct regmap *regmap = priv->regmap;
+	int ret;
+
+	/*
+	 * Some clocks on Lochnagar can either generate a clock themselves
+	 * or accept an external clock, these default to generating the clock
+	 * themselves. If we set a parent however we should update the dir_mask
+	 * to indicate to the hardware that this clock will now be receiving an
+	 * external clock.
+	 */
+	if (lclk->dir_mask) {
+		ret = regmap_update_bits(regmap, lclk->cfg_reg,
+					 lclk->dir_mask, lclk->dir_mask);
+		if (ret < 0) {
+			dev_err(priv->dev, "Failed to set %s direction: %d\n",
+				lclk->name, ret);
+			return ret;
+		}
+	}
+
+	ret = regmap_update_bits(regmap, lclk->src_reg, lclk->src_mask, index);
+	if (ret < 0)
+		dev_err(priv->dev, "Failed to reparent %s: %d\n",
+			lclk->name, ret);
+
+	return ret;
+}
+
+static u8 lochnagar_regmap_get_parent(struct clk_hw *hw)
+{
+	struct lochnagar_clk *lclk = lochnagar_hw_to_lclk(hw);
+	struct lochnagar_clk_priv *priv = lclk->priv;
+	struct regmap *regmap = priv->regmap;
+	unsigned int val;
+	int ret;
+
+	ret = regmap_read(regmap, lclk->src_reg, &val);
+	if (ret < 0) {
+		dev_err(priv->dev, "Failed to read parent of %s: %d\n",
+			lclk->name, ret);
+		return priv->nparents;
+	}
+
+	val &= lclk->src_mask;
+
+	return val;
+}
+
+static const struct clk_ops lochnagar_clk_regmap_ops = {
+	.prepare = lochnagar_regmap_prepare,
+	.unprepare = lochnagar_regmap_unprepare,
+	.set_parent = lochnagar_regmap_set_parent,
+	.get_parent = lochnagar_regmap_get_parent,
+};
+
+static int lochnagar_init_parents(struct lochnagar_clk_priv *priv)
+{
+	struct device_node *np = priv->dev->of_node;
+	int i, j;
+
+	switch (priv->type) {
+	case LOCHNAGAR1:
+		memcpy(priv->lclks, lochnagar1_clks, sizeof(lochnagar1_clks));
+
+		priv->nparents = ARRAY_SIZE(lochnagar1_clk_parents);
+		priv->parents = devm_kmemdup(priv->dev, lochnagar1_clk_parents,
+					     sizeof(lochnagar1_clk_parents),
+					     GFP_KERNEL);
+		break;
+	case LOCHNAGAR2:
+		memcpy(priv->lclks, lochnagar2_clks, sizeof(lochnagar2_clks));
+
+		priv->nparents = ARRAY_SIZE(lochnagar2_clk_parents);
+		priv->parents = devm_kmemdup(priv->dev, lochnagar2_clk_parents,
+					     sizeof(lochnagar2_clk_parents),
+					     GFP_KERNEL);
+		break;
+	default:
+		dev_err(priv->dev, "Unknown Lochnagar type: %d\n", priv->type);
+		return -EINVAL;
+	}
+
+	if (!priv->parents)
+		return -ENOMEM;
+
+	for (i = 0; i < priv->nparents; i++) {
+		j = of_property_match_string(np, "clock-names",
+					     priv->parents[i]);
+		if (j >= 0)
+			priv->parents[i] = of_clk_get_parent_name(np, j);
+	}
+
+	return 0;
+}
+
+static int lochnagar_init_clks(struct lochnagar_clk_priv *priv)
+{
+	struct clk_init_data clk_init = {
+		.ops = &lochnagar_clk_regmap_ops,
+		.parent_names = priv->parents,
+		.num_parents = priv->nparents,
+	};
+	struct lochnagar_clk *lclk;
+	int ret, i;
+
+	for (i = 0; i < ARRAY_SIZE(priv->lclks); i++) {
+		lclk = &priv->lclks[i];
+
+		if (!lclk->name)
+			continue;
+
+		clk_init.name = lclk->name;
+
+		lclk->priv = priv;
+		lclk->hw.init = &clk_init;
+
+		ret = devm_clk_hw_register(priv->dev, &lclk->hw);
+		if (ret) {
+			dev_err(priv->dev, "Failed to register %s: %d\n",
+				lclk->name, ret);
+			return ret;
+		}
+
+		priv->clk_data->hws[i] = &lclk->hw;
+	}
+
+	priv->clk_data->num = ARRAY_SIZE(priv->lclks);
+
+	ret = devm_of_clk_add_hw_provider(priv->dev, of_clk_hw_onecell_get,
+					  priv->clk_data);
+	if (ret < 0) {
+		dev_err(priv->dev, "Failed to register provider: %d\n", ret);
+		return ret;
+	}
+
+	return 0;
+}
+
+static const struct of_device_id lochnagar_of_match[] = {
+	{ .compatible = "cirrus,lochnagar1-clk", .data = (void *)LOCHNAGAR1 },
+	{ .compatible = "cirrus,lochnagar2-clk", .data = (void *)LOCHNAGAR2 },
+	{},
+};
+
+static int lochnagar_clk_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct lochnagar_clk_priv *priv;
+	const struct of_device_id *of_id;
+	int ret;
+
+	of_id = of_match_device(lochnagar_of_match, dev);
+	if (!of_id)
+		return -EINVAL;
+
+	priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
+	if (!priv)
+		return -ENOMEM;
+
+	priv->clk_data = devm_kzalloc(dev, struct_size(priv->clk_data, hws,
+						       ARRAY_SIZE(priv->lclks)),
+				      GFP_KERNEL);
+	if (!priv->clk_data)
+		return -ENOMEM;
+
+	priv->dev = dev;
+	priv->regmap = dev_get_regmap(dev->parent, NULL);
+	priv->type = (enum lochnagar_type)of_id->data;
+
+	ret = lochnagar_init_parents(priv);
+	if (ret)
+		return ret;
+
+	ret = lochnagar_init_clks(priv);
+	if (ret)
+		return ret;
+
+	return 0;
+}
+
+static struct platform_driver lochnagar_clk_driver = {
+	.driver = {
+		.name = "lochnagar-clk",
+		.of_match_table = of_match_ptr(lochnagar_of_match),
+	},
+
+	.probe = lochnagar_clk_probe,
+};
+module_platform_driver(lochnagar_clk_driver);
+
+MODULE_AUTHOR("Charles Keepax <ckeepax@opensource.cirrus.com>");
+MODULE_DESCRIPTION("Clock driver for Cirrus Logic Lochnagar Board");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:lochnagar-clk");
-- 
2.11.0


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

* [PATCH v5 8/8] pinctrl: lochnagar: Add support for the Cirrus Logic Lochnagar
  2018-11-20 14:16 [PATCH v5 1/8] regulator: lochnagar: Move driver to binding from DT Charles Keepax
                   ` (5 preceding siblings ...)
  2018-11-20 14:16 ` [PATCH v5 7/8] clk: " Charles Keepax
@ 2018-11-20 14:16 ` Charles Keepax
  2018-11-24 16:11   ` kbuild test robot
  6 siblings, 1 reply; 21+ messages in thread
From: Charles Keepax @ 2018-11-20 14:16 UTC (permalink / raw)
  To: lee.jones, mturquette, sboyd, broonie, linus.walleij, robh+dt
  Cc: mark.rutland, lgirdwood, devicetree, linux-kernel, patches,
	linux-clk, linux-gpio

Lochnagar is an evaluation and development board for Cirrus
Logic Smart CODEC and Amp devices. It allows the connection of
most Cirrus Logic devices on mini-cards, as well as allowing
connection of various application processor systems to provide a
full evaluation platform. This driver supports the board
controller chip on the Lochnagar board.

Lochnagar provides many pins which can generally be used for an
audio function such as an AIF or a PDM interface, but also as
GPIOs.

Reviewed-by: Linus Walleij <linus.walleij@linaro.org>
Signed-off-by: Charles Keepax <ckeepax@opensource.cirrus.com>
---

Changes since v4:
 - Removed pinctrl-lochnagar.h and moved its contents into the source
   file
 - Removed template chip and just set values directly

Thanks,
Charles

 drivers/pinctrl/cirrus/Kconfig             |   10 +
 drivers/pinctrl/cirrus/Makefile            |    2 +
 drivers/pinctrl/cirrus/pinctrl-lochnagar.c | 1236 ++++++++++++++++++++++++++++
 3 files changed, 1248 insertions(+)
 create mode 100644 drivers/pinctrl/cirrus/pinctrl-lochnagar.c

diff --git a/drivers/pinctrl/cirrus/Kconfig b/drivers/pinctrl/cirrus/Kconfig
index 27013e5949bc..74af07e25174 100644
--- a/drivers/pinctrl/cirrus/Kconfig
+++ b/drivers/pinctrl/cirrus/Kconfig
@@ -1,3 +1,13 @@
+config PINCTRL_LOCHNAGAR
+	tristate "Cirrus Logic Lochnagar pinctrl driver"
+	depends on MFD_LOCHNAGAR
+	select PINMUX
+	select PINCONF
+	select GENERIC_PINCONF
+	help
+	  This driver supports configuring the GPIO and other pin configuration
+	  of the Cirrus Logic Lochnagar audio development board.
+
 # This is all selected by the Madera MFD driver Kconfig options
 config PINCTRL_MADERA
 	tristate
diff --git a/drivers/pinctrl/cirrus/Makefile b/drivers/pinctrl/cirrus/Makefile
index 6e4938cde9e3..20baebf438f6 100644
--- a/drivers/pinctrl/cirrus/Makefile
+++ b/drivers/pinctrl/cirrus/Makefile
@@ -1,4 +1,6 @@
 # Cirrus Logic pinctrl drivers
+obj-$(CONFIG_PINCTRL_LOCHNAGAR)	+= pinctrl-lochnagar.o
+
 pinctrl-madera-objs		:= pinctrl-madera-core.o
 ifeq ($(CONFIG_PINCTRL_CS47L35),y)
 pinctrl-madera-objs		+= pinctrl-cs47l35.o
diff --git a/drivers/pinctrl/cirrus/pinctrl-lochnagar.c b/drivers/pinctrl/cirrus/pinctrl-lochnagar.c
new file mode 100644
index 000000000000..35d40200e432
--- /dev/null
+++ b/drivers/pinctrl/cirrus/pinctrl-lochnagar.c
@@ -0,0 +1,1236 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Lochnagar pin and GPIO control
+ *
+ * Copyright (c) 2017-2018 Cirrus Logic, Inc. and
+ *                         Cirrus Logic International Semiconductor Ltd.
+ *
+ * Author: Charles Keepax <ckeepax@opensource.cirrus.com>
+ */
+
+#include <linux/err.h>
+#include <linux/errno.h>
+#include <linux/gpio/driver.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+#include <linux/pinctrl/pinctrl.h>
+#include <linux/pinctrl/pinmux.h>
+#include <linux/pinctrl/pinconf.h>
+#include <linux/pinctrl/pinconf-generic.h>
+
+#include <linux/mfd/lochnagar.h>
+#include <linux/mfd/lochnagar1_regs.h>
+#include <linux/mfd/lochnagar2_regs.h>
+
+#include <dt-bindings/pinctrl/lochnagar.h>
+
+#include "../pinctrl-utils.h"
+
+#define LN2_NUM_GPIO_CHANNELS	16
+
+#define LN_CDC_AIF1_STR		"codec-aif1"
+#define LN_CDC_AIF2_STR		"codec-aif2"
+#define LN_CDC_AIF3_STR		"codec-aif3"
+#define LN_DSP_AIF1_STR		"dsp-aif1"
+#define LN_DSP_AIF2_STR		"dsp-aif2"
+#define LN_PSIA1_STR		"psia1"
+#define LN_PSIA2_STR		"psia2"
+#define LN_GF_AIF1_STR		"gf-aif1"
+#define LN_GF_AIF2_STR		"gf-aif2"
+#define LN_GF_AIF3_STR		"gf-aif3"
+#define LN_GF_AIF4_STR		"gf-aif4"
+#define LN_SPDIF_AIF_STR	"spdif-aif"
+#define LN_USB_AIF1_STR		"usb-aif1"
+#define LN_USB_AIF2_STR		"usb-aif2"
+#define LN_ADAT_AIF_STR		"adat-aif"
+#define LN_SOUNDCARD_AIF_STR	"soundcard-aif"
+
+#define LN_PIN_GPIO(REV, ID, NAME, REG, SHIFT, INVERT) \
+static const struct lochnagar_pin lochnagar##REV##_##ID##_pin = { \
+	.name = NAME, .type = LN_PTYPE_GPIO, .reg = LOCHNAGAR##REV##_##REG, \
+	.shift = LOCHNAGAR##REV##_##SHIFT##_SHIFT, .invert = INVERT, \
+}
+
+#define LN_PIN_SAIF(REV, ID, NAME) \
+static const struct lochnagar_pin lochnagar##REV##_##ID##_pin = \
+	{ .name = NAME, .type = LN_PTYPE_AIF, }
+
+#define LN_PIN_AIF(REV, ID) \
+	LN_PIN_SAIF(REV, ID##_BCLK,  LN_##ID##_STR"-bclk"); \
+	LN_PIN_SAIF(REV, ID##_LRCLK, LN_##ID##_STR"-lrclk"); \
+	LN_PIN_SAIF(REV, ID##_RXDAT, LN_##ID##_STR"-rxdat"); \
+	LN_PIN_SAIF(REV, ID##_TXDAT, LN_##ID##_STR"-txdat")
+
+#define LN1_PIN_GPIO(ID, NAME, REG, SHIFT, INVERT) \
+	LN_PIN_GPIO(1, ID, NAME, REG, SHIFT, INVERT)
+
+#define LN1_PIN_MUX(ID, NAME) \
+static const struct lochnagar_pin lochnagar1_##ID##_pin = \
+	{ .name = NAME, .type = LN_PTYPE_MUX, .reg = LOCHNAGAR1_##ID, }
+
+#define LN1_PIN_AIF(ID) LN_PIN_AIF(1, ID)
+
+#define LN2_PIN_GPIO(ID, NAME, REG, SHIFT, INVERT) \
+	LN_PIN_GPIO(2, ID, NAME, REG, SHIFT, INVERT)
+
+#define LN2_PIN_MUX(ID, NAME) \
+static const struct lochnagar_pin lochnagar2_##ID##_pin = \
+	{ .name = NAME, .type = LN_PTYPE_MUX, .reg = LOCHNAGAR2_GPIO_##ID, }
+
+#define LN2_PIN_AIF(ID) LN_PIN_AIF(2, ID)
+
+#define LN2_PIN_GAI(ID) \
+	LN2_PIN_MUX(ID##_BCLK,  LN_##ID##_STR"-bclk"); \
+	LN2_PIN_MUX(ID##_LRCLK, LN_##ID##_STR"-lrclk"); \
+	LN2_PIN_MUX(ID##_RXDAT, LN_##ID##_STR"-rxdat"); \
+	LN2_PIN_MUX(ID##_TXDAT, LN_##ID##_STR"-txdat")
+
+#define LN_PIN(REV, ID) [LOCHNAGAR##REV##_PIN_##ID] = { \
+	.number = LOCHNAGAR##REV##_PIN_##ID, \
+	.name = lochnagar##REV##_##ID##_pin.name, \
+	.drv_data = (void *)&lochnagar##REV##_##ID##_pin, \
+}
+
+#define LN1_PIN(ID) LN_PIN(1, ID)
+#define LN2_PIN(ID) LN_PIN(2, ID)
+
+#define LN_PINS(REV, ID) \
+	LN_PIN(REV, ID##_BCLK), LN_PIN(REV, ID##_LRCLK), \
+	LN_PIN(REV, ID##_RXDAT), LN_PIN(REV, ID##_TXDAT)
+
+#define LN1_PINS(ID) LN_PINS(1, ID)
+#define LN2_PINS(ID) LN_PINS(2, ID)
+
+enum {
+	LOCHNAGAR1_PIN_GF_GPIO2 = LOCHNAGAR1_PIN_NUM_GPIOS,
+	LOCHNAGAR1_PIN_GF_GPIO3,
+	LOCHNAGAR1_PIN_GF_GPIO7,
+	LOCHNAGAR1_PIN_LED1,
+	LOCHNAGAR1_PIN_LED2,
+	LOCHNAGAR1_PIN_CDC_AIF1_BCLK,
+	LOCHNAGAR1_PIN_CDC_AIF1_LRCLK,
+	LOCHNAGAR1_PIN_CDC_AIF1_RXDAT,
+	LOCHNAGAR1_PIN_CDC_AIF1_TXDAT,
+	LOCHNAGAR1_PIN_CDC_AIF2_BCLK,
+	LOCHNAGAR1_PIN_CDC_AIF2_LRCLK,
+	LOCHNAGAR1_PIN_CDC_AIF2_RXDAT,
+	LOCHNAGAR1_PIN_CDC_AIF2_TXDAT,
+	LOCHNAGAR1_PIN_CDC_AIF3_BCLK,
+	LOCHNAGAR1_PIN_CDC_AIF3_LRCLK,
+	LOCHNAGAR1_PIN_CDC_AIF3_RXDAT,
+	LOCHNAGAR1_PIN_CDC_AIF3_TXDAT,
+	LOCHNAGAR1_PIN_DSP_AIF1_BCLK,
+	LOCHNAGAR1_PIN_DSP_AIF1_LRCLK,
+	LOCHNAGAR1_PIN_DSP_AIF1_RXDAT,
+	LOCHNAGAR1_PIN_DSP_AIF1_TXDAT,
+	LOCHNAGAR1_PIN_DSP_AIF2_BCLK,
+	LOCHNAGAR1_PIN_DSP_AIF2_LRCLK,
+	LOCHNAGAR1_PIN_DSP_AIF2_RXDAT,
+	LOCHNAGAR1_PIN_DSP_AIF2_TXDAT,
+	LOCHNAGAR1_PIN_PSIA1_BCLK,
+	LOCHNAGAR1_PIN_PSIA1_LRCLK,
+	LOCHNAGAR1_PIN_PSIA1_RXDAT,
+	LOCHNAGAR1_PIN_PSIA1_TXDAT,
+	LOCHNAGAR1_PIN_PSIA2_BCLK,
+	LOCHNAGAR1_PIN_PSIA2_LRCLK,
+	LOCHNAGAR1_PIN_PSIA2_RXDAT,
+	LOCHNAGAR1_PIN_PSIA2_TXDAT,
+	LOCHNAGAR1_PIN_SPDIF_AIF_BCLK,
+	LOCHNAGAR1_PIN_SPDIF_AIF_LRCLK,
+	LOCHNAGAR1_PIN_SPDIF_AIF_RXDAT,
+	LOCHNAGAR1_PIN_SPDIF_AIF_TXDAT,
+	LOCHNAGAR1_PIN_GF_AIF3_BCLK,
+	LOCHNAGAR1_PIN_GF_AIF3_RXDAT,
+	LOCHNAGAR1_PIN_GF_AIF3_LRCLK,
+	LOCHNAGAR1_PIN_GF_AIF3_TXDAT,
+	LOCHNAGAR1_PIN_GF_AIF4_BCLK,
+	LOCHNAGAR1_PIN_GF_AIF4_RXDAT,
+	LOCHNAGAR1_PIN_GF_AIF4_LRCLK,
+	LOCHNAGAR1_PIN_GF_AIF4_TXDAT,
+	LOCHNAGAR1_PIN_GF_AIF1_BCLK,
+	LOCHNAGAR1_PIN_GF_AIF1_RXDAT,
+	LOCHNAGAR1_PIN_GF_AIF1_LRCLK,
+	LOCHNAGAR1_PIN_GF_AIF1_TXDAT,
+	LOCHNAGAR1_PIN_GF_AIF2_BCLK,
+	LOCHNAGAR1_PIN_GF_AIF2_RXDAT,
+	LOCHNAGAR1_PIN_GF_AIF2_LRCLK,
+	LOCHNAGAR1_PIN_GF_AIF2_TXDAT,
+
+	LOCHNAGAR2_PIN_SPDIF_AIF_BCLK = LOCHNAGAR2_PIN_NUM_GPIOS,
+	LOCHNAGAR2_PIN_SPDIF_AIF_LRCLK,
+	LOCHNAGAR2_PIN_SPDIF_AIF_RXDAT,
+	LOCHNAGAR2_PIN_SPDIF_AIF_TXDAT,
+	LOCHNAGAR2_PIN_USB_AIF1_BCLK,
+	LOCHNAGAR2_PIN_USB_AIF1_LRCLK,
+	LOCHNAGAR2_PIN_USB_AIF1_RXDAT,
+	LOCHNAGAR2_PIN_USB_AIF1_TXDAT,
+	LOCHNAGAR2_PIN_USB_AIF2_BCLK,
+	LOCHNAGAR2_PIN_USB_AIF2_LRCLK,
+	LOCHNAGAR2_PIN_USB_AIF2_RXDAT,
+	LOCHNAGAR2_PIN_USB_AIF2_TXDAT,
+	LOCHNAGAR2_PIN_ADAT_AIF_BCLK,
+	LOCHNAGAR2_PIN_ADAT_AIF_LRCLK,
+	LOCHNAGAR2_PIN_ADAT_AIF_RXDAT,
+	LOCHNAGAR2_PIN_ADAT_AIF_TXDAT,
+	LOCHNAGAR2_PIN_SOUNDCARD_AIF_BCLK,
+	LOCHNAGAR2_PIN_SOUNDCARD_AIF_LRCLK,
+	LOCHNAGAR2_PIN_SOUNDCARD_AIF_RXDAT,
+	LOCHNAGAR2_PIN_SOUNDCARD_AIF_TXDAT,
+};
+
+enum lochnagar_pin_type {
+	LN_PTYPE_GPIO,
+	LN_PTYPE_MUX,
+	LN_PTYPE_AIF,
+	LN_PTYPE_COUNT,
+};
+
+struct lochnagar_pin {
+	const char name[20];
+
+	enum lochnagar_pin_type type;
+
+	unsigned int reg;
+	int shift;
+	bool invert;
+};
+
+LN1_PIN_GPIO(CDC_RESET,    "codec-reset",    RST,      CDC_RESET,    1);
+LN1_PIN_GPIO(DSP_RESET,    "dsp-reset",      RST,      DSP_RESET,    1);
+LN1_PIN_GPIO(CDC_CIF1MODE, "codec-cif1mode", I2C_CTRL, CDC_CIF_MODE, 0);
+LN1_PIN_MUX(GF_GPIO2,      "gf-gpio2");
+LN1_PIN_MUX(GF_GPIO3,      "gf-gpio3");
+LN1_PIN_MUX(GF_GPIO7,      "gf-gpio7");
+LN1_PIN_MUX(LED1,          "led1");
+LN1_PIN_MUX(LED2,          "led2");
+LN1_PIN_AIF(CDC_AIF1);
+LN1_PIN_AIF(CDC_AIF2);
+LN1_PIN_AIF(CDC_AIF3);
+LN1_PIN_AIF(DSP_AIF1);
+LN1_PIN_AIF(DSP_AIF2);
+LN1_PIN_AIF(PSIA1);
+LN1_PIN_AIF(PSIA2);
+LN1_PIN_AIF(SPDIF_AIF);
+LN1_PIN_AIF(GF_AIF1);
+LN1_PIN_AIF(GF_AIF2);
+LN1_PIN_AIF(GF_AIF3);
+LN1_PIN_AIF(GF_AIF4);
+
+LN2_PIN_GPIO(CDC_RESET,    "codec-reset",    MINICARD_RESETS, CDC_RESET,     1);
+LN2_PIN_GPIO(DSP_RESET,    "dsp-reset",      MINICARD_RESETS, DSP_RESET,     1);
+LN2_PIN_GPIO(CDC_CIF1MODE, "codec-cif1mode", COMMS_CTRL4,     CDC_CIF1MODE,  0);
+LN2_PIN_GPIO(CDC_LDOENA,   "codec-ldoena",   POWER_CTRL,      PWR_ENA,       0);
+LN2_PIN_GPIO(SPDIF_HWMODE, "spdif-hwmode",   SPDIF_CTRL,      SPDIF_HWMODE,  0);
+LN2_PIN_GPIO(SPDIF_RESET,  "spdif-reset",    SPDIF_CTRL,      SPDIF_RESET,   1);
+LN2_PIN_MUX(FPGA_GPIO1,    "fgpa-gpio1");
+LN2_PIN_MUX(FPGA_GPIO2,    "fgpa-gpio2");
+LN2_PIN_MUX(FPGA_GPIO3,    "fgpa-gpio3");
+LN2_PIN_MUX(FPGA_GPIO4,    "fgpa-gpio4");
+LN2_PIN_MUX(FPGA_GPIO5,    "fgpa-gpio5");
+LN2_PIN_MUX(FPGA_GPIO6,    "fgpa-gpio6");
+LN2_PIN_MUX(CDC_GPIO1,     "codec-gpio1");
+LN2_PIN_MUX(CDC_GPIO2,     "codec-gpio2");
+LN2_PIN_MUX(CDC_GPIO3,     "codec-gpio3");
+LN2_PIN_MUX(CDC_GPIO4,     "codec-gpio4");
+LN2_PIN_MUX(CDC_GPIO5,     "codec-gpio5");
+LN2_PIN_MUX(CDC_GPIO6,     "codec-gpio6");
+LN2_PIN_MUX(CDC_GPIO7,     "codec-gpio7");
+LN2_PIN_MUX(CDC_GPIO8,     "codec-gpio8");
+LN2_PIN_MUX(DSP_GPIO1,     "dsp-gpio1");
+LN2_PIN_MUX(DSP_GPIO2,     "dsp-gpio2");
+LN2_PIN_MUX(DSP_GPIO3,     "dsp-gpio3");
+LN2_PIN_MUX(DSP_GPIO4,     "dsp-gpio4");
+LN2_PIN_MUX(DSP_GPIO5,     "dsp-gpio5");
+LN2_PIN_MUX(DSP_GPIO6,     "dsp-gpio6");
+LN2_PIN_MUX(GF_GPIO2,      "gf-gpio2");
+LN2_PIN_MUX(GF_GPIO3,      "gf-gpio3");
+LN2_PIN_MUX(GF_GPIO7,      "gf-gpio7");
+LN2_PIN_MUX(DSP_UART1_RX,  "dsp-uart1-rx");
+LN2_PIN_MUX(DSP_UART1_TX,  "dsp-uart1-tx");
+LN2_PIN_MUX(DSP_UART2_RX,  "dsp-uart2-rx");
+LN2_PIN_MUX(DSP_UART2_TX,  "dsp-uart2-tx");
+LN2_PIN_MUX(GF_UART2_RX,   "gf-uart2-rx");
+LN2_PIN_MUX(GF_UART2_TX,   "gf-uart2-tx");
+LN2_PIN_MUX(USB_UART_RX,   "usb-uart-rx");
+LN2_PIN_MUX(CDC_PDMCLK1,   "codec-pdmclk1");
+LN2_PIN_MUX(CDC_PDMDAT1,   "codec-pdmdat1");
+LN2_PIN_MUX(CDC_PDMCLK2,   "codec-pdmclk2");
+LN2_PIN_MUX(CDC_PDMDAT2,   "codec-pdmdat2");
+LN2_PIN_MUX(CDC_DMICCLK1,  "codec-dmicclk1");
+LN2_PIN_MUX(CDC_DMICDAT1,  "codec-dmicdat1");
+LN2_PIN_MUX(CDC_DMICCLK2,  "codec-dmicclk2");
+LN2_PIN_MUX(CDC_DMICDAT2,  "codec-dmicdat2");
+LN2_PIN_MUX(CDC_DMICCLK3,  "codec-dmicclk3");
+LN2_PIN_MUX(CDC_DMICDAT3,  "codec-dmicdat3");
+LN2_PIN_MUX(CDC_DMICCLK4,  "codec-dmicclk4");
+LN2_PIN_MUX(CDC_DMICDAT4,  "codec-dmicdat4");
+LN2_PIN_MUX(DSP_DMICCLK1,  "dsp-dmicclk1");
+LN2_PIN_MUX(DSP_DMICDAT1,  "dsp-dmicdat1");
+LN2_PIN_MUX(DSP_DMICCLK2,  "dsp-dmicclk2");
+LN2_PIN_MUX(DSP_DMICDAT2,  "dsp-dmicdat2");
+LN2_PIN_MUX(I2C2_SCL,      "i2c2-scl");
+LN2_PIN_MUX(I2C2_SDA,      "i2c2-sda");
+LN2_PIN_MUX(I2C3_SCL,      "i2c3-scl");
+LN2_PIN_MUX(I2C3_SDA,      "i2c3-sda");
+LN2_PIN_MUX(I2C4_SCL,      "i2c4-scl");
+LN2_PIN_MUX(I2C4_SDA,      "i2c4-sda");
+LN2_PIN_MUX(DSP_STANDBY,   "dsp-standby");
+LN2_PIN_MUX(CDC_MCLK1,     "codec-mclk1");
+LN2_PIN_MUX(CDC_MCLK2,     "codec-mclk2");
+LN2_PIN_MUX(DSP_CLKIN,     "dsp-clkin");
+LN2_PIN_MUX(PSIA1_MCLK,    "psia1-mclk");
+LN2_PIN_MUX(PSIA2_MCLK,    "psia2-mclk");
+LN2_PIN_MUX(GF_GPIO1,      "gf-gpio1");
+LN2_PIN_MUX(GF_GPIO5,      "gf-gpio5");
+LN2_PIN_MUX(DSP_GPIO20,    "dsp-gpio20");
+LN2_PIN_GAI(CDC_AIF1);
+LN2_PIN_GAI(CDC_AIF2);
+LN2_PIN_GAI(CDC_AIF3);
+LN2_PIN_GAI(DSP_AIF1);
+LN2_PIN_GAI(DSP_AIF2);
+LN2_PIN_GAI(PSIA1);
+LN2_PIN_GAI(PSIA2);
+LN2_PIN_GAI(GF_AIF1);
+LN2_PIN_GAI(GF_AIF2);
+LN2_PIN_GAI(GF_AIF3);
+LN2_PIN_GAI(GF_AIF4);
+LN2_PIN_AIF(SPDIF_AIF);
+LN2_PIN_AIF(USB_AIF1);
+LN2_PIN_AIF(USB_AIF2);
+LN2_PIN_AIF(ADAT_AIF);
+LN2_PIN_AIF(SOUNDCARD_AIF);
+
+static const struct pinctrl_pin_desc lochnagar1_pins[] = {
+	LN1_PIN(CDC_RESET),      LN1_PIN(DSP_RESET),    LN1_PIN(CDC_CIF1MODE),
+	LN1_PIN(GF_GPIO2),       LN1_PIN(GF_GPIO3),     LN1_PIN(GF_GPIO7),
+	LN1_PIN(LED1),           LN1_PIN(LED2),
+	LN1_PINS(CDC_AIF1),      LN1_PINS(CDC_AIF2),    LN1_PINS(CDC_AIF3),
+	LN1_PINS(DSP_AIF1),      LN1_PINS(DSP_AIF2),
+	LN1_PINS(PSIA1),         LN1_PINS(PSIA2),
+	LN1_PINS(SPDIF_AIF),
+	LN1_PINS(GF_AIF1),       LN1_PINS(GF_AIF2),
+	LN1_PINS(GF_AIF3),       LN1_PINS(GF_AIF4),
+};
+
+static const struct pinctrl_pin_desc lochnagar2_pins[] = {
+	LN2_PIN(CDC_RESET),      LN2_PIN(DSP_RESET),    LN2_PIN(CDC_CIF1MODE),
+	LN2_PIN(CDC_LDOENA),
+	LN2_PIN(SPDIF_HWMODE),   LN2_PIN(SPDIF_RESET),
+	LN2_PIN(FPGA_GPIO1),     LN2_PIN(FPGA_GPIO2),   LN2_PIN(FPGA_GPIO3),
+	LN2_PIN(FPGA_GPIO4),     LN2_PIN(FPGA_GPIO5),   LN2_PIN(FPGA_GPIO6),
+	LN2_PIN(CDC_GPIO1),      LN2_PIN(CDC_GPIO2),    LN2_PIN(CDC_GPIO3),
+	LN2_PIN(CDC_GPIO4),      LN2_PIN(CDC_GPIO5),    LN2_PIN(CDC_GPIO6),
+	LN2_PIN(CDC_GPIO7),      LN2_PIN(CDC_GPIO8),
+	LN2_PIN(DSP_GPIO1),      LN2_PIN(DSP_GPIO2),    LN2_PIN(DSP_GPIO3),
+	LN2_PIN(DSP_GPIO4),      LN2_PIN(DSP_GPIO5),    LN2_PIN(DSP_GPIO6),
+	LN2_PIN(DSP_GPIO20),
+	LN2_PIN(GF_GPIO1),       LN2_PIN(GF_GPIO2),     LN2_PIN(GF_GPIO3),
+	LN2_PIN(GF_GPIO5),       LN2_PIN(GF_GPIO7),
+	LN2_PINS(CDC_AIF1),      LN2_PINS(CDC_AIF2),    LN2_PINS(CDC_AIF3),
+	LN2_PINS(DSP_AIF1),      LN2_PINS(DSP_AIF2),
+	LN2_PINS(PSIA1),         LN2_PINS(PSIA2),
+	LN2_PINS(GF_AIF1),       LN2_PINS(GF_AIF2),
+	LN2_PINS(GF_AIF3),       LN2_PINS(GF_AIF4),
+	LN2_PIN(DSP_UART1_RX),   LN2_PIN(DSP_UART1_TX),
+	LN2_PIN(DSP_UART2_RX),   LN2_PIN(DSP_UART2_TX),
+	LN2_PIN(GF_UART2_RX),    LN2_PIN(GF_UART2_TX),
+	LN2_PIN(USB_UART_RX),
+	LN2_PIN(CDC_PDMCLK1),    LN2_PIN(CDC_PDMDAT1),
+	LN2_PIN(CDC_PDMCLK2),    LN2_PIN(CDC_PDMDAT2),
+	LN2_PIN(CDC_DMICCLK1),   LN2_PIN(CDC_DMICDAT1),
+	LN2_PIN(CDC_DMICCLK2),   LN2_PIN(CDC_DMICDAT2),
+	LN2_PIN(CDC_DMICCLK3),   LN2_PIN(CDC_DMICDAT3),
+	LN2_PIN(CDC_DMICCLK4),   LN2_PIN(CDC_DMICDAT4),
+	LN2_PIN(DSP_DMICCLK1),   LN2_PIN(DSP_DMICDAT1),
+	LN2_PIN(DSP_DMICCLK2),   LN2_PIN(DSP_DMICDAT2),
+	LN2_PIN(I2C2_SCL),       LN2_PIN(I2C2_SDA),
+	LN2_PIN(I2C3_SCL),       LN2_PIN(I2C3_SDA),
+	LN2_PIN(I2C4_SCL),       LN2_PIN(I2C4_SDA),
+	LN2_PIN(DSP_STANDBY),
+	LN2_PIN(CDC_MCLK1),      LN2_PIN(CDC_MCLK2),
+	LN2_PIN(DSP_CLKIN),
+	LN2_PIN(PSIA1_MCLK),     LN2_PIN(PSIA2_MCLK),
+	LN2_PINS(SPDIF_AIF),
+	LN2_PINS(USB_AIF1),      LN2_PINS(USB_AIF2),
+	LN2_PINS(ADAT_AIF),
+	LN2_PINS(SOUNDCARD_AIF),
+};
+
+#define LN_AIF_PINS(REV, ID) \
+	LOCHNAGAR##REV##_PIN_##ID##_BCLK, \
+	LOCHNAGAR##REV##_PIN_##ID##_LRCLK, \
+	LOCHNAGAR##REV##_PIN_##ID##_TXDAT, \
+	LOCHNAGAR##REV##_PIN_##ID##_RXDAT,
+
+#define LN1_AIF(ID, CTRL) \
+static const struct lochnagar_aif lochnagar1_##ID##_aif = { \
+	.name = LN_##ID##_STR, \
+	.pins = { LN_AIF_PINS(1, ID) }, \
+	.src_reg = LOCHNAGAR1_##ID##_SEL, \
+	.src_mask = LOCHNAGAR1_SRC_MASK, \
+	.ctrl_reg = LOCHNAGAR1_##CTRL, \
+	.ena_mask = LOCHNAGAR1_##ID##_ENA_MASK, \
+	.master_mask = LOCHNAGAR1_##ID##_LRCLK_DIR_MASK | \
+		       LOCHNAGAR1_##ID##_BCLK_DIR_MASK, \
+}
+
+#define LN2_AIF(ID) \
+static const struct lochnagar_aif lochnagar2_##ID##_aif = { \
+	.name = LN_##ID##_STR, \
+	.pins = { LN_AIF_PINS(2, ID) }, \
+	.src_reg = LOCHNAGAR2_##ID##_CTRL,  \
+	.src_mask = LOCHNAGAR2_AIF_SRC_MASK, \
+	.ctrl_reg = LOCHNAGAR2_##ID##_CTRL, \
+	.ena_mask = LOCHNAGAR2_AIF_ENA_MASK, \
+	.master_mask = LOCHNAGAR2_AIF_LRCLK_DIR_MASK | \
+		       LOCHNAGAR2_AIF_BCLK_DIR_MASK, \
+}
+
+struct lochnagar_aif {
+	const char name[16];
+
+	unsigned int pins[4];
+
+	u16 src_reg;
+	u16 src_mask;
+
+	u16 ctrl_reg;
+	u16 ena_mask;
+	u16 master_mask;
+};
+
+LN1_AIF(CDC_AIF1,      CDC_AIF_CTRL1);
+LN1_AIF(CDC_AIF2,      CDC_AIF_CTRL1);
+LN1_AIF(CDC_AIF3,      CDC_AIF_CTRL2);
+LN1_AIF(DSP_AIF1,      DSP_AIF);
+LN1_AIF(DSP_AIF2,      DSP_AIF);
+LN1_AIF(PSIA1,         PSIA_AIF);
+LN1_AIF(PSIA2,         PSIA_AIF);
+LN1_AIF(GF_AIF1,       GF_AIF1);
+LN1_AIF(GF_AIF2,       GF_AIF2);
+LN1_AIF(GF_AIF3,       GF_AIF1);
+LN1_AIF(GF_AIF4,       GF_AIF2);
+LN1_AIF(SPDIF_AIF,     EXT_AIF_CTRL);
+
+LN2_AIF(CDC_AIF1);
+LN2_AIF(CDC_AIF2);
+LN2_AIF(CDC_AIF3);
+LN2_AIF(DSP_AIF1);
+LN2_AIF(DSP_AIF2);
+LN2_AIF(PSIA1);
+LN2_AIF(PSIA2);
+LN2_AIF(GF_AIF1);
+LN2_AIF(GF_AIF2);
+LN2_AIF(GF_AIF3);
+LN2_AIF(GF_AIF4);
+LN2_AIF(SPDIF_AIF);
+LN2_AIF(USB_AIF1);
+LN2_AIF(USB_AIF2);
+LN2_AIF(ADAT_AIF);
+LN2_AIF(SOUNDCARD_AIF);
+
+#define LN2_OP_AIF	0x00
+#define LN2_OP_GPIO	0xFE
+
+#define LN_FUNC(NAME, TYPE, OP) \
+	{ .name = NAME, .type = LN_FTYPE_##TYPE, .op = OP }
+
+#define LN_FUNC_PIN(REV, ID, OP) \
+	LN_FUNC(lochnagar##REV##_##ID##_pin.name, PIN, OP)
+
+#define LN1_FUNC_PIN(ID, OP) LN_FUNC_PIN(1, ID, OP)
+#define LN2_FUNC_PIN(ID, OP) LN_FUNC_PIN(2, ID, OP)
+
+#define LN_FUNC_AIF(REV, ID, OP) \
+	LN_FUNC(lochnagar##REV##_##ID##_aif.name, AIF, OP)
+
+#define LN1_FUNC_AIF(ID, OP) LN_FUNC_AIF(1, ID, OP)
+#define LN2_FUNC_AIF(ID, OP) LN_FUNC_AIF(2, ID, OP)
+
+#define LN2_FUNC_GAI(ID, OP, BOP, LROP, RXOP, TXOP) \
+	LN2_FUNC_AIF(ID, OP), \
+	LN_FUNC(lochnagar2_##ID##_BCLK_pin.name, PIN, BOP), \
+	LN_FUNC(lochnagar2_##ID##_LRCLK_pin.name, PIN, LROP), \
+	LN_FUNC(lochnagar2_##ID##_RXDAT_pin.name, PIN, RXOP), \
+	LN_FUNC(lochnagar2_##ID##_TXDAT_pin.name, PIN, TXOP)
+
+enum lochnagar_func_type {
+	LN_FTYPE_PIN,
+	LN_FTYPE_AIF,
+	LN_FTYPE_COUNT,
+};
+
+struct lochnagar_func {
+	const char * const name;
+
+	enum lochnagar_func_type type;
+
+	u8 op;
+};
+
+static const struct lochnagar_func lochnagar1_funcs[] = {
+	LN_FUNC("dsp-gpio1",       PIN, 0x01),
+	LN_FUNC("dsp-gpio2",       PIN, 0x02),
+	LN_FUNC("dsp-gpio3",       PIN, 0x03),
+	LN_FUNC("codec-gpio1",     PIN, 0x04),
+	LN_FUNC("codec-gpio2",     PIN, 0x05),
+	LN_FUNC("codec-gpio3",     PIN, 0x06),
+	LN_FUNC("codec-gpio4",     PIN, 0x07),
+	LN_FUNC("codec-gpio5",     PIN, 0x08),
+	LN_FUNC("codec-gpio6",     PIN, 0x09),
+	LN_FUNC("codec-gpio7",     PIN, 0x0A),
+	LN_FUNC("codec-gpio8",     PIN, 0x0B),
+	LN1_FUNC_PIN(GF_GPIO2,          0x0C),
+	LN1_FUNC_PIN(GF_GPIO3,          0x0D),
+	LN1_FUNC_PIN(GF_GPIO7,          0x0E),
+
+	LN1_FUNC_AIF(SPDIF_AIF,         0x01),
+	LN1_FUNC_AIF(PSIA1,             0x02),
+	LN1_FUNC_AIF(PSIA2,             0x03),
+	LN1_FUNC_AIF(CDC_AIF1,          0x04),
+	LN1_FUNC_AIF(CDC_AIF2,          0x05),
+	LN1_FUNC_AIF(CDC_AIF3,          0x06),
+	LN1_FUNC_AIF(DSP_AIF1,          0x07),
+	LN1_FUNC_AIF(DSP_AIF2,          0x08),
+	LN1_FUNC_AIF(GF_AIF3,           0x09),
+	LN1_FUNC_AIF(GF_AIF4,           0x0A),
+	LN1_FUNC_AIF(GF_AIF1,           0x0B),
+	LN1_FUNC_AIF(GF_AIF2,           0x0C),
+};
+
+static const struct lochnagar_func lochnagar2_funcs[] = {
+	LN_FUNC("aif",             PIN, LN2_OP_AIF),
+	LN2_FUNC_PIN(FPGA_GPIO1,        0x01),
+	LN2_FUNC_PIN(FPGA_GPIO2,        0x02),
+	LN2_FUNC_PIN(FPGA_GPIO3,        0x03),
+	LN2_FUNC_PIN(FPGA_GPIO4,        0x04),
+	LN2_FUNC_PIN(FPGA_GPIO5,        0x05),
+	LN2_FUNC_PIN(FPGA_GPIO6,        0x06),
+	LN2_FUNC_PIN(CDC_GPIO1,         0x07),
+	LN2_FUNC_PIN(CDC_GPIO2,         0x08),
+	LN2_FUNC_PIN(CDC_GPIO3,         0x09),
+	LN2_FUNC_PIN(CDC_GPIO4,         0x0A),
+	LN2_FUNC_PIN(CDC_GPIO5,         0x0B),
+	LN2_FUNC_PIN(CDC_GPIO6,         0x0C),
+	LN2_FUNC_PIN(CDC_GPIO7,         0x0D),
+	LN2_FUNC_PIN(CDC_GPIO8,         0x0E),
+	LN2_FUNC_PIN(DSP_GPIO1,         0x0F),
+	LN2_FUNC_PIN(DSP_GPIO2,         0x10),
+	LN2_FUNC_PIN(DSP_GPIO3,         0x11),
+	LN2_FUNC_PIN(DSP_GPIO4,         0x12),
+	LN2_FUNC_PIN(DSP_GPIO5,         0x13),
+	LN2_FUNC_PIN(DSP_GPIO6,         0x14),
+	LN2_FUNC_PIN(GF_GPIO2,          0x15),
+	LN2_FUNC_PIN(GF_GPIO3,          0x16),
+	LN2_FUNC_PIN(GF_GPIO7,          0x17),
+	LN2_FUNC_PIN(GF_GPIO1,          0x18),
+	LN2_FUNC_PIN(GF_GPIO5,          0x19),
+	LN2_FUNC_PIN(DSP_GPIO20,        0x1A),
+	LN_FUNC("codec-clkout",    PIN, 0x20),
+	LN_FUNC("dsp-clkout",      PIN, 0x21),
+	LN_FUNC("pmic-32k",        PIN, 0x22),
+	LN_FUNC("spdif-clkout",    PIN, 0x23),
+	LN_FUNC("clk-12m288",      PIN, 0x24),
+	LN_FUNC("clk-11m2986",     PIN, 0x25),
+	LN_FUNC("clk-24m576",      PIN, 0x26),
+	LN_FUNC("clk-22m5792",     PIN, 0x27),
+	LN_FUNC("xmos-mclk",       PIN, 0x29),
+	LN_FUNC("gf-clkout1",      PIN, 0x2A),
+	LN_FUNC("gf-mclk1",        PIN, 0x2B),
+	LN_FUNC("gf-mclk3",        PIN, 0x2C),
+	LN_FUNC("gf-mclk2",        PIN, 0x2D),
+	LN_FUNC("gf-clkout2",      PIN, 0x2E),
+	LN2_FUNC_PIN(CDC_MCLK1,         0x2F),
+	LN2_FUNC_PIN(CDC_MCLK2,         0x30),
+	LN2_FUNC_PIN(DSP_CLKIN,         0x31),
+	LN2_FUNC_PIN(PSIA1_MCLK,        0x32),
+	LN2_FUNC_PIN(PSIA2_MCLK,        0x33),
+	LN_FUNC("spdif-mclk",      PIN, 0x34),
+	LN_FUNC("codec-irq",       PIN, 0x42),
+	LN2_FUNC_PIN(CDC_RESET,         0x43),
+	LN2_FUNC_PIN(DSP_RESET,         0x44),
+	LN_FUNC("dsp-irq",         PIN, 0x45),
+	LN2_FUNC_PIN(DSP_STANDBY,       0x46),
+	LN2_FUNC_PIN(CDC_PDMCLK1,       0x90),
+	LN2_FUNC_PIN(CDC_PDMDAT1,       0x91),
+	LN2_FUNC_PIN(CDC_PDMCLK2,       0x92),
+	LN2_FUNC_PIN(CDC_PDMDAT2,       0x93),
+	LN2_FUNC_PIN(CDC_DMICCLK1,      0xA0),
+	LN2_FUNC_PIN(CDC_DMICDAT1,      0xA1),
+	LN2_FUNC_PIN(CDC_DMICCLK2,      0xA2),
+	LN2_FUNC_PIN(CDC_DMICDAT2,      0xA3),
+	LN2_FUNC_PIN(CDC_DMICCLK3,      0xA4),
+	LN2_FUNC_PIN(CDC_DMICDAT3,      0xA5),
+	LN2_FUNC_PIN(CDC_DMICCLK4,      0xA6),
+	LN2_FUNC_PIN(CDC_DMICDAT4,      0xA7),
+	LN2_FUNC_PIN(DSP_DMICCLK1,      0xA8),
+	LN2_FUNC_PIN(DSP_DMICDAT1,      0xA9),
+	LN2_FUNC_PIN(DSP_DMICCLK2,      0xAA),
+	LN2_FUNC_PIN(DSP_DMICDAT2,      0xAB),
+	LN2_FUNC_PIN(DSP_UART1_RX,      0xC0),
+	LN2_FUNC_PIN(DSP_UART1_TX,      0xC1),
+	LN2_FUNC_PIN(DSP_UART2_RX,      0xC2),
+	LN2_FUNC_PIN(DSP_UART2_TX,      0xC3),
+	LN2_FUNC_PIN(GF_UART2_RX,       0xC4),
+	LN2_FUNC_PIN(GF_UART2_TX,       0xC5),
+	LN2_FUNC_PIN(USB_UART_RX,       0xC6),
+	LN_FUNC("usb-uart-tx",     PIN, 0xC7),
+	LN2_FUNC_PIN(I2C2_SCL,          0xE0),
+	LN2_FUNC_PIN(I2C2_SDA,          0xE1),
+	LN2_FUNC_PIN(I2C3_SCL,          0xE2),
+	LN2_FUNC_PIN(I2C3_SDA,          0xE3),
+	LN2_FUNC_PIN(I2C4_SCL,          0xE4),
+	LN2_FUNC_PIN(I2C4_SDA,          0xE5),
+	LN_FUNC("gpio",            PIN, LN2_OP_GPIO),
+
+	LN2_FUNC_AIF(SPDIF_AIF,         0x01),
+	LN2_FUNC_GAI(PSIA1,             0x02, 0x50, 0x51, 0x52, 0x53),
+	LN2_FUNC_GAI(PSIA2,             0x03, 0x54, 0x55, 0x56, 0x57),
+	LN2_FUNC_GAI(CDC_AIF1,          0x04, 0x59, 0x5B, 0x5A, 0x58),
+	LN2_FUNC_GAI(CDC_AIF2,          0x05, 0x5D, 0x5F, 0x5E, 0x5C),
+	LN2_FUNC_GAI(CDC_AIF3,          0x06, 0x61, 0x62, 0x63, 0x60),
+	LN2_FUNC_GAI(DSP_AIF1,          0x07, 0x65, 0x67, 0x66, 0x64),
+	LN2_FUNC_GAI(DSP_AIF2,          0x08, 0x69, 0x6B, 0x6A, 0x68),
+	LN2_FUNC_GAI(GF_AIF3,           0x09, 0x6D, 0x6F, 0x6C, 0x6E),
+	LN2_FUNC_GAI(GF_AIF4,           0x0A, 0x71, 0x73, 0x70, 0x72),
+	LN2_FUNC_GAI(GF_AIF1,           0x0B, 0x75, 0x77, 0x74, 0x76),
+	LN2_FUNC_GAI(GF_AIF2,           0x0C, 0x79, 0x7B, 0x78, 0x7A),
+	LN2_FUNC_AIF(USB_AIF1,          0x0D),
+	LN2_FUNC_AIF(USB_AIF2,          0x0E),
+	LN2_FUNC_AIF(ADAT_AIF,          0x0F),
+	LN2_FUNC_AIF(SOUNDCARD_AIF,     0x10),
+};
+
+#define LN_GROUP_PIN(REV, ID) { \
+	.name = lochnagar##REV##_##ID##_pin.name, \
+	.type = LN_FTYPE_PIN, \
+	.pins = &lochnagar##REV##_pins[LOCHNAGAR##REV##_PIN_##ID].number, \
+	.npins = 1, \
+	.priv = &lochnagar##REV##_pins[LOCHNAGAR##REV##_PIN_##ID], \
+}
+
+#define LN_GROUP_AIF(REV, ID) { \
+	.name = lochnagar##REV##_##ID##_aif.name, \
+	.type = LN_FTYPE_AIF, \
+	.pins = lochnagar##REV##_##ID##_aif.pins, \
+	.npins = ARRAY_SIZE(lochnagar##REV##_##ID##_aif.pins), \
+	.priv = &lochnagar##REV##_##ID##_aif, \
+}
+
+#define LN1_GROUP_PIN(ID) LN_GROUP_PIN(1, ID)
+#define LN2_GROUP_PIN(ID) LN_GROUP_PIN(2, ID)
+
+#define LN1_GROUP_AIF(ID) LN_GROUP_AIF(1, ID)
+#define LN2_GROUP_AIF(ID) LN_GROUP_AIF(2, ID)
+
+#define LN2_GROUP_GAI(ID) \
+	LN2_GROUP_AIF(ID), \
+	LN2_GROUP_PIN(ID##_BCLK), LN2_GROUP_PIN(ID##_LRCLK), \
+	LN2_GROUP_PIN(ID##_RXDAT), LN2_GROUP_PIN(ID##_TXDAT)
+
+struct lochnagar_group {
+	const char * const name;
+
+	enum lochnagar_func_type type;
+
+	const unsigned int *pins;
+	unsigned int npins;
+
+	const void *priv;
+};
+
+static const struct lochnagar_group lochnagar1_groups[] = {
+	LN1_GROUP_PIN(GF_GPIO2),       LN1_GROUP_PIN(GF_GPIO3),
+	LN1_GROUP_PIN(GF_GPIO7),
+	LN1_GROUP_PIN(LED1),           LN1_GROUP_PIN(LED2),
+	LN1_GROUP_AIF(CDC_AIF1),       LN1_GROUP_AIF(CDC_AIF2),
+	LN1_GROUP_AIF(CDC_AIF3),
+	LN1_GROUP_AIF(DSP_AIF1),       LN1_GROUP_AIF(DSP_AIF2),
+	LN1_GROUP_AIF(PSIA1),          LN1_GROUP_AIF(PSIA2),
+	LN1_GROUP_AIF(GF_AIF1),        LN1_GROUP_AIF(GF_AIF2),
+	LN1_GROUP_AIF(GF_AIF3),        LN1_GROUP_AIF(GF_AIF4),
+	LN1_GROUP_AIF(SPDIF_AIF),
+};
+
+static const struct lochnagar_group lochnagar2_groups[] = {
+	LN2_GROUP_PIN(FPGA_GPIO1),     LN2_GROUP_PIN(FPGA_GPIO2),
+	LN2_GROUP_PIN(FPGA_GPIO3),     LN2_GROUP_PIN(FPGA_GPIO4),
+	LN2_GROUP_PIN(FPGA_GPIO5),     LN2_GROUP_PIN(FPGA_GPIO6),
+	LN2_GROUP_PIN(CDC_GPIO1),      LN2_GROUP_PIN(CDC_GPIO2),
+	LN2_GROUP_PIN(CDC_GPIO3),      LN2_GROUP_PIN(CDC_GPIO4),
+	LN2_GROUP_PIN(CDC_GPIO5),      LN2_GROUP_PIN(CDC_GPIO6),
+	LN2_GROUP_PIN(CDC_GPIO7),      LN2_GROUP_PIN(CDC_GPIO8),
+	LN2_GROUP_PIN(DSP_GPIO1),      LN2_GROUP_PIN(DSP_GPIO2),
+	LN2_GROUP_PIN(DSP_GPIO3),      LN2_GROUP_PIN(DSP_GPIO4),
+	LN2_GROUP_PIN(DSP_GPIO5),      LN2_GROUP_PIN(DSP_GPIO6),
+	LN2_GROUP_PIN(DSP_GPIO20),
+	LN2_GROUP_PIN(GF_GPIO1),
+	LN2_GROUP_PIN(GF_GPIO2),       LN2_GROUP_PIN(GF_GPIO5),
+	LN2_GROUP_PIN(GF_GPIO3),       LN2_GROUP_PIN(GF_GPIO7),
+	LN2_GROUP_PIN(DSP_UART1_RX),   LN2_GROUP_PIN(DSP_UART1_TX),
+	LN2_GROUP_PIN(DSP_UART2_RX),   LN2_GROUP_PIN(DSP_UART2_TX),
+	LN2_GROUP_PIN(GF_UART2_RX),    LN2_GROUP_PIN(GF_UART2_TX),
+	LN2_GROUP_PIN(USB_UART_RX),
+	LN2_GROUP_PIN(CDC_PDMCLK1),    LN2_GROUP_PIN(CDC_PDMDAT1),
+	LN2_GROUP_PIN(CDC_PDMCLK2),    LN2_GROUP_PIN(CDC_PDMDAT2),
+	LN2_GROUP_PIN(CDC_DMICCLK1),   LN2_GROUP_PIN(CDC_DMICDAT1),
+	LN2_GROUP_PIN(CDC_DMICCLK2),   LN2_GROUP_PIN(CDC_DMICDAT2),
+	LN2_GROUP_PIN(CDC_DMICCLK3),   LN2_GROUP_PIN(CDC_DMICDAT3),
+	LN2_GROUP_PIN(CDC_DMICCLK4),   LN2_GROUP_PIN(CDC_DMICDAT4),
+	LN2_GROUP_PIN(DSP_DMICCLK1),   LN2_GROUP_PIN(DSP_DMICDAT1),
+	LN2_GROUP_PIN(DSP_DMICCLK2),   LN2_GROUP_PIN(DSP_DMICDAT2),
+	LN2_GROUP_PIN(I2C2_SCL),       LN2_GROUP_PIN(I2C2_SDA),
+	LN2_GROUP_PIN(I2C3_SCL),       LN2_GROUP_PIN(I2C3_SDA),
+	LN2_GROUP_PIN(I2C4_SCL),       LN2_GROUP_PIN(I2C4_SDA),
+	LN2_GROUP_PIN(DSP_STANDBY),
+	LN2_GROUP_PIN(CDC_MCLK1),      LN2_GROUP_PIN(CDC_MCLK2),
+	LN2_GROUP_PIN(DSP_CLKIN),
+	LN2_GROUP_PIN(PSIA1_MCLK),     LN2_GROUP_PIN(PSIA2_MCLK),
+	LN2_GROUP_GAI(CDC_AIF1),       LN2_GROUP_GAI(CDC_AIF2),
+	LN2_GROUP_GAI(CDC_AIF3),
+	LN2_GROUP_GAI(DSP_AIF1),       LN2_GROUP_GAI(DSP_AIF2),
+	LN2_GROUP_GAI(PSIA1),          LN2_GROUP_GAI(PSIA2),
+	LN2_GROUP_GAI(GF_AIF1),        LN2_GROUP_GAI(GF_AIF2),
+	LN2_GROUP_GAI(GF_AIF3),        LN2_GROUP_GAI(GF_AIF4),
+	LN2_GROUP_AIF(SPDIF_AIF),
+	LN2_GROUP_AIF(USB_AIF1),       LN2_GROUP_AIF(USB_AIF2),
+	LN2_GROUP_AIF(ADAT_AIF),
+	LN2_GROUP_AIF(SOUNDCARD_AIF),
+};
+
+struct lochnagar_func_groups {
+	const char **groups;
+	unsigned int ngroups;
+};
+
+struct lochnagar_pin_priv {
+	struct lochnagar *lochnagar;
+	struct device *dev;
+
+	const struct lochnagar_func *funcs;
+	unsigned int nfuncs;
+
+	const struct pinctrl_pin_desc *pins;
+	unsigned int npins;
+
+	const struct lochnagar_group *groups;
+	unsigned int ngroups;
+
+	struct lochnagar_func_groups func_groups[LN_FTYPE_COUNT];
+
+	struct gpio_chip gpio_chip;
+};
+
+static int lochnagar_get_groups_count(struct pinctrl_dev *pctldev)
+{
+	struct lochnagar_pin_priv *priv = pinctrl_dev_get_drvdata(pctldev);
+
+	return priv->ngroups;
+}
+
+static const char *lochnagar_get_group_name(struct pinctrl_dev *pctldev,
+					    unsigned int group_idx)
+{
+	struct lochnagar_pin_priv *priv = pinctrl_dev_get_drvdata(pctldev);
+
+	return priv->groups[group_idx].name;
+}
+
+static int lochnagar_get_group_pins(struct pinctrl_dev *pctldev,
+				    unsigned int group_idx,
+				    const unsigned int **pins,
+				    unsigned int *num_pins)
+{
+	struct lochnagar_pin_priv *priv = pinctrl_dev_get_drvdata(pctldev);
+
+	*pins = priv->groups[group_idx].pins;
+	*num_pins = priv->groups[group_idx].npins;
+
+	return 0;
+}
+
+static const struct pinctrl_ops lochnagar_pin_group_ops = {
+	.get_groups_count = lochnagar_get_groups_count,
+	.get_group_name = lochnagar_get_group_name,
+	.get_group_pins = lochnagar_get_group_pins,
+	.dt_node_to_map = pinconf_generic_dt_node_to_map_all,
+	.dt_free_map = pinctrl_utils_free_map,
+};
+
+static int lochnagar_get_funcs_count(struct pinctrl_dev *pctldev)
+{
+	struct lochnagar_pin_priv *priv = pinctrl_dev_get_drvdata(pctldev);
+
+	return priv->nfuncs;
+}
+
+static const char *lochnagar_get_func_name(struct pinctrl_dev *pctldev,
+					   unsigned int func_idx)
+{
+	struct lochnagar_pin_priv *priv = pinctrl_dev_get_drvdata(pctldev);
+
+	return priv->funcs[func_idx].name;
+}
+
+static int lochnagar_get_func_groups(struct pinctrl_dev *pctldev,
+				     unsigned int func_idx,
+				     const char * const **groups,
+				     unsigned int * const num_groups)
+{
+	struct lochnagar_pin_priv *priv = pinctrl_dev_get_drvdata(pctldev);
+	int func_type;
+
+	func_type = priv->funcs[func_idx].type;
+
+	*groups = priv->func_groups[func_type].groups;
+	*num_groups = priv->func_groups[func_type].ngroups;
+
+	return 0;
+}
+
+static int lochnagar2_get_gpio_chan(struct lochnagar_pin_priv *priv,
+				    unsigned int op)
+{
+	struct regmap *regmap = priv->lochnagar->regmap;
+	unsigned int val;
+	int free = -1;
+	int i, ret;
+
+	for (i = 0; i < LN2_NUM_GPIO_CHANNELS; i++) {
+		ret = regmap_read(regmap, LOCHNAGAR2_GPIO_CHANNEL1 + i, &val);
+		if (ret)
+			return ret;
+
+		val &= LOCHNAGAR2_GPIO_CHANNEL_SRC_MASK;
+
+		if (val == op)
+			return i + 1;
+
+		if (free < 0 && !val)
+			free = i;
+	}
+
+	if (free >= 0) {
+		ret = regmap_update_bits(regmap,
+					 LOCHNAGAR2_GPIO_CHANNEL1 + free,
+					 LOCHNAGAR2_GPIO_CHANNEL_SRC_MASK, op);
+		if (ret)
+			return ret;
+
+		free++;
+
+		dev_dbg(priv->dev, "Set channel %d to 0x%x\n", free, op);
+
+		return free;
+	}
+
+	return -ENOSPC;
+}
+
+static int lochnagar_pin_set_mux(struct lochnagar_pin_priv *priv,
+				 const struct lochnagar_pin *pin,
+				 unsigned int op)
+{
+	int ret;
+
+	switch (priv->lochnagar->type) {
+	case LOCHNAGAR1:
+		break;
+	default:
+		ret = lochnagar2_get_gpio_chan(priv, op);
+		if (ret < 0) {
+			dev_err(priv->dev, "Failed to get channel for %s: %d\n",
+				pin->name, ret);
+			return ret;
+		}
+
+		op = ret;
+		break;
+	}
+
+	dev_dbg(priv->dev, "Set pin %s to 0x%x\n", pin->name, op);
+
+	ret = regmap_write(priv->lochnagar->regmap, pin->reg, op);
+	if (ret)
+		dev_err(priv->dev, "Failed to set %s mux: %d\n",
+			pin->name, ret);
+
+	return 0;
+}
+
+static int lochnagar_aif_set_mux(struct lochnagar_pin_priv *priv,
+				 const struct lochnagar_group *group,
+				 unsigned int op)
+{
+	struct regmap *regmap = priv->lochnagar->regmap;
+	const struct lochnagar_aif *aif = group->priv;
+	const struct lochnagar_pin *pin;
+	int i, ret;
+
+	ret = regmap_update_bits(regmap, aif->src_reg, aif->src_mask, op);
+	if (ret) {
+		dev_err(priv->dev, "Failed to set %s source: %d\n",
+			group->name, ret);
+		return ret;
+	}
+
+	ret = regmap_update_bits(regmap, aif->ctrl_reg,
+				 aif->ena_mask, aif->ena_mask);
+	if (ret) {
+		dev_err(priv->dev, "Failed to set %s enable: %d\n",
+			group->name, ret);
+		return ret;
+	}
+
+	for (i = 0; i < group->npins; i++) {
+		pin = priv->pins[group->pins[i]].drv_data;
+
+		if (pin->type != LN_PTYPE_MUX)
+			continue;
+
+		dev_dbg(priv->dev, "Set pin %s to AIF\n", pin->name);
+
+		ret = regmap_update_bits(regmap, pin->reg,
+					 LOCHNAGAR2_GPIO_SRC_MASK,
+					 LN2_OP_AIF);
+		if (ret) {
+			dev_err(priv->dev, "Failed to set %s to AIF: %d\n",
+				pin->name, ret);
+			return ret;
+		}
+	}
+
+	return 0;
+}
+
+static int lochnagar_set_mux(struct pinctrl_dev *pctldev,
+			     unsigned int func_idx, unsigned int group_idx)
+{
+	struct lochnagar_pin_priv *priv = pinctrl_dev_get_drvdata(pctldev);
+	const struct lochnagar_func *func = &priv->funcs[func_idx];
+	const struct lochnagar_group *group = &priv->groups[group_idx];
+	const struct lochnagar_pin *pin;
+
+	switch (func->type) {
+	case LN_FTYPE_AIF:
+		dev_dbg(priv->dev, "Set group %s to %s\n",
+			group->name, func->name);
+
+		return lochnagar_aif_set_mux(priv, group, func->op);
+	case LN_FTYPE_PIN:
+		pin = priv->pins[*group->pins].drv_data;
+
+		dev_dbg(priv->dev, "Set pin %s to %s\n", pin->name, func->name);
+
+		return lochnagar_pin_set_mux(priv, pin, func->op);
+	default:
+		return -EINVAL;
+	}
+}
+
+static int lochnagar_gpio_request(struct pinctrl_dev *pctldev,
+				  struct pinctrl_gpio_range *range,
+				  unsigned int offset)
+{
+	struct lochnagar_pin_priv *priv = pinctrl_dev_get_drvdata(pctldev);
+	struct lochnagar *lochnagar = priv->lochnagar;
+	const struct lochnagar_pin *pin = priv->pins[offset].drv_data;
+	int ret;
+
+	dev_dbg(priv->dev, "Requesting GPIO %s\n", pin->name);
+
+	if (lochnagar->type == LOCHNAGAR1 || pin->type != LN_PTYPE_MUX)
+		return 0;
+
+	ret = lochnagar2_get_gpio_chan(priv, LN2_OP_GPIO);
+	if (ret < 0) {
+		dev_err(priv->dev, "Failed to get low channel: %d\n", ret);
+		return ret;
+	}
+
+	ret = lochnagar2_get_gpio_chan(priv, LN2_OP_GPIO | 0x1);
+	if (ret < 0) {
+		dev_err(priv->dev, "Failed to get high channel: %d\n", ret);
+		return ret;
+	}
+
+	return 0;
+}
+
+static int lochnagar_gpio_set_direction(struct pinctrl_dev *pctldev,
+					struct pinctrl_gpio_range *range,
+					unsigned int offset,
+					bool input)
+{
+	/* The GPIOs only support output */
+	if (input)
+		return -EINVAL;
+
+	return 0;
+}
+
+static const struct pinmux_ops lochnagar_pin_mux_ops = {
+	.get_functions_count = lochnagar_get_funcs_count,
+	.get_function_name = lochnagar_get_func_name,
+	.get_function_groups = lochnagar_get_func_groups,
+	.set_mux = lochnagar_set_mux,
+
+	.gpio_request_enable = lochnagar_gpio_request,
+	.gpio_set_direction = lochnagar_gpio_set_direction,
+
+	.strict = true,
+};
+
+static int lochnagar_aif_set_master(struct lochnagar_pin_priv *priv,
+				    unsigned int group_idx, bool master)
+{
+	struct regmap *regmap = priv->lochnagar->regmap;
+	const struct lochnagar_group *group = &priv->groups[group_idx];
+	const struct lochnagar_aif *aif = group->priv;
+	unsigned int val = 0;
+	int ret;
+
+	if (group->type != LN_FTYPE_AIF)
+		return -EINVAL;
+
+	if (!master)
+		val = aif->master_mask;
+
+	dev_dbg(priv->dev, "Set AIF %s to %s\n",
+		group->name, master ? "master" : "slave");
+
+	ret = regmap_update_bits(regmap, aif->ctrl_reg, aif->master_mask, val);
+	if (ret) {
+		dev_err(priv->dev, "Failed to set %s mode: %d\n",
+			group->name, ret);
+		return ret;
+	}
+
+	return 0;
+}
+
+static int lochnagar_conf_group_set(struct pinctrl_dev *pctldev,
+				    unsigned int group_idx,
+				    unsigned long *configs,
+				    unsigned int num_configs)
+{
+	struct lochnagar_pin_priv *priv = pinctrl_dev_get_drvdata(pctldev);
+	int i, ret;
+
+	for (i = 0; i < num_configs; i++) {
+		unsigned int param = pinconf_to_config_param(*configs);
+
+		switch (param) {
+		case PIN_CONFIG_OUTPUT_ENABLE:
+			ret = lochnagar_aif_set_master(priv, group_idx, true);
+			if (ret)
+				return ret;
+			break;
+		case PIN_CONFIG_INPUT_ENABLE:
+			ret = lochnagar_aif_set_master(priv, group_idx, false);
+			if (ret)
+				return ret;
+			break;
+		default:
+			return -ENOTSUPP;
+		}
+
+		configs++;
+	}
+
+	return 0;
+}
+
+static const struct pinconf_ops lochnagar_pin_conf_ops = {
+	.pin_config_group_set = lochnagar_conf_group_set,
+};
+
+static const struct pinctrl_desc lochnagar_pin_desc = {
+	.name = "lochnagar-pinctrl",
+	.owner = THIS_MODULE,
+
+	.pctlops = &lochnagar_pin_group_ops,
+	.pmxops = &lochnagar_pin_mux_ops,
+	.confops = &lochnagar_pin_conf_ops,
+};
+
+static void lochnagar_gpio_set(struct gpio_chip *chip,
+			       unsigned int offset, int value)
+{
+	struct lochnagar_pin_priv *priv = gpiochip_get_data(chip);
+	struct lochnagar *lochnagar = priv->lochnagar;
+	const struct lochnagar_pin *pin = priv->pins[offset].drv_data;
+	int ret;
+
+	value = !!value;
+
+	dev_dbg(priv->dev, "Set GPIO %s to %s\n",
+		pin->name, value ? "high" : "low");
+
+	switch (pin->type) {
+	case LN_PTYPE_MUX:
+		value |= LN2_OP_GPIO;
+
+		ret = lochnagar_pin_set_mux(priv, pin, value);
+		break;
+	case LN_PTYPE_GPIO:
+		if (pin->invert)
+			value = !value;
+
+		ret = regmap_update_bits(lochnagar->regmap, pin->reg,
+					 BIT(pin->shift), value << pin->shift);
+		break;
+	default:
+		ret = -EINVAL;
+		break;
+	}
+
+	if (ret < 0)
+		dev_err(chip->parent, "Failed to set %s value: %d\n",
+			pin->name, ret);
+}
+
+static int lochnagar_gpio_direction_out(struct gpio_chip *chip,
+					unsigned int offset, int value)
+{
+	lochnagar_gpio_set(chip, offset, value);
+
+	return pinctrl_gpio_direction_output(chip->base + offset);
+}
+
+static int lochnagar_fill_func_groups(struct lochnagar_pin_priv *priv)
+{
+	struct lochnagar_func_groups *funcs;
+	int i;
+
+	for (i = 0; i < priv->ngroups; i++)
+		priv->func_groups[priv->groups[i].type].ngroups++;
+
+	for (i = 0; i < LN_FTYPE_COUNT; i++) {
+		funcs = &priv->func_groups[i];
+
+		if (!funcs->ngroups)
+			continue;
+
+		funcs->groups = devm_kcalloc(priv->dev, funcs->ngroups,
+					     sizeof(*funcs->groups),
+					     GFP_KERNEL);
+		if (!funcs->groups)
+			return -ENOMEM;
+
+		funcs->ngroups = 0;
+	}
+
+	for (i = 0; i < priv->ngroups; i++) {
+		funcs = &priv->func_groups[priv->groups[i].type];
+
+		funcs->groups[funcs->ngroups++] = priv->groups[i].name;
+	}
+
+	return 0;
+}
+
+static int lochnagar_pin_probe(struct platform_device *pdev)
+{
+	struct lochnagar *lochnagar = dev_get_drvdata(pdev->dev.parent);
+	struct lochnagar_pin_priv *priv;
+	struct pinctrl_desc *desc;
+	struct pinctrl_dev *pctl;
+	struct device *dev = &pdev->dev;
+	int ret;
+
+	priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
+	if (!priv)
+		return -ENOMEM;
+
+	priv->dev = dev;
+	priv->lochnagar = lochnagar;
+
+	desc = devm_kzalloc(dev, sizeof(*desc), GFP_KERNEL);
+	if (!desc)
+		return -ENOMEM;
+
+	*desc = lochnagar_pin_desc;
+
+	priv->gpio_chip.label = dev_name(dev);
+	priv->gpio_chip.request = gpiochip_generic_request;
+	priv->gpio_chip.free = gpiochip_generic_free;
+	priv->gpio_chip.direction_output = lochnagar_gpio_direction_out;
+	priv->gpio_chip.set = lochnagar_gpio_set;
+	priv->gpio_chip.can_sleep = true;
+	priv->gpio_chip.parent = dev;
+	priv->gpio_chip.base = -1;
+#ifdef CONFIG_OF_GPIO
+	priv->gpio_chip.of_node = dev->of_node;
+#endif
+
+	switch (lochnagar->type) {
+	case LOCHNAGAR1:
+		priv->funcs = lochnagar1_funcs;
+		priv->nfuncs = ARRAY_SIZE(lochnagar1_funcs);
+		priv->pins = lochnagar1_pins;
+		priv->npins = ARRAY_SIZE(lochnagar1_pins);
+		priv->groups = lochnagar1_groups;
+		priv->ngroups = ARRAY_SIZE(lochnagar1_groups);
+
+		priv->gpio_chip.ngpio = LOCHNAGAR1_PIN_NUM_GPIOS;
+		break;
+	case LOCHNAGAR2:
+		priv->funcs = lochnagar2_funcs;
+		priv->nfuncs = ARRAY_SIZE(lochnagar2_funcs);
+		priv->pins = lochnagar2_pins;
+		priv->npins = ARRAY_SIZE(lochnagar2_pins);
+		priv->groups = lochnagar2_groups;
+		priv->ngroups = ARRAY_SIZE(lochnagar2_groups);
+
+		priv->gpio_chip.ngpio = LOCHNAGAR2_PIN_NUM_GPIOS;
+		break;
+	default:
+		dev_err(dev, "Unknown Lochnagar type: %d\n", lochnagar->type);
+		return -EINVAL;
+	}
+
+	ret = lochnagar_fill_func_groups(priv);
+	if (ret < 0)
+		return ret;
+
+	desc->pins = priv->pins;
+	desc->npins = priv->npins;
+
+	pctl = devm_pinctrl_register(dev, desc, priv);
+	if (IS_ERR(pctl)) {
+		ret = PTR_ERR(pctl);
+		dev_err(priv->dev, "Failed to register pinctrl: %d\n", ret);
+		return ret;
+	}
+
+	ret = devm_gpiochip_add_data(dev, &priv->gpio_chip, priv);
+	if (ret < 0) {
+		dev_err(&pdev->dev, "Failed to register gpiochip: %d\n", ret);
+		return ret;
+	}
+
+	return 0;
+}
+
+static const struct of_device_id lochnagar_of_match[] = {
+	{ .compatible = "cirrus,lochnagar-pinctrl" },
+	{},
+};
+
+static struct platform_driver lochnagar_pin_driver = {
+	.driver = {
+		.name = "lochnagar-pinctrl",
+		.of_match_table = of_match_ptr(lochnagar_of_match),
+	},
+
+	.probe = lochnagar_pin_probe,
+};
+module_platform_driver(lochnagar_pin_driver);
+
+MODULE_AUTHOR("Charles Keepax <ckeepax@opensource.cirrus.com>");
+MODULE_DESCRIPTION("Pinctrl driver for Cirrus Logic Lochnagar Board");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:lochnagar-pinctrl");
-- 
2.11.0


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

* Re: [PATCH v5 6/8] mfd: lochnagar: Add support for the Cirrus Logic Lochnagar
  2018-11-20 14:16 ` [PATCH v5 6/8] mfd: lochnagar: Add support for the Cirrus Logic Lochnagar Charles Keepax
@ 2018-11-23  9:00   ` kbuild test robot
  2018-11-23  9:15     ` Charles Keepax
  2018-11-28  9:22   ` Lee Jones
  1 sibling, 1 reply; 21+ messages in thread
From: kbuild test robot @ 2018-11-23  9:00 UTC (permalink / raw)
  To: Charles Keepax
  Cc: kbuild-all, lee.jones, mturquette, sboyd, broonie, linus.walleij,
	robh+dt, mark.rutland, lgirdwood, devicetree, linux-kernel,
	patches, linux-clk, linux-gpio

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

Hi Charles,

I love your patch! Yet something to improve:

[auto build test ERROR on ljones-mfd/for-mfd-next]
[also build test ERROR on v4.20-rc3]
[cannot apply to next-20181122]
[if your patch is applied to the wrong git tree, please drop us a note to help improve the system]

url:    https://github.com/0day-ci/linux/commits/Charles-Keepax/regulator-lochnagar-Move-driver-to-binding-from-DT/20181123-133943
base:   https://git.kernel.org/pub/scm/linux/kernel/git/lee/mfd.git for-mfd-next
config: sh-allyesconfig (attached as .config)
compiler: sh4-linux-gnu-gcc (Debian 7.2.0-11) 7.2.0
reproduce:
        wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross
        chmod +x ~/bin/make.cross
        # save the attached .config to linux build tree
        GCC_VERSION=7.2.0 make.cross ARCH=sh 

All errors (new ones prefixed by >>):

   In file included from arch/sh/include/asm/string.h:3:0,
                    from include/linux/string.h:20,
                    from include/linux/bitmap.h:9,
                    from include/linux/nodemask.h:95,
                    from include/linux/mmzone.h:17,
                    from include/linux/gfp.h:6,
                    from include/linux/umh.h:4,
                    from include/linux/kmod.h:22,
                    from include/linux/module.h:13,
                    from drivers/staging/media/bcm2048/radio-bcm2048.c:33:
   drivers/staging/media/bcm2048/radio-bcm2048.c: In function 'bcm2048_vidioc_g_audio':
   arch/sh/include/asm/string_32.h:50:42: warning: array subscript is above array bounds [-Warray-bounds]
      : "0" (__dest), "1" (__src), "r" (__src+__n)
                                        ~~~~~^~~~
   drivers/staging/iio/adc/ad7606_par.c: In function 'ad7606_par16_read_block':
   drivers/staging/iio/adc/ad7606_par.c:22:23: warning: unused variable 'st' [-Wunused-variable]
     struct ad7606_state *st = iio_priv(indio_dev);
                          ^~
   drivers/staging/iio/adc/ad7606_par.c: In function 'ad7606_par8_read_block':
   drivers/staging/iio/adc/ad7606_par.c:37:23: warning: unused variable 'st' [-Wunused-variable]
     struct ad7606_state *st = iio_priv(indio_dev);
                          ^~
   drivers/staging/media/bcm2048/radio-bcm2048.c: In function 'bcm2048_vidioc_g_tuner':
   arch/sh/include/asm/string_32.h:50:42: warning: array subscript is above array bounds [-Warray-bounds]
      : "0" (__dest), "1" (__src), "r" (__src+__n)
                                        ~~~~~^~~~
   drivers/thermal/broadcom/ns-thermal.c: In function 'ns_thermal_remove':
   drivers/thermal/broadcom/ns-thermal.c:81:21: warning: unused variable 'ns_thermal' [-Wunused-variable]
     struct ns_thermal *ns_thermal = platform_get_drvdata(pdev);
                        ^~~~~~~~~~
   In file included from arch/sh/include/asm/string.h:3:0,
                    from include/linux/string.h:20,
                    from include/linux/bitmap.h:9,
                    from include/linux/nodemask.h:95,
                    from include/linux/mmzone.h:17,
                    from include/linux/gfp.h:6,
                    from include/linux/umh.h:4,
                    from include/linux/kmod.h:22,
                    from include/linux/module.h:13,
                    from drivers/scsi/ch.c:10:
   drivers/scsi/ch.c: In function 'ch_ioctl':
   arch/sh/include/asm/string_32.h:50:42: warning: array subscript is above array bounds [-Warray-bounds]
      : "0" (__dest), "1" (__src), "r" (__src+__n)
                                        ~~~~~^~~~
   arch/sh/include/asm/string_32.h:50:42: warning: array subscript is above array bounds [-Warray-bounds]
      : "0" (__dest), "1" (__src), "r" (__src+__n)
                                        ~~~~~^~~~
   arch/sh/include/asm/string_32.h:50:42: warning: array subscript is above array bounds [-Warray-bounds]
      : "0" (__dest), "1" (__src), "r" (__src+__n)
                                        ~~~~~^~~~
   arch/sh/include/asm/string_32.h:50:42: warning: array subscript is above array bounds [-Warray-bounds]
      : "0" (__dest), "1" (__src), "r" (__src+__n)
                                        ~~~~~^~~~
   drivers/regulator/lochnagar-regulator.c: In function 'lochnagar_micbias_of_parse':
>> drivers/regulator/lochnagar-regulator.c:115:7: error: 'LOCHNAGAR2_P2_MICBIAS_SRC_SHIFT' undeclared (first use in this function); did you mean 'LOCHNAGAR_DEVICE_ID_SHIFT'?
          LOCHNAGAR2_P2_MICBIAS_SRC_SHIFT;
          ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
          LOCHNAGAR_DEVICE_ID_SHIFT
   drivers/regulator/lochnagar-regulator.c:115:7: note: each undeclared identifier is reported only once for each function it appears in
>> drivers/regulator/lochnagar-regulator.c:116:13: error: 'LOCHNAGAR2_P1_MICBIAS_SRC_MASK' undeclared (first use in this function); did you mean 'LOCHNAGAR2_P2_MICBIAS_SRC_SHIFT'?
     int mask = LOCHNAGAR2_P1_MICBIAS_SRC_MASK << shift;
                ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
                LOCHNAGAR2_P2_MICBIAS_SRC_SHIFT
   In file included from drivers/regulator/lochnagar-regulator.c:18:0:
>> drivers/regulator/lochnagar-regulator.c:124:7: error: 'LOCHNAGAR2_ANALOGUE_PATH_CTRL2' undeclared (first use in this function)
          LOCHNAGAR2_ANALOGUE_PATH_CTRL2,
          ^
   include/linux/regmap.h:77:31: note: in definition of macro 'regmap_update_bits'
     regmap_update_bits_base(map, reg, mask, val, NULL, false, false)
                                  ^~~
   drivers/regulator/lochnagar-regulator.c: At top level:
>> drivers/regulator/lochnagar-regulator.c:148:17: error: 'LOCHNAGAR2_MICVDD_CTRL1' undeclared here (not in a function); did you mean 'LOCHNAGAR_MICVDD'?
      .enable_reg = LOCHNAGAR2_MICVDD_CTRL1,
                    ^~~~~~~~~~~~~~~~~~~~~~~
                    LOCHNAGAR_MICVDD
>> drivers/regulator/lochnagar-regulator.c:149:18: error: 'LOCHNAGAR2_MICVDD_REG_ENA_MASK' undeclared here (not in a function); did you mean 'LOCHNAGAR2_MICVDD_CTRL1'?
      .enable_mask = LOCHNAGAR2_MICVDD_REG_ENA_MASK,
                     ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
                     LOCHNAGAR2_MICVDD_CTRL1
>> drivers/regulator/lochnagar-regulator.c:150:15: error: 'LOCHNAGAR2_MICVDD_CTRL2' undeclared here (not in a function); did you mean 'LOCHNAGAR2_MICVDD_CTRL1'?
      .vsel_reg = LOCHNAGAR2_MICVDD_CTRL2,
                  ^~~~~~~~~~~~~~~~~~~~~~~
                  LOCHNAGAR2_MICVDD_CTRL1
>> drivers/regulator/lochnagar-regulator.c:151:16: error: 'LOCHNAGAR2_MICVDD_VSEL_MASK' undeclared here (not in a function); did you mean 'LOCHNAGAR2_MICVDD_REG_ENA_MASK'?
      .vsel_mask = LOCHNAGAR2_MICVDD_VSEL_MASK,
                   ^~~~~~~~~~~~~~~~~~~~~~~~~~~
                   LOCHNAGAR2_MICVDD_REG_ENA_MASK
>> drivers/regulator/lochnagar-regulator.c:171:17: error: 'LOCHNAGAR2_ANALOGUE_PATH_CTRL2' undeclared here (not in a function); did you mean 'LOCHNAGAR2_MICVDD_CTRL2'?
      .enable_reg = LOCHNAGAR2_ANALOGUE_PATH_CTRL2,
                    ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
                    LOCHNAGAR2_MICVDD_CTRL2
>> drivers/regulator/lochnagar-regulator.c:172:18: error: 'LOCHNAGAR2_P1_INPUT_BIAS_ENA_MASK' undeclared here (not in a function); did you mean 'LOCHNAGAR2_MICVDD_REG_ENA_MASK'?
      .enable_mask = LOCHNAGAR2_P1_INPUT_BIAS_ENA_MASK,
                     ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
                     LOCHNAGAR2_MICVDD_REG_ENA_MASK
>> drivers/regulator/lochnagar-regulator.c:187:18: error: 'LOCHNAGAR2_P2_INPUT_BIAS_ENA_MASK' undeclared here (not in a function); did you mean 'LOCHNAGAR2_P1_INPUT_BIAS_ENA_MASK'?
      .enable_mask = LOCHNAGAR2_P2_INPUT_BIAS_ENA_MASK,
                     ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
                     LOCHNAGAR2_P1_INPUT_BIAS_ENA_MASK
>> drivers/regulator/lochnagar-regulator.c:201:17: error: 'LOCHNAGAR2_VDDCORE_CDC_CTRL1' undeclared here (not in a function); did you mean 'LOCHNAGAR2_MICVDD_CTRL1'?
      .enable_reg = LOCHNAGAR2_VDDCORE_CDC_CTRL1,
                    ^~~~~~~~~~~~~~~~~~~~~~~~~~~~
                    LOCHNAGAR2_MICVDD_CTRL1
>> drivers/regulator/lochnagar-regulator.c:202:18: error: 'LOCHNAGAR2_VDDCORE_CDC_REG_ENA_MASK' undeclared here (not in a function); did you mean 'LOCHNAGAR2_MICVDD_REG_ENA_MASK'?
      .enable_mask = LOCHNAGAR2_VDDCORE_CDC_REG_ENA_MASK,
                     ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
                     LOCHNAGAR2_MICVDD_REG_ENA_MASK
>> drivers/regulator/lochnagar-regulator.c:203:15: error: 'LOCHNAGAR2_VDDCORE_CDC_CTRL2' undeclared here (not in a function); did you mean 'LOCHNAGAR2_VDDCORE_CDC_CTRL1'?
      .vsel_reg = LOCHNAGAR2_VDDCORE_CDC_CTRL2,
                  ^~~~~~~~~~~~~~~~~~~~~~~~~~~~
                  LOCHNAGAR2_VDDCORE_CDC_CTRL1
>> drivers/regulator/lochnagar-regulator.c:204:16: error: 'LOCHNAGAR2_VDDCORE_CDC_VSEL_MASK' undeclared here (not in a function); did you mean 'LOCHNAGAR2_VDDCORE_CDC_REG_ENA_MASK'?
      .vsel_mask = LOCHNAGAR2_VDDCORE_CDC_VSEL_MASK,
                   ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
                   LOCHNAGAR2_VDDCORE_CDC_REG_ENA_MASK
   make[3]: *** [drivers/regulator/lochnagar-regulator.o] Error 1
   make[3]: Target '__build' not remade because of errors.
   make[2]: *** [drivers/regulator] Error 2
   In file included from arch/sh/include/asm/string.h:3:0,
                    from include/linux/string.h:20,
                    from include/linux/bitmap.h:9,
                    from include/linux/cpumask.h:12,
                    from include/linux/rcupdate.h:44,
                    from include/linux/radix-tree.h:28,
                    from include/linux/idr.h:15,
                    from include/linux/kernfs.h:14,
                    from include/linux/sysfs.h:16,
                    from include/linux/kobject.h:20,
                    from include/linux/device.h:16,
                    from include/linux/platform_device.h:14,
                    from drivers/tty/serial/xilinx_uartps.c:16:
   drivers/tty/serial/xilinx_uartps.c: In function 'cdns_uart_probe':
   arch/sh/include/asm/string_32.h:50:42: warning: array subscript is above array bounds [-Warray-bounds]
      : "0" (__dest), "1" (__src), "r" (__src+__n)
                                        ~~~~~^~~~
   In file included from arch/sh/include/asm/string.h:3:0,
                    from include/linux/string.h:20,
                    from include/linux/bitmap.h:9,
                    from include/linux/nodemask.h:95,
                    from include/linux/mmzone.h:17,
                    from include/linux/gfp.h:6,
                    from include/linux/umh.h:4,
                    from include/linux/kmod.h:22,
                    from include/linux/module.h:13,
                    from drivers/usb/gadget/udc/mv_u3d_core.c:6:
   drivers/usb/gadget/udc/mv_u3d_core.c: In function 'mv_u3d_probe':
   arch/sh/include/asm/string_32.h:50:42: warning: array subscript is above array bounds [-Warray-bounds]
      : "0" (__dest), "1" (__src), "r" (__src+__n)
                                        ~~~~~^~~~
   In file included from arch/sh/include/asm/string.h:3:0,
                    from include/linux/string.h:20,
                    from include/linux/bitmap.h:9,
                    from include/linux/nodemask.h:95,
                    from include/linux/mmzone.h:17,
                    from include/linux/gfp.h:6,
                    from include/linux/umh.h:4,
                    from include/linux/kmod.h:22,
                    from include/linux/module.h:13,
                    from drivers/usb/gadget/udc/mv_udc_core.c:8:
   drivers/usb/gadget/udc/mv_udc_core.c: In function 'mv_udc_probe':
   arch/sh/include/asm/string_32.h:50:42: warning: array subscript is above array bounds [-Warray-bounds]
      : "0" (__dest), "1" (__src), "r" (__src+__n)
                                        ~~~~~^~~~
   make[2]: Target '__build' not remade because of errors.

vim +115 drivers/regulator/lochnagar-regulator.c

bef9391c Charles Keepax 2018-10-08    9  
bef9391c Charles Keepax 2018-10-08   10  #include <linux/bitops.h>
bef9391c Charles Keepax 2018-10-08   11  #include <linux/device.h>
bef9391c Charles Keepax 2018-10-08   12  #include <linux/err.h>
bef9391c Charles Keepax 2018-10-08   13  #include <linux/module.h>
bef9391c Charles Keepax 2018-10-08   14  #include <linux/mutex.h>
bef9391c Charles Keepax 2018-10-08   15  #include <linux/of.h>
fda7f8cb Charles Keepax 2018-11-20   16  #include <linux/of_device.h>
bef9391c Charles Keepax 2018-10-08   17  #include <linux/platform_device.h>
bef9391c Charles Keepax 2018-10-08  @18  #include <linux/regmap.h>
bef9391c Charles Keepax 2018-10-08   19  #include <linux/regulator/driver.h>
bef9391c Charles Keepax 2018-10-08   20  #include <linux/regulator/machine.h>
bef9391c Charles Keepax 2018-10-08   21  #include <linux/regulator/of_regulator.h>
bef9391c Charles Keepax 2018-10-08   22  
bef9391c Charles Keepax 2018-10-08   23  #include <linux/mfd/lochnagar.h>
bef9391c Charles Keepax 2018-10-08   24  
bef9391c Charles Keepax 2018-10-08   25  static const struct regulator_ops lochnagar_micvdd_ops = {
bef9391c Charles Keepax 2018-10-08   26  	.enable = regulator_enable_regmap,
bef9391c Charles Keepax 2018-10-08   27  	.disable = regulator_disable_regmap,
bef9391c Charles Keepax 2018-10-08   28  	.is_enabled = regulator_is_enabled_regmap,
bef9391c Charles Keepax 2018-10-08   29  
bef9391c Charles Keepax 2018-10-08   30  	.list_voltage = regulator_list_voltage_linear_range,
bef9391c Charles Keepax 2018-10-08   31  	.map_voltage = regulator_map_voltage_linear_range,
bef9391c Charles Keepax 2018-10-08   32  
bef9391c Charles Keepax 2018-10-08   33  	.get_voltage_sel = regulator_get_voltage_sel_regmap,
bef9391c Charles Keepax 2018-10-08   34  	.set_voltage_sel = regulator_set_voltage_sel_regmap,
bef9391c Charles Keepax 2018-10-08   35  };
bef9391c Charles Keepax 2018-10-08   36  
bef9391c Charles Keepax 2018-10-08   37  static const struct regulator_linear_range lochnagar_micvdd_ranges[] = {
bef9391c Charles Keepax 2018-10-08   38  	REGULATOR_LINEAR_RANGE(1000000, 0,    0xC, 50000),
bef9391c Charles Keepax 2018-10-08   39  	REGULATOR_LINEAR_RANGE(1700000, 0xD, 0x1F, 100000),
bef9391c Charles Keepax 2018-10-08   40  };
bef9391c Charles Keepax 2018-10-08   41  
bef9391c Charles Keepax 2018-10-08   42  static int lochnagar_micbias_enable(struct regulator_dev *rdev)
bef9391c Charles Keepax 2018-10-08   43  {
bef9391c Charles Keepax 2018-10-08   44  	struct lochnagar *lochnagar = rdev_get_drvdata(rdev);
bef9391c Charles Keepax 2018-10-08   45  	int ret;
bef9391c Charles Keepax 2018-10-08   46  
bef9391c Charles Keepax 2018-10-08   47  	mutex_lock(&lochnagar->analogue_config_lock);
bef9391c Charles Keepax 2018-10-08   48  
bef9391c Charles Keepax 2018-10-08   49  	ret = regulator_enable_regmap(rdev);
bef9391c Charles Keepax 2018-10-08   50  	if (ret < 0)
bef9391c Charles Keepax 2018-10-08   51  		goto err;
bef9391c Charles Keepax 2018-10-08   52  
bef9391c Charles Keepax 2018-10-08   53  	ret = lochnagar_update_config(lochnagar);
bef9391c Charles Keepax 2018-10-08   54  
bef9391c Charles Keepax 2018-10-08   55  err:
bef9391c Charles Keepax 2018-10-08   56  	mutex_unlock(&lochnagar->analogue_config_lock);
bef9391c Charles Keepax 2018-10-08   57  
bef9391c Charles Keepax 2018-10-08   58  	return ret;
bef9391c Charles Keepax 2018-10-08   59  }
bef9391c Charles Keepax 2018-10-08   60  
bef9391c Charles Keepax 2018-10-08   61  static int lochnagar_micbias_disable(struct regulator_dev *rdev)
bef9391c Charles Keepax 2018-10-08   62  {
bef9391c Charles Keepax 2018-10-08   63  	struct lochnagar *lochnagar = rdev_get_drvdata(rdev);
bef9391c Charles Keepax 2018-10-08   64  	int ret;
bef9391c Charles Keepax 2018-10-08   65  
bef9391c Charles Keepax 2018-10-08   66  	mutex_lock(&lochnagar->analogue_config_lock);
bef9391c Charles Keepax 2018-10-08   67  
bef9391c Charles Keepax 2018-10-08   68  	ret = regulator_disable_regmap(rdev);
bef9391c Charles Keepax 2018-10-08   69  	if (ret < 0)
bef9391c Charles Keepax 2018-10-08   70  		goto err;
bef9391c Charles Keepax 2018-10-08   71  
bef9391c Charles Keepax 2018-10-08   72  	ret = lochnagar_update_config(lochnagar);
bef9391c Charles Keepax 2018-10-08   73  
bef9391c Charles Keepax 2018-10-08   74  err:
bef9391c Charles Keepax 2018-10-08   75  	mutex_unlock(&lochnagar->analogue_config_lock);
bef9391c Charles Keepax 2018-10-08   76  
bef9391c Charles Keepax 2018-10-08   77  	return ret;
bef9391c Charles Keepax 2018-10-08   78  }
bef9391c Charles Keepax 2018-10-08   79  
bef9391c Charles Keepax 2018-10-08   80  static const struct regulator_ops lochnagar_micbias_ops = {
bef9391c Charles Keepax 2018-10-08   81  	.enable = lochnagar_micbias_enable,
bef9391c Charles Keepax 2018-10-08   82  	.disable = lochnagar_micbias_disable,
bef9391c Charles Keepax 2018-10-08   83  	.is_enabled = regulator_is_enabled_regmap,
bef9391c Charles Keepax 2018-10-08   84  };
bef9391c Charles Keepax 2018-10-08   85  
bef9391c Charles Keepax 2018-10-08   86  static const struct regulator_ops lochnagar_vddcore_ops = {
bef9391c Charles Keepax 2018-10-08   87  	.enable = regulator_enable_regmap,
bef9391c Charles Keepax 2018-10-08   88  	.disable = regulator_disable_regmap,
bef9391c Charles Keepax 2018-10-08   89  	.is_enabled = regulator_is_enabled_regmap,
bef9391c Charles Keepax 2018-10-08   90  
bef9391c Charles Keepax 2018-10-08   91  	.list_voltage = regulator_list_voltage_linear_range,
bef9391c Charles Keepax 2018-10-08   92  	.map_voltage = regulator_map_voltage_linear_range,
bef9391c Charles Keepax 2018-10-08   93  
bef9391c Charles Keepax 2018-10-08   94  	.get_voltage_sel = regulator_get_voltage_sel_regmap,
bef9391c Charles Keepax 2018-10-08   95  	.set_voltage_sel = regulator_set_voltage_sel_regmap,
bef9391c Charles Keepax 2018-10-08   96  };
bef9391c Charles Keepax 2018-10-08   97  
bef9391c Charles Keepax 2018-10-08   98  static const struct regulator_linear_range lochnagar_vddcore_ranges[] = {
bef9391c Charles Keepax 2018-10-08   99  	REGULATOR_LINEAR_RANGE(600000, 0x8, 0x41, 12500),
bef9391c Charles Keepax 2018-10-08  100  };
bef9391c Charles Keepax 2018-10-08  101  
bef9391c Charles Keepax 2018-10-08  102  enum lochnagar_regulators {
bef9391c Charles Keepax 2018-10-08  103  	LOCHNAGAR_MICVDD,
bef9391c Charles Keepax 2018-10-08  104  	LOCHNAGAR_MIC1VDD,
bef9391c Charles Keepax 2018-10-08  105  	LOCHNAGAR_MIC2VDD,
bef9391c Charles Keepax 2018-10-08  106  	LOCHNAGAR_VDDCORE,
bef9391c Charles Keepax 2018-10-08  107  };
bef9391c Charles Keepax 2018-10-08  108  
bef9391c Charles Keepax 2018-10-08  109  static int lochnagar_micbias_of_parse(struct device_node *np,
bef9391c Charles Keepax 2018-10-08  110  				      const struct regulator_desc *desc,
bef9391c Charles Keepax 2018-10-08  111  				      struct regulator_config *config)
bef9391c Charles Keepax 2018-10-08  112  {
bef9391c Charles Keepax 2018-10-08  113  	struct lochnagar *lochnagar = config->driver_data;
bef9391c Charles Keepax 2018-10-08  114  	int shift = (desc->id - LOCHNAGAR_MIC1VDD) *
bef9391c Charles Keepax 2018-10-08 @115  		    LOCHNAGAR2_P2_MICBIAS_SRC_SHIFT;
bef9391c Charles Keepax 2018-10-08 @116  	int mask = LOCHNAGAR2_P1_MICBIAS_SRC_MASK << shift;
bef9391c Charles Keepax 2018-10-08  117  	unsigned int val;
bef9391c Charles Keepax 2018-10-08  118  	int ret;
bef9391c Charles Keepax 2018-10-08  119  
bef9391c Charles Keepax 2018-10-08  120  	ret = of_property_read_u32(np, "cirrus,micbias-input", &val);
bef9391c Charles Keepax 2018-10-08  121  	if (ret >= 0) {
bef9391c Charles Keepax 2018-10-08  122  		mutex_lock(&lochnagar->analogue_config_lock);
bef9391c Charles Keepax 2018-10-08  123  		ret = regmap_update_bits(lochnagar->regmap,
bef9391c Charles Keepax 2018-10-08 @124  					 LOCHNAGAR2_ANALOGUE_PATH_CTRL2,
bef9391c Charles Keepax 2018-10-08  125  					 mask, val << shift);
bef9391c Charles Keepax 2018-10-08  126  		mutex_unlock(&lochnagar->analogue_config_lock);
bef9391c Charles Keepax 2018-10-08  127  		if (ret < 0) {
bef9391c Charles Keepax 2018-10-08  128  			dev_err(lochnagar->dev,
bef9391c Charles Keepax 2018-10-08  129  				"Failed to update micbias source: %d\n", ret);
bef9391c Charles Keepax 2018-10-08  130  			return ret;
bef9391c Charles Keepax 2018-10-08  131  		}
bef9391c Charles Keepax 2018-10-08  132  	}
bef9391c Charles Keepax 2018-10-08  133  
bef9391c Charles Keepax 2018-10-08  134  	return 0;
bef9391c Charles Keepax 2018-10-08  135  }
bef9391c Charles Keepax 2018-10-08  136  
bef9391c Charles Keepax 2018-10-08  137  static const struct regulator_desc lochnagar_regulators[] = {
bef9391c Charles Keepax 2018-10-08  138  	[LOCHNAGAR_MICVDD] = {
bef9391c Charles Keepax 2018-10-08  139  		.name = "MICVDD",
bef9391c Charles Keepax 2018-10-08  140  		.supply_name = "SYSVDD",
bef9391c Charles Keepax 2018-10-08  141  		.type = REGULATOR_VOLTAGE,
bef9391c Charles Keepax 2018-10-08  142  		.n_voltages = 32,
bef9391c Charles Keepax 2018-10-08  143  		.ops = &lochnagar_micvdd_ops,
bef9391c Charles Keepax 2018-10-08  144  
bef9391c Charles Keepax 2018-10-08  145  		.id = LOCHNAGAR_MICVDD,
bef9391c Charles Keepax 2018-10-08  146  		.of_match = of_match_ptr("MICVDD"),
bef9391c Charles Keepax 2018-10-08  147  
bef9391c Charles Keepax 2018-10-08 @148  		.enable_reg = LOCHNAGAR2_MICVDD_CTRL1,
bef9391c Charles Keepax 2018-10-08 @149  		.enable_mask = LOCHNAGAR2_MICVDD_REG_ENA_MASK,
bef9391c Charles Keepax 2018-10-08 @150  		.vsel_reg = LOCHNAGAR2_MICVDD_CTRL2,
bef9391c Charles Keepax 2018-10-08 @151  		.vsel_mask = LOCHNAGAR2_MICVDD_VSEL_MASK,
bef9391c Charles Keepax 2018-10-08  152  
bef9391c Charles Keepax 2018-10-08  153  		.linear_ranges = lochnagar_micvdd_ranges,
bef9391c Charles Keepax 2018-10-08  154  		.n_linear_ranges = ARRAY_SIZE(lochnagar_micvdd_ranges),
bef9391c Charles Keepax 2018-10-08  155  
bef9391c Charles Keepax 2018-10-08  156  		.enable_time = 3000,
bef9391c Charles Keepax 2018-10-08  157  		.ramp_delay = 1000,
bef9391c Charles Keepax 2018-10-08  158  
bef9391c Charles Keepax 2018-10-08  159  		.owner = THIS_MODULE,
bef9391c Charles Keepax 2018-10-08  160  	},
bef9391c Charles Keepax 2018-10-08  161  	[LOCHNAGAR_MIC1VDD] = {
bef9391c Charles Keepax 2018-10-08  162  		.name = "MIC1VDD",
bef9391c Charles Keepax 2018-10-08  163  		.supply_name = "MICBIAS1",
bef9391c Charles Keepax 2018-10-08  164  		.type = REGULATOR_VOLTAGE,
bef9391c Charles Keepax 2018-10-08  165  		.ops = &lochnagar_micbias_ops,
bef9391c Charles Keepax 2018-10-08  166  
bef9391c Charles Keepax 2018-10-08  167  		.id = LOCHNAGAR_MIC1VDD,
bef9391c Charles Keepax 2018-10-08  168  		.of_match = of_match_ptr("MIC1VDD"),
bef9391c Charles Keepax 2018-10-08  169  		.of_parse_cb = lochnagar_micbias_of_parse,
bef9391c Charles Keepax 2018-10-08  170  
bef9391c Charles Keepax 2018-10-08 @171  		.enable_reg = LOCHNAGAR2_ANALOGUE_PATH_CTRL2,
bef9391c Charles Keepax 2018-10-08 @172  		.enable_mask = LOCHNAGAR2_P1_INPUT_BIAS_ENA_MASK,
bef9391c Charles Keepax 2018-10-08  173  
bef9391c Charles Keepax 2018-10-08  174  		.owner = THIS_MODULE,
bef9391c Charles Keepax 2018-10-08  175  	},
bef9391c Charles Keepax 2018-10-08  176  	[LOCHNAGAR_MIC2VDD] = {
bef9391c Charles Keepax 2018-10-08  177  		.name = "MIC2VDD",
bef9391c Charles Keepax 2018-10-08  178  		.supply_name = "MICBIAS2",
bef9391c Charles Keepax 2018-10-08  179  		.type = REGULATOR_VOLTAGE,
bef9391c Charles Keepax 2018-10-08  180  		.ops = &lochnagar_micbias_ops,
bef9391c Charles Keepax 2018-10-08  181  
bef9391c Charles Keepax 2018-10-08  182  		.id = LOCHNAGAR_MIC2VDD,
bef9391c Charles Keepax 2018-10-08  183  		.of_match = of_match_ptr("MIC2VDD"),
bef9391c Charles Keepax 2018-10-08  184  		.of_parse_cb = lochnagar_micbias_of_parse,
bef9391c Charles Keepax 2018-10-08  185  
bef9391c Charles Keepax 2018-10-08  186  		.enable_reg = LOCHNAGAR2_ANALOGUE_PATH_CTRL2,
bef9391c Charles Keepax 2018-10-08 @187  		.enable_mask = LOCHNAGAR2_P2_INPUT_BIAS_ENA_MASK,
bef9391c Charles Keepax 2018-10-08  188  
bef9391c Charles Keepax 2018-10-08  189  		.owner = THIS_MODULE,
bef9391c Charles Keepax 2018-10-08  190  	},
bef9391c Charles Keepax 2018-10-08  191  	[LOCHNAGAR_VDDCORE] = {
bef9391c Charles Keepax 2018-10-08  192  		.name = "VDDCORE",
bef9391c Charles Keepax 2018-10-08  193  		.supply_name = "SYSVDD",
bef9391c Charles Keepax 2018-10-08  194  		.type = REGULATOR_VOLTAGE,
bef9391c Charles Keepax 2018-10-08  195  		.n_voltages = 57,
bef9391c Charles Keepax 2018-10-08  196  		.ops = &lochnagar_vddcore_ops,
bef9391c Charles Keepax 2018-10-08  197  
bef9391c Charles Keepax 2018-10-08  198  		.id = LOCHNAGAR_VDDCORE,
bef9391c Charles Keepax 2018-10-08  199  		.of_match = of_match_ptr("VDDCORE"),
bef9391c Charles Keepax 2018-10-08  200  
bef9391c Charles Keepax 2018-10-08 @201  		.enable_reg = LOCHNAGAR2_VDDCORE_CDC_CTRL1,
bef9391c Charles Keepax 2018-10-08 @202  		.enable_mask = LOCHNAGAR2_VDDCORE_CDC_REG_ENA_MASK,
bef9391c Charles Keepax 2018-10-08 @203  		.vsel_reg = LOCHNAGAR2_VDDCORE_CDC_CTRL2,
bef9391c Charles Keepax 2018-10-08 @204  		.vsel_mask = LOCHNAGAR2_VDDCORE_CDC_VSEL_MASK,
bef9391c Charles Keepax 2018-10-08  205  
bef9391c Charles Keepax 2018-10-08  206  		.linear_ranges = lochnagar_vddcore_ranges,
bef9391c Charles Keepax 2018-10-08  207  		.n_linear_ranges = ARRAY_SIZE(lochnagar_vddcore_ranges),
bef9391c Charles Keepax 2018-10-08  208  
bef9391c Charles Keepax 2018-10-08  209  		.enable_time = 3000,
bef9391c Charles Keepax 2018-10-08  210  		.ramp_delay = 1000,
bef9391c Charles Keepax 2018-10-08  211  
bef9391c Charles Keepax 2018-10-08  212  		.owner = THIS_MODULE,
bef9391c Charles Keepax 2018-10-08  213  	},
bef9391c Charles Keepax 2018-10-08  214  };
bef9391c Charles Keepax 2018-10-08  215  

:::::: The code at line 115 was first introduced by commit
:::::: bef9391cbec547351c6a13e52f3a26bb2d271ec7 regulator: lochnagar: Add support for the Cirrus Logic Lochnagar

:::::: TO: Charles Keepax <ckeepax@opensource.wolfsonmicro.com>
:::::: CC: Mark Brown <broonie@kernel.org>

---
0-DAY kernel test infrastructure                Open Source Technology Center
https://lists.01.org/pipermail/kbuild-all                   Intel Corporation

[-- Attachment #2: .config.gz --]
[-- Type: application/gzip, Size: 50582 bytes --]

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

* Re: [PATCH v5 6/8] mfd: lochnagar: Add support for the Cirrus Logic Lochnagar
  2018-11-23  9:00   ` kbuild test robot
@ 2018-11-23  9:15     ` Charles Keepax
  0 siblings, 0 replies; 21+ messages in thread
From: Charles Keepax @ 2018-11-23  9:15 UTC (permalink / raw)
  To: lee.jones
  Cc: kbuild-all, lee.jones, mturquette, sboyd, broonie, linus.walleij,
	robh+dt, mark.rutland, lgirdwood, devicetree, linux-kernel,
	patches, linux-clk, linux-gpio

On Fri, Nov 23, 2018 at 05:00:57PM +0800, kbuild test robot wrote:
> Hi Charles,
> 
> I love your patch! Yet something to improve:
> 
> [auto build test ERROR on ljones-mfd/for-mfd-next]
> [also build test ERROR on v4.20-rc3]
> [cannot apply to next-20181122]
> [if your patch is applied to the wrong git tree, please drop us a note to help improve the system]
>    drivers/regulator/lochnagar-regulator.c: In function 'lochnagar_micbias_of_parse':

> >> drivers/regulator/lochnagar-regulator.c:115:7: error: 'LOCHNAGAR2_P2_MICBIAS_SRC_SHIFT' undeclared (first use in this function); did you mean 'LOCHNAGAR_DEVICE_ID_SHIFT'?
>           LOCHNAGAR2_P2_MICBIAS_SRC_SHIFT;
>           ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

These issues will resolve themselves in the merge, this patch is
already merged in Mark's tree and will resolve the issue:

fa2bb8b97d77 ("regulator: lochnagar: Explicitly include register headers")

Thanks,
Charles

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

* Re: [PATCH v5 8/8] pinctrl: lochnagar: Add support for the Cirrus Logic Lochnagar
  2018-11-20 14:16 ` [PATCH v5 8/8] pinctrl: " Charles Keepax
@ 2018-11-24 16:11   ` kbuild test robot
  0 siblings, 0 replies; 21+ messages in thread
From: kbuild test robot @ 2018-11-24 16:11 UTC (permalink / raw)
  To: Charles Keepax
  Cc: kbuild-all, lee.jones, mturquette, sboyd, broonie, linus.walleij,
	robh+dt, mark.rutland, lgirdwood, devicetree, linux-kernel,
	patches, linux-clk, linux-gpio

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

Hi Charles,

I love your patch! Yet something to improve:

[auto build test ERROR on ljones-mfd/for-mfd-next]
[also build test ERROR on v4.20-rc3]
[cannot apply to next-20181123]
[if your patch is applied to the wrong git tree, please drop us a note to help improve the system]

url:    https://github.com/0day-ci/linux/commits/Charles-Keepax/regulator-lochnagar-Move-driver-to-binding-from-DT/20181123-133943
base:   https://git.kernel.org/pub/scm/linux/kernel/git/lee/mfd.git for-mfd-next
config: x86_64-allmodconfig (attached as .config)
compiler: gcc-7 (Debian 7.3.0-1) 7.3.0
reproduce:
        # save the attached .config to linux build tree
        make ARCH=x86_64 

All errors (new ones prefixed by >>):

>> drivers/regulator/lochnagar-regulator.c:115:21: error: undefined identifier 'LOCHNAGAR2_P2_MICBIAS_SRC_SHIFT'
>> drivers/regulator/lochnagar-regulator.c:116:20: error: undefined identifier 'LOCHNAGAR2_P1_MICBIAS_SRC_MASK'
>> drivers/regulator/lochnagar-regulator.c:123:23: error: undefined identifier 'LOCHNAGAR2_ANALOGUE_PATH_CTRL2'
>> drivers/regulator/lochnagar-regulator.c:148:31: error: undefined identifier 'LOCHNAGAR2_MICVDD_CTRL1'
>> drivers/regulator/lochnagar-regulator.c:149:32: error: undefined identifier 'LOCHNAGAR2_MICVDD_REG_ENA_MASK'
>> drivers/regulator/lochnagar-regulator.c:150:29: error: undefined identifier 'LOCHNAGAR2_MICVDD_CTRL2'
>> drivers/regulator/lochnagar-regulator.c:151:30: error: undefined identifier 'LOCHNAGAR2_MICVDD_VSEL_MASK'
   drivers/regulator/lochnagar-regulator.c:171:31: error: undefined identifier 'LOCHNAGAR2_ANALOGUE_PATH_CTRL2'
>> drivers/regulator/lochnagar-regulator.c:172:32: error: undefined identifier 'LOCHNAGAR2_P1_INPUT_BIAS_ENA_MASK'
   drivers/regulator/lochnagar-regulator.c:186:31: error: undefined identifier 'LOCHNAGAR2_ANALOGUE_PATH_CTRL2'
>> drivers/regulator/lochnagar-regulator.c:187:32: error: undefined identifier 'LOCHNAGAR2_P2_INPUT_BIAS_ENA_MASK'
>> drivers/regulator/lochnagar-regulator.c:201:31: error: undefined identifier 'LOCHNAGAR2_VDDCORE_CDC_CTRL1'
>> drivers/regulator/lochnagar-regulator.c:202:32: error: undefined identifier 'LOCHNAGAR2_VDDCORE_CDC_REG_ENA_MASK'
>> drivers/regulator/lochnagar-regulator.c:203:29: error: undefined identifier 'LOCHNAGAR2_VDDCORE_CDC_CTRL2'
>> drivers/regulator/lochnagar-regulator.c:204:30: error: undefined identifier 'LOCHNAGAR2_VDDCORE_CDC_VSEL_MASK'
   drivers/regulator/lochnagar-regulator.c: In function 'lochnagar_micbias_of_parse':
   drivers/regulator/lochnagar-regulator.c:115:7: error: 'LOCHNAGAR2_P2_MICBIAS_SRC_SHIFT' undeclared (first use in this function); did you mean 'LOCHNAGAR_DEVICE_ID_SHIFT'?
          LOCHNAGAR2_P2_MICBIAS_SRC_SHIFT;
          ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
          LOCHNAGAR_DEVICE_ID_SHIFT
   drivers/regulator/lochnagar-regulator.c:115:7: note: each undeclared identifier is reported only once for each function it appears in
   drivers/regulator/lochnagar-regulator.c:116:13: error: 'LOCHNAGAR2_P1_MICBIAS_SRC_MASK' undeclared (first use in this function); did you mean 'LOCHNAGAR2_P2_MICBIAS_SRC_SHIFT'?
     int mask = LOCHNAGAR2_P1_MICBIAS_SRC_MASK << shift;
                ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
                LOCHNAGAR2_P2_MICBIAS_SRC_SHIFT
   In file included from drivers/regulator/lochnagar-regulator.c:18:0:
   drivers/regulator/lochnagar-regulator.c:124:7: error: 'LOCHNAGAR2_ANALOGUE_PATH_CTRL2' undeclared (first use in this function)
          LOCHNAGAR2_ANALOGUE_PATH_CTRL2,
          ^
   include/linux/regmap.h:77:31: note: in definition of macro 'regmap_update_bits'
     regmap_update_bits_base(map, reg, mask, val, NULL, false, false)
                                  ^~~
   drivers/regulator/lochnagar-regulator.c: At top level:
   drivers/regulator/lochnagar-regulator.c:148:17: error: 'LOCHNAGAR2_MICVDD_CTRL1' undeclared here (not in a function); did you mean 'LOCHNAGAR_MICVDD'?
      .enable_reg = LOCHNAGAR2_MICVDD_CTRL1,
                    ^~~~~~~~~~~~~~~~~~~~~~~
                    LOCHNAGAR_MICVDD
   drivers/regulator/lochnagar-regulator.c:149:18: error: 'LOCHNAGAR2_MICVDD_REG_ENA_MASK' undeclared here (not in a function); did you mean 'LOCHNAGAR2_MICVDD_CTRL1'?
      .enable_mask = LOCHNAGAR2_MICVDD_REG_ENA_MASK,
                     ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
                     LOCHNAGAR2_MICVDD_CTRL1
   drivers/regulator/lochnagar-regulator.c:150:15: error: 'LOCHNAGAR2_MICVDD_CTRL2' undeclared here (not in a function); did you mean 'LOCHNAGAR2_MICVDD_CTRL1'?
      .vsel_reg = LOCHNAGAR2_MICVDD_CTRL2,
                  ^~~~~~~~~~~~~~~~~~~~~~~
                  LOCHNAGAR2_MICVDD_CTRL1
   drivers/regulator/lochnagar-regulator.c:151:16: error: 'LOCHNAGAR2_MICVDD_VSEL_MASK' undeclared here (not in a function); did you mean 'LOCHNAGAR2_MICVDD_REG_ENA_MASK'?
      .vsel_mask = LOCHNAGAR2_MICVDD_VSEL_MASK,
                   ^~~~~~~~~~~~~~~~~~~~~~~~~~~
                   LOCHNAGAR2_MICVDD_REG_ENA_MASK
   drivers/regulator/lochnagar-regulator.c:171:17: error: 'LOCHNAGAR2_ANALOGUE_PATH_CTRL2' undeclared here (not in a function); did you mean 'LOCHNAGAR2_MICVDD_CTRL2'?
      .enable_reg = LOCHNAGAR2_ANALOGUE_PATH_CTRL2,
                    ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
                    LOCHNAGAR2_MICVDD_CTRL2
   drivers/regulator/lochnagar-regulator.c:172:18: error: 'LOCHNAGAR2_P1_INPUT_BIAS_ENA_MASK' undeclared here (not in a function); did you mean 'LOCHNAGAR2_MICVDD_REG_ENA_MASK'?
      .enable_mask = LOCHNAGAR2_P1_INPUT_BIAS_ENA_MASK,
                     ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
                     LOCHNAGAR2_MICVDD_REG_ENA_MASK
   drivers/regulator/lochnagar-regulator.c:187:18: error: 'LOCHNAGAR2_P2_INPUT_BIAS_ENA_MASK' undeclared here (not in a function); did you mean 'LOCHNAGAR2_P1_INPUT_BIAS_ENA_MASK'?
      .enable_mask = LOCHNAGAR2_P2_INPUT_BIAS_ENA_MASK,
                     ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
                     LOCHNAGAR2_P1_INPUT_BIAS_ENA_MASK
   drivers/regulator/lochnagar-regulator.c:201:17: error: 'LOCHNAGAR2_VDDCORE_CDC_CTRL1' undeclared here (not in a function); did you mean 'LOCHNAGAR2_MICVDD_CTRL1'?
      .enable_reg = LOCHNAGAR2_VDDCORE_CDC_CTRL1,
                    ^~~~~~~~~~~~~~~~~~~~~~~~~~~~
                    LOCHNAGAR2_MICVDD_CTRL1
   drivers/regulator/lochnagar-regulator.c:202:18: error: 'LOCHNAGAR2_VDDCORE_CDC_REG_ENA_MASK' undeclared here (not in a function); did you mean 'LOCHNAGAR2_MICVDD_REG_ENA_MASK'?
      .enable_mask = LOCHNAGAR2_VDDCORE_CDC_REG_ENA_MASK,
                     ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
                     LOCHNAGAR2_MICVDD_REG_ENA_MASK
   drivers/regulator/lochnagar-regulator.c:203:15: error: 'LOCHNAGAR2_VDDCORE_CDC_CTRL2' undeclared here (not in a function); did you mean 'LOCHNAGAR2_VDDCORE_CDC_CTRL1'?
      .vsel_reg = LOCHNAGAR2_VDDCORE_CDC_CTRL2,
                  ^~~~~~~~~~~~~~~~~~~~~~~~~~~~
                  LOCHNAGAR2_VDDCORE_CDC_CTRL1
   drivers/regulator/lochnagar-regulator.c:204:16: error: 'LOCHNAGAR2_VDDCORE_CDC_VSEL_MASK' undeclared here (not in a function); did you mean 'LOCHNAGAR2_VDDCORE_CDC_REG_ENA_MASK'?
      .vsel_mask = LOCHNAGAR2_VDDCORE_CDC_VSEL_MASK,
                   ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
                   LOCHNAGAR2_VDDCORE_CDC_REG_ENA_MASK

vim +/LOCHNAGAR2_P2_MICBIAS_SRC_SHIFT +115 drivers/regulator/lochnagar-regulator.c

bef9391c Charles Keepax 2018-10-08  108  
bef9391c Charles Keepax 2018-10-08  109  static int lochnagar_micbias_of_parse(struct device_node *np,
bef9391c Charles Keepax 2018-10-08  110  				      const struct regulator_desc *desc,
bef9391c Charles Keepax 2018-10-08  111  				      struct regulator_config *config)
bef9391c Charles Keepax 2018-10-08  112  {
bef9391c Charles Keepax 2018-10-08  113  	struct lochnagar *lochnagar = config->driver_data;
bef9391c Charles Keepax 2018-10-08  114  	int shift = (desc->id - LOCHNAGAR_MIC1VDD) *
bef9391c Charles Keepax 2018-10-08 @115  		    LOCHNAGAR2_P2_MICBIAS_SRC_SHIFT;
bef9391c Charles Keepax 2018-10-08 @116  	int mask = LOCHNAGAR2_P1_MICBIAS_SRC_MASK << shift;
bef9391c Charles Keepax 2018-10-08  117  	unsigned int val;
bef9391c Charles Keepax 2018-10-08  118  	int ret;
bef9391c Charles Keepax 2018-10-08  119  
bef9391c Charles Keepax 2018-10-08  120  	ret = of_property_read_u32(np, "cirrus,micbias-input", &val);
bef9391c Charles Keepax 2018-10-08  121  	if (ret >= 0) {
bef9391c Charles Keepax 2018-10-08  122  		mutex_lock(&lochnagar->analogue_config_lock);
bef9391c Charles Keepax 2018-10-08 @123  		ret = regmap_update_bits(lochnagar->regmap,
bef9391c Charles Keepax 2018-10-08  124  					 LOCHNAGAR2_ANALOGUE_PATH_CTRL2,
bef9391c Charles Keepax 2018-10-08  125  					 mask, val << shift);
bef9391c Charles Keepax 2018-10-08  126  		mutex_unlock(&lochnagar->analogue_config_lock);
bef9391c Charles Keepax 2018-10-08  127  		if (ret < 0) {
bef9391c Charles Keepax 2018-10-08  128  			dev_err(lochnagar->dev,
bef9391c Charles Keepax 2018-10-08  129  				"Failed to update micbias source: %d\n", ret);
bef9391c Charles Keepax 2018-10-08  130  			return ret;
bef9391c Charles Keepax 2018-10-08  131  		}
bef9391c Charles Keepax 2018-10-08  132  	}
bef9391c Charles Keepax 2018-10-08  133  
bef9391c Charles Keepax 2018-10-08  134  	return 0;
bef9391c Charles Keepax 2018-10-08  135  }
bef9391c Charles Keepax 2018-10-08  136  
bef9391c Charles Keepax 2018-10-08  137  static const struct regulator_desc lochnagar_regulators[] = {
bef9391c Charles Keepax 2018-10-08  138  	[LOCHNAGAR_MICVDD] = {
bef9391c Charles Keepax 2018-10-08  139  		.name = "MICVDD",
bef9391c Charles Keepax 2018-10-08  140  		.supply_name = "SYSVDD",
bef9391c Charles Keepax 2018-10-08  141  		.type = REGULATOR_VOLTAGE,
bef9391c Charles Keepax 2018-10-08  142  		.n_voltages = 32,
bef9391c Charles Keepax 2018-10-08  143  		.ops = &lochnagar_micvdd_ops,
bef9391c Charles Keepax 2018-10-08  144  
bef9391c Charles Keepax 2018-10-08  145  		.id = LOCHNAGAR_MICVDD,
bef9391c Charles Keepax 2018-10-08  146  		.of_match = of_match_ptr("MICVDD"),
bef9391c Charles Keepax 2018-10-08  147  
bef9391c Charles Keepax 2018-10-08 @148  		.enable_reg = LOCHNAGAR2_MICVDD_CTRL1,
bef9391c Charles Keepax 2018-10-08 @149  		.enable_mask = LOCHNAGAR2_MICVDD_REG_ENA_MASK,
bef9391c Charles Keepax 2018-10-08 @150  		.vsel_reg = LOCHNAGAR2_MICVDD_CTRL2,
bef9391c Charles Keepax 2018-10-08 @151  		.vsel_mask = LOCHNAGAR2_MICVDD_VSEL_MASK,
bef9391c Charles Keepax 2018-10-08  152  
bef9391c Charles Keepax 2018-10-08  153  		.linear_ranges = lochnagar_micvdd_ranges,
bef9391c Charles Keepax 2018-10-08  154  		.n_linear_ranges = ARRAY_SIZE(lochnagar_micvdd_ranges),
bef9391c Charles Keepax 2018-10-08  155  
bef9391c Charles Keepax 2018-10-08  156  		.enable_time = 3000,
bef9391c Charles Keepax 2018-10-08  157  		.ramp_delay = 1000,
bef9391c Charles Keepax 2018-10-08  158  
bef9391c Charles Keepax 2018-10-08  159  		.owner = THIS_MODULE,
bef9391c Charles Keepax 2018-10-08  160  	},
bef9391c Charles Keepax 2018-10-08  161  	[LOCHNAGAR_MIC1VDD] = {
bef9391c Charles Keepax 2018-10-08  162  		.name = "MIC1VDD",
bef9391c Charles Keepax 2018-10-08  163  		.supply_name = "MICBIAS1",
bef9391c Charles Keepax 2018-10-08  164  		.type = REGULATOR_VOLTAGE,
bef9391c Charles Keepax 2018-10-08  165  		.ops = &lochnagar_micbias_ops,
bef9391c Charles Keepax 2018-10-08  166  
bef9391c Charles Keepax 2018-10-08  167  		.id = LOCHNAGAR_MIC1VDD,
bef9391c Charles Keepax 2018-10-08  168  		.of_match = of_match_ptr("MIC1VDD"),
bef9391c Charles Keepax 2018-10-08  169  		.of_parse_cb = lochnagar_micbias_of_parse,
bef9391c Charles Keepax 2018-10-08  170  
bef9391c Charles Keepax 2018-10-08  171  		.enable_reg = LOCHNAGAR2_ANALOGUE_PATH_CTRL2,
bef9391c Charles Keepax 2018-10-08 @172  		.enable_mask = LOCHNAGAR2_P1_INPUT_BIAS_ENA_MASK,
bef9391c Charles Keepax 2018-10-08  173  
bef9391c Charles Keepax 2018-10-08  174  		.owner = THIS_MODULE,
bef9391c Charles Keepax 2018-10-08  175  	},
bef9391c Charles Keepax 2018-10-08  176  	[LOCHNAGAR_MIC2VDD] = {
bef9391c Charles Keepax 2018-10-08  177  		.name = "MIC2VDD",
bef9391c Charles Keepax 2018-10-08  178  		.supply_name = "MICBIAS2",
bef9391c Charles Keepax 2018-10-08  179  		.type = REGULATOR_VOLTAGE,
bef9391c Charles Keepax 2018-10-08  180  		.ops = &lochnagar_micbias_ops,
bef9391c Charles Keepax 2018-10-08  181  
bef9391c Charles Keepax 2018-10-08  182  		.id = LOCHNAGAR_MIC2VDD,
bef9391c Charles Keepax 2018-10-08  183  		.of_match = of_match_ptr("MIC2VDD"),
bef9391c Charles Keepax 2018-10-08  184  		.of_parse_cb = lochnagar_micbias_of_parse,
bef9391c Charles Keepax 2018-10-08  185  
bef9391c Charles Keepax 2018-10-08  186  		.enable_reg = LOCHNAGAR2_ANALOGUE_PATH_CTRL2,
bef9391c Charles Keepax 2018-10-08 @187  		.enable_mask = LOCHNAGAR2_P2_INPUT_BIAS_ENA_MASK,
bef9391c Charles Keepax 2018-10-08  188  
bef9391c Charles Keepax 2018-10-08  189  		.owner = THIS_MODULE,
bef9391c Charles Keepax 2018-10-08  190  	},
bef9391c Charles Keepax 2018-10-08  191  	[LOCHNAGAR_VDDCORE] = {
bef9391c Charles Keepax 2018-10-08  192  		.name = "VDDCORE",
bef9391c Charles Keepax 2018-10-08  193  		.supply_name = "SYSVDD",
bef9391c Charles Keepax 2018-10-08  194  		.type = REGULATOR_VOLTAGE,
bef9391c Charles Keepax 2018-10-08  195  		.n_voltages = 57,
bef9391c Charles Keepax 2018-10-08  196  		.ops = &lochnagar_vddcore_ops,
bef9391c Charles Keepax 2018-10-08  197  
bef9391c Charles Keepax 2018-10-08  198  		.id = LOCHNAGAR_VDDCORE,
bef9391c Charles Keepax 2018-10-08  199  		.of_match = of_match_ptr("VDDCORE"),
bef9391c Charles Keepax 2018-10-08  200  
bef9391c Charles Keepax 2018-10-08 @201  		.enable_reg = LOCHNAGAR2_VDDCORE_CDC_CTRL1,
bef9391c Charles Keepax 2018-10-08 @202  		.enable_mask = LOCHNAGAR2_VDDCORE_CDC_REG_ENA_MASK,
bef9391c Charles Keepax 2018-10-08 @203  		.vsel_reg = LOCHNAGAR2_VDDCORE_CDC_CTRL2,
bef9391c Charles Keepax 2018-10-08 @204  		.vsel_mask = LOCHNAGAR2_VDDCORE_CDC_VSEL_MASK,
bef9391c Charles Keepax 2018-10-08  205  
bef9391c Charles Keepax 2018-10-08  206  		.linear_ranges = lochnagar_vddcore_ranges,
bef9391c Charles Keepax 2018-10-08  207  		.n_linear_ranges = ARRAY_SIZE(lochnagar_vddcore_ranges),
bef9391c Charles Keepax 2018-10-08  208  
bef9391c Charles Keepax 2018-10-08  209  		.enable_time = 3000,
bef9391c Charles Keepax 2018-10-08  210  		.ramp_delay = 1000,
bef9391c Charles Keepax 2018-10-08  211  
bef9391c Charles Keepax 2018-10-08  212  		.owner = THIS_MODULE,
bef9391c Charles Keepax 2018-10-08  213  	},
bef9391c Charles Keepax 2018-10-08  214  };
bef9391c Charles Keepax 2018-10-08  215  

:::::: The code at line 115 was first introduced by commit
:::::: bef9391cbec547351c6a13e52f3a26bb2d271ec7 regulator: lochnagar: Add support for the Cirrus Logic Lochnagar

:::::: TO: Charles Keepax <ckeepax@opensource.wolfsonmicro.com>
:::::: CC: Mark Brown <broonie@kernel.org>

---
0-DAY kernel test infrastructure                Open Source Technology Center
https://lists.01.org/pipermail/kbuild-all                   Intel Corporation

[-- Attachment #2: .config.gz --]
[-- Type: application/gzip, Size: 66634 bytes --]

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

* Re: [PATCH v5 3/8] clk: lochnagar: Add initial binding documentation
  2018-11-20 14:16 ` [PATCH v5 3/8] clk: " Charles Keepax
@ 2018-11-26 20:16   ` Rob Herring
  2018-11-27  9:34     ` Charles Keepax
  0 siblings, 1 reply; 21+ messages in thread
From: Rob Herring @ 2018-11-26 20:16 UTC (permalink / raw)
  To: Charles Keepax
  Cc: lee.jones, mturquette, sboyd, broonie, linus.walleij,
	mark.rutland, lgirdwood, devicetree, linux-kernel, patches,
	linux-clk, linux-gpio

On Tue, Nov 20, 2018 at 02:16:26PM +0000, Charles Keepax wrote:
> Lochnagar is an evaluation and development board for Cirrus
> Logic Smart CODEC and Amp devices. It allows the connection of
> most Cirrus Logic devices on mini-cards, as well as allowing
> connection of various application processor systems to provide a
> full evaluation platform. This driver supports the board
> controller chip on the Lochnagar board.
> 
> Signed-off-by: Charles Keepax <ckeepax@opensource.cirrus.com>
> ---
>  .../devicetree/bindings/clock/cirrus,lochnagar.txt | 89 ++++++++++++++++++++++
>  1 file changed, 89 insertions(+)
>  create mode 100644 Documentation/devicetree/bindings/clock/cirrus,lochnagar.txt
> 
> diff --git a/Documentation/devicetree/bindings/clock/cirrus,lochnagar.txt b/Documentation/devicetree/bindings/clock/cirrus,lochnagar.txt
> new file mode 100644
> index 000000000000..c1b5478d5432
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/clock/cirrus,lochnagar.txt
> @@ -0,0 +1,89 @@
> +Cirrus Logic Lochnagar Audio Development Board
> +
> +Lochnagar is an evaluation and development board for Cirrus Logic
> +Smart CODEC and Amp devices. It allows the connection of most Cirrus
> +Logic devices on mini-cards, as well as allowing connection of
> +various application processor systems to provide a full evaluation
> +platform.  Audio system topology, clocking and power can all be
> +controlled through the Lochnagar, allowing the device under test
> +to be used in a variety of possible use cases.
> +
> +This binding document describes the binding for the clock portion of
> +the driver.
> +
> +Also see these documents for generic binding information:
> +  [1] Clock : ../clock/clock-bindings.txt
> +
> +And these for relevant defines:
> +  [2] include/dt-bindings/clock/lochnagar.h
> +
> +This binding must be part of the Lochnagar MFD binding:
> +  [3] ../mfd/cirrus,lochnagar.txt
> +
> +Required properties:
> +
> +  - compatible : One of the following strings:
> +                 "cirrus,lochnagar1-clk"
> +                 "cirrus,lochnagar2-clk"

What's the 1 vs. 2?

> +
> +  - #clock-cells : Must be 1. The first cell indicates the clock
> +    number, see [2] for available clocks and [1].
> +
> +Optional properties:
> +
> +  - clocks : Must contain an entry for each clock in clock-names.
> +  - clock-names : May contain entries for each of the following
> +    clocks:
> +     - ln-cdc-clkout : Output clock from CODEC card.
> +     - ln-dsp-clkout : Output clock from DSP card.
> +     - ln-gf-mclk1,ln-gf-mclk2,ln-gf-mclk3,ln-gf-mclk4 : Optional
> +       input audio clocks from host system.
> +     - ln-psia1-mclk, ln-psia2-mclk : Optional input audio clocks from
> +       external connector.
> +     - ln-spdif-clkout : Optional input audio clock from SPDIF.
> +     - ln-adat-clkout : Optional input audio clock from ADAT.
> +     - ln-pmic-32k : On board fixed regulator.

regulator?

> +     - ln-clk-12m : On board fixed regulator.
> +     - ln-clk-11m : On board fixed regulator.
> +     - ln-clk-24m : On board fixed regulator.
> +     - ln-clk-22m : On board fixed regulator.
> +     - ln-usb-clk-24m : On board fixed regulator.
> +     - ln-usb-clk-12m : On board fixed regulator.
> +
> +  - assigned-clocks : A list of Lochnagar clocks to be reparented, see
> +    [2] for available clocks.
> +  - assigned-clock-parents : Parents to be assigned to the clocks
> +    listed in "assigned-clocks".
> +
> +Optional sub-nodes:
> +
> +  - fixed-clock nodes may be registered for the following on board clocks:
> +     - ln-pmic-32k : 32768 kHz
> +     - ln-clk-12m : 12288000 kHz
> +     - ln-clk-11m : 11298600 kHz
> +     - ln-clk-24m : 24576000 kHz
> +     - ln-clk-22m : 22579200 kHz
> +     - ln-usb-clk-24m : 24576000 kHz
> +     - ln-usb-clk-12m : 12288000 kHz
> +
> +Example:
> +
> +lochnagar-clk {
> +	compatible = "cirrus,lochnagar2-clk";
> +
> +	#clock-cells = <1>;
> +
> +	clocks = <&clk-audio>, <&clk_pmic>;
> +	clock-names = "ln-gf-mclk2", "ln-pmic-32k";
> +
> +	assigned-clocks = <&lochnagar-clk LOCHNAGAR_CDC_MCLK1>,
> +			  <&lochnagar-clk LOCHNAGAR_CDC_MCLK2>;
> +	assigned-clock-parents = <&clk-audio>,
> +				 <&clk-pmic>;
> +
> +	clk-pmic: clk-pmic {

This isn't really any relationship to the parent and I think shouldn't 
be a sub-node.

> +		compatible = "fixed-clock";
> +		clock-cells = <0>;
> +		clock-frequency = <32768>;
> +	};
> +};
> -- 
> 2.11.0
> 

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

* Re: [PATCH v5 3/8] clk: lochnagar: Add initial binding documentation
  2018-11-26 20:16   ` Rob Herring
@ 2018-11-27  9:34     ` Charles Keepax
  0 siblings, 0 replies; 21+ messages in thread
From: Charles Keepax @ 2018-11-27  9:34 UTC (permalink / raw)
  To: Rob Herring
  Cc: lee.jones, mturquette, sboyd, broonie, linus.walleij,
	mark.rutland, lgirdwood, devicetree, linux-kernel, patches,
	linux-clk, linux-gpio

On Mon, Nov 26, 2018 at 02:16:45PM -0600, Rob Herring wrote:
> On Tue, Nov 20, 2018 at 02:16:26PM +0000, Charles Keepax wrote:
> > Lochnagar is an evaluation and development board for Cirrus
> > Logic Smart CODEC and Amp devices. It allows the connection of
> > most Cirrus Logic devices on mini-cards, as well as allowing
> > connection of various application processor systems to provide a
> > full evaluation platform. This driver supports the board
> > controller chip on the Lochnagar board.
> > 
> > Signed-off-by: Charles Keepax <ckeepax@opensource.cirrus.com>
> > ---
> > +  - compatible : One of the following strings:
> > +                 "cirrus,lochnagar1-clk"
> > +                 "cirrus,lochnagar2-clk"
> 
> What's the 1 vs. 2?
> 

There are two versions of the device, we need to be able to
differenciate between them in the driver.

> > +     - ln-pmic-32k : On board fixed regulator.
> 
> regulator?

Well that is a spectacular copy and paste oversight sorry about
that will get it fixed up.

> 
> > +     - ln-clk-12m : On board fixed regulator.
> > +     - ln-clk-11m : On board fixed regulator.
> > +     - ln-clk-24m : On board fixed regulator.
> > +     - ln-clk-22m : On board fixed regulator.
> > +     - ln-usb-clk-24m : On board fixed regulator.
> > +     - ln-usb-clk-12m : On board fixed regulator.

> > +lochnagar-clk {
> > +	compatible = "cirrus,lochnagar2-clk";
> > +
> > +	#clock-cells = <1>;
> > +
> > +	clocks = <&clk-audio>, <&clk_pmic>;
> > +	clock-names = "ln-gf-mclk2", "ln-pmic-32k";
> > +
> > +	assigned-clocks = <&lochnagar-clk LOCHNAGAR_CDC_MCLK1>,
> > +			  <&lochnagar-clk LOCHNAGAR_CDC_MCLK2>;
> > +	assigned-clock-parents = <&clk-audio>,
> > +				 <&clk-pmic>;
> > +
> > +	clk-pmic: clk-pmic {
> 
> This isn't really any relationship to the parent and I think shouldn't 
> be a sub-node.
> 

Yeah sorry that is a good point will move it out.

Thanks,
Charles

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

* Re: [PATCH v5 2/8] mfd: lochnagar: Add initial binding documentation
  2018-11-20 14:16 ` [PATCH v5 2/8] mfd: lochnagar: Add initial binding documentation Charles Keepax
@ 2018-11-28  9:18   ` Lee Jones
  0 siblings, 0 replies; 21+ messages in thread
From: Lee Jones @ 2018-11-28  9:18 UTC (permalink / raw)
  To: Charles Keepax
  Cc: mturquette, sboyd, broonie, linus.walleij, robh+dt, mark.rutland,
	lgirdwood, devicetree, linux-kernel, patches, linux-clk,
	linux-gpio

On Tue, 20 Nov 2018, Charles Keepax wrote:

> Lochnagar is an evaluation and development board for Cirrus
> Logic Smart CODEC and Amp devices. It allows the connection of
> most Cirrus Logic devices on mini-cards, as well as allowing
> connection of various application processor systems to provide a
> full evaluation platform. This driver supports the board
> controller chip on the Lochnagar board.
> 
> Signed-off-by: Charles Keepax <ckeepax@opensource.cirrus.com>
> ---
> 
> Changes since v4:
>  - Move sub-bindings into separate documents
> 
> Again incase Rob missed v4 I have dropped his ack due to the large
> changes introduced in v4, see:
> 
>  https://patchwork.kernel.org/patch/10673891/
> 
> Thanks,
> Charles
> 
>  .../devicetree/bindings/mfd/cirrus,lochnagar.txt   |  71 +++++++++++

For my own reference:
  Acked-for-MFD-by: Lee Jones <lee.jones@linaro.org>

-- 
Lee Jones [李琼斯]
Linaro Services Technical Lead
Linaro.org │ Open source software for ARM SoCs
Follow Linaro: Facebook | Twitter | Blog

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

* Re: [PATCH v5 6/8] mfd: lochnagar: Add support for the Cirrus Logic Lochnagar
  2018-11-20 14:16 ` [PATCH v5 6/8] mfd: lochnagar: Add support for the Cirrus Logic Lochnagar Charles Keepax
  2018-11-23  9:00   ` kbuild test robot
@ 2018-11-28  9:22   ` Lee Jones
  1 sibling, 0 replies; 21+ messages in thread
From: Lee Jones @ 2018-11-28  9:22 UTC (permalink / raw)
  To: Charles Keepax
  Cc: mturquette, sboyd, broonie, linus.walleij, robh+dt, mark.rutland,
	lgirdwood, devicetree, linux-kernel, patches, linux-clk,
	linux-gpio

On Tue, 20 Nov 2018, Charles Keepax wrote:

> Lochnagar is an evaluation and development board for Cirrus
> Logic Smart CODEC and Amp devices. It allows the connection of
> most Cirrus Logic devices on mini-cards, as well as allowing
> connection of various application processor systems to provide a
> full evaluation platform. This driver supports the board
> controller chip on the Lochnagar board. Audio system topology,
> clocking and power can all be controlled through the Lochnagar
> controller chip, allowing the device under test to be used in
> a variety of possible use cases.
> 
> As the Lochnagar is a fairly complex device this MFD driver
> allows the drivers for the various features to be bound
> in. Initially clocking, regulator and pinctrl will be added as
> these are necessary to configure the system. But in time at least
> audio and voltage/current monitoring will also be added.
> 
> Signed-off-by: Charles Keepax <ckeepax@opensource.cirrus.com>
> ---
> 
> No change since v4.
> 
> Thanks,
> Charles
> 
>  MAINTAINERS                         |  17 ++
>  drivers/mfd/Kconfig                 |   8 +
>  drivers/mfd/Makefile                |   2 +
>  drivers/mfd/lochnagar-i2c.c         | 394 ++++++++++++++++++++++++++++++++++++
>  include/linux/mfd/lochnagar.h       |  55 +++++
>  include/linux/mfd/lochnagar1_regs.h | 157 ++++++++++++++
>  include/linux/mfd/lochnagar2_regs.h | 253 +++++++++++++++++++++++
>  7 files changed, 886 insertions(+)
>  create mode 100644 drivers/mfd/lochnagar-i2c.c
>  create mode 100644 include/linux/mfd/lochnagar.h
>  create mode 100644 include/linux/mfd/lochnagar1_regs.h
>  create mode 100644 include/linux/mfd/lochnagar2_regs.h

For my own reference:
  Acked-for-MFD-by: Lee Jones <lee.jones@linaro.org>

-- 
Lee Jones [李琼斯]
Linaro Services Technical Lead
Linaro.org │ Open source software for ARM SoCs
Follow Linaro: Facebook | Twitter | Blog

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

* Re: [PATCH v5 7/8] clk: lochnagar: Add support for the Cirrus Logic Lochnagar
  2018-11-20 14:16 ` [PATCH v5 7/8] clk: " Charles Keepax
@ 2018-11-30  7:53   ` Stephen Boyd
  2018-12-21 13:50     ` Charles Keepax
  0 siblings, 1 reply; 21+ messages in thread
From: Stephen Boyd @ 2018-11-30  7:53 UTC (permalink / raw)
  To: Charles Keepax, broonie, lee.jones, linus.walleij, mturquette, robh+dt
  Cc: mark.rutland, lgirdwood, devicetree, linux-kernel, patches,
	linux-clk, linux-gpio

Quoting Charles Keepax (2018-11-20 06:16:30)
> diff --git a/drivers/clk/clk-lochnagar.c b/drivers/clk/clk-lochnagar.c
> new file mode 100644
> index 000000000000..8b2a78689715
> --- /dev/null
> +++ b/drivers/clk/clk-lochnagar.c
> @@ -0,0 +1,360 @@
[...]
> +
> +static int lochnagar_regmap_set_parent(struct clk_hw *hw, u8 index)
> +{
> +       struct lochnagar_clk *lclk = lochnagar_hw_to_lclk(hw);
> +       struct lochnagar_clk_priv *priv = lclk->priv;
> +       struct regmap *regmap = priv->regmap;
> +       int ret;
> +
> +       /*
> +        * Some clocks on Lochnagar can either generate a clock themselves
> +        * or accept an external clock, these default to generating the clock
> +        * themselves. If we set a parent however we should update the dir_mask
> +        * to indicate to the hardware that this clock will now be receiving an
> +        * external clock.

Hmm ok. So the plan is to configure parents in DT or from driver code if
the configuration is to accept an external clk? I guess this works.

> +        */
> +       if (lclk->dir_mask) {
> +               ret = regmap_update_bits(regmap, lclk->cfg_reg,
> +                                        lclk->dir_mask, lclk->dir_mask);
> +               if (ret < 0) {
> +                       dev_err(priv->dev, "Failed to set %s direction: %d\n",
> +                               lclk->name, ret);
> +                       return ret;
> +               }
> +       }
> +
> +       ret = regmap_update_bits(regmap, lclk->src_reg, lclk->src_mask, index);
> +       if (ret < 0)
> +               dev_err(priv->dev, "Failed to reparent %s: %d\n",
> +                       lclk->name, ret);
> +
> +       return ret;
> +}
> +
> +static u8 lochnagar_regmap_get_parent(struct clk_hw *hw)
> +{
> +       struct lochnagar_clk *lclk = lochnagar_hw_to_lclk(hw);
> +       struct lochnagar_clk_priv *priv = lclk->priv;
> +       struct regmap *regmap = priv->regmap;
> +       unsigned int val;
> +       int ret;
> +
> +       ret = regmap_read(regmap, lclk->src_reg, &val);
> +       if (ret < 0) {
> +               dev_err(priv->dev, "Failed to read parent of %s: %d\n",
> +                       lclk->name, ret);

The error messages in the above functions could be spammy. Just let
drivers who fail when using these clks ops print errors and maybe
downgrade these to debug? If you don't agree with this it's fine, I'll
just hope to never see these prints change to debug in the future.

> +               return priv->nparents;
> +       }
> +
> +       val &= lclk->src_mask;
> +
> +       return val;
> +}
> +
> +static const struct clk_ops lochnagar_clk_regmap_ops = {
> +       .prepare = lochnagar_regmap_prepare,
> +       .unprepare = lochnagar_regmap_unprepare,
> +       .set_parent = lochnagar_regmap_set_parent,
> +       .get_parent = lochnagar_regmap_get_parent,

Is regmap important to have in the name of these functions and struct?
I'd prefer it was just clk instead of regmap.

> +};
> +
> +static int lochnagar_init_parents(struct lochnagar_clk_priv *priv)
> +{
> +       struct device_node *np = priv->dev->of_node;
> +       int i, j;
> +
> +       switch (priv->type) {
> +       case LOCHNAGAR1:
> +               memcpy(priv->lclks, lochnagar1_clks, sizeof(lochnagar1_clks));
> +
> +               priv->nparents = ARRAY_SIZE(lochnagar1_clk_parents);
> +               priv->parents = devm_kmemdup(priv->dev, lochnagar1_clk_parents,
> +                                            sizeof(lochnagar1_clk_parents),
> +                                            GFP_KERNEL);
> +               break;
> +       case LOCHNAGAR2:
> +               memcpy(priv->lclks, lochnagar2_clks, sizeof(lochnagar2_clks));
> +
> +               priv->nparents = ARRAY_SIZE(lochnagar2_clk_parents);
> +               priv->parents = devm_kmemdup(priv->dev, lochnagar2_clk_parents,
> +                                            sizeof(lochnagar2_clk_parents),
> +                                            GFP_KERNEL);

Why do we need to kmemdup it? The clk framework already deep copies
everything from clk_init structure.

> +               break;
> +       default:
> +               dev_err(priv->dev, "Unknown Lochnagar type: %d\n", priv->type);
> +               return -EINVAL;
> +       }
> +
> +       if (!priv->parents)
> +               return -ENOMEM;
> +
> +       for (i = 0; i < priv->nparents; i++) {
> +               j = of_property_match_string(np, "clock-names",
> +                                            priv->parents[i]);
> +               if (j >= 0)
> +                       priv->parents[i] = of_clk_get_parent_name(np, j);

Isn't this of_clk_parent_fill()? But there are holes or something?

> +       }
> +
> +       return 0;
> +}
> +
> +static int lochnagar_init_clks(struct lochnagar_clk_priv *priv)
> +{
> +       struct clk_init_data clk_init = {
> +               .ops = &lochnagar_clk_regmap_ops,
> +               .parent_names = priv->parents,
> +               .num_parents = priv->nparents,
> +       };
> +       struct lochnagar_clk *lclk;
> +       int ret, i;
> +
> +       for (i = 0; i < ARRAY_SIZE(priv->lclks); i++) {

We already have an array of clks.

> +               lclk = &priv->lclks[i];
> +
> +               if (!lclk->name)
> +                       continue;
> +
> +               clk_init.name = lclk->name;
> +
> +               lclk->priv = priv;
> +               lclk->hw.init = &clk_init;
> +
> +               ret = devm_clk_hw_register(priv->dev, &lclk->hw);
> +               if (ret) {
> +                       dev_err(priv->dev, "Failed to register %s: %d\n",
> +                               lclk->name, ret);
> +                       return ret;
> +               }
> +
> +               priv->clk_data->hws[i] = &lclk->hw;

But then we copy the pointers into here to use of_clk_hw_onecell_get().
Can you just roll your own function to use your own array of clk
structures? I know it's sort of sad, but it avoids a copy.

> +       }
> +
> +       priv->clk_data->num = ARRAY_SIZE(priv->lclks);
> +
> +       ret = devm_of_clk_add_hw_provider(priv->dev, of_clk_hw_onecell_get,
> +                                         priv->clk_data);
> +       if (ret < 0) {
> +               dev_err(priv->dev, "Failed to register provider: %d\n", ret);
> +               return ret;
> +       }
> +
> +       return 0;

Simplify this to

	if (ret < 0)
		dev_err(...)

	return ret;

> +}
> +
> +static const struct of_device_id lochnagar_of_match[] = {
> +       { .compatible = "cirrus,lochnagar1-clk", .data = (void *)LOCHNAGAR1 },
> +       { .compatible = "cirrus,lochnagar2-clk", .data = (void *)LOCHNAGAR2 },
> +       {},

Nitpick: Drop the comma, it's the sentinel so nothing should come after.

> +};

Any MODULE_DEVICE_TABLE?

> +
> +static int lochnagar_clk_probe(struct platform_device *pdev)
> +{
> +       struct device *dev = &pdev->dev;
> +       struct lochnagar_clk_priv *priv;
> +       const struct of_device_id *of_id;
> +       int ret;
> +
> +       of_id = of_match_device(lochnagar_of_match, dev);
> +       if (!of_id)
> +               return -EINVAL;
> +
> +       priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
> +       if (!priv)
> +               return -ENOMEM;
> +
> +       priv->clk_data = devm_kzalloc(dev, struct_size(priv->clk_data, hws,
> +                                                      ARRAY_SIZE(priv->lclks)),
> +                                     GFP_KERNEL);
> +       if (!priv->clk_data)
> +               return -ENOMEM;
> +
> +       priv->dev = dev;
> +       priv->regmap = dev_get_regmap(dev->parent, NULL);
> +       priv->type = (enum lochnagar_type)of_id->data;
> +
> +       ret = lochnagar_init_parents(priv);
> +       if (ret)
> +               return ret;
> +
> +       ret = lochnagar_init_clks(priv);
> +       if (ret)
> +               return ret;
> +
> +       return 0;
> +}
> +
> +static struct platform_driver lochnagar_clk_driver = {
> +       .driver = {
> +               .name = "lochnagar-clk",
> +               .of_match_table = of_match_ptr(lochnagar_of_match),

I suspect of_match_ptr() makes the build complain about unused match
table when CONFIG_OF=N. Can you try building it that way?

> +       },
> +

Nitpick: Why the extra newline?

> +       .probe = lochnagar_clk_probe,
> +};
> +module_platform_driver(lochnagar_clk_driver);
> +
> +MODULE_AUTHOR("Charles Keepax <ckeepax@opensource.cirrus.com>");
> +MODULE_DESCRIPTION("Clock driver for Cirrus Logic Lochnagar Board");
> +MODULE_LICENSE("GPL v2");
> +MODULE_ALIAS("platform:lochnagar-clk");

I think MODULE_ALIAS is not needed if it's this simple?


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

* Re: [PATCH v5 4/8] pinctrl: lochnagar: Add initial binding documentation
  2018-11-20 14:16 ` [PATCH v5 4/8] pinctrl: " Charles Keepax
@ 2018-12-07 17:07   ` Rob Herring
  2018-12-16  0:16   ` Linus Walleij
  1 sibling, 0 replies; 21+ messages in thread
From: Rob Herring @ 2018-12-07 17:07 UTC (permalink / raw)
  To: Charles Keepax
  Cc: lee.jones, mturquette, sboyd, broonie, linus.walleij, robh+dt,
	mark.rutland, lgirdwood, devicetree, linux-kernel, patches,
	linux-clk, linux-gpio

On Tue, 20 Nov 2018 14:16:27 +0000, Charles Keepax wrote:
> Lochnagar is an evaluation and development board for Cirrus
> Logic Smart CODEC and Amp devices. It allows the connection of
> most Cirrus Logic devices on mini-cards, as well as allowing
> connection of various application processor systems to provide a
> full evaluation platform. This driver supports the board
> controller chip on the Lochnagar board.
> 
> Signed-off-by: Charles Keepax <ckeepax@opensource.cirrus.com>
> ---
>  .../bindings/pinctrl/cirrus,lochnagar.txt          | 141 +++++++++++++++++++++
>  1 file changed, 141 insertions(+)
>  create mode 100644 Documentation/devicetree/bindings/pinctrl/cirrus,lochnagar.txt
> 

Reviewed-by: Rob Herring <robh@kernel.org>

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

* Re: [PATCH v5 4/8] pinctrl: lochnagar: Add initial binding documentation
  2018-11-20 14:16 ` [PATCH v5 4/8] pinctrl: " Charles Keepax
  2018-12-07 17:07   ` Rob Herring
@ 2018-12-16  0:16   ` Linus Walleij
  1 sibling, 0 replies; 21+ messages in thread
From: Linus Walleij @ 2018-12-16  0:16 UTC (permalink / raw)
  To: Charles Keepax
  Cc: Lee Jones, Michael Turquette, Stephen Boyd, Mark Brown,
	Rob Herring, Mark Rutland, Liam Girdwood,
	open list:OPEN FIRMWARE AND FLATTENED DEVICE TREE BINDINGS,
	linux-kernel, patches, linux-clk, open list:GPIO SUBSYSTEM

On Tue, Nov 20, 2018 at 3:16 PM Charles Keepax
<ckeepax@opensource.cirrus.com> wrote:

> Lochnagar is an evaluation and development board for Cirrus
> Logic Smart CODEC and Amp devices. It allows the connection of
> most Cirrus Logic devices on mini-cards, as well as allowing
> connection of various application processor systems to provide a
> full evaluation platform. This driver supports the board
> controller chip on the Lochnagar board.
>
> Signed-off-by: Charles Keepax <ckeepax@opensource.cirrus.com>

Acked-by: Linus Walleij <linus.walleij@linaro.org>

Yours,
Linus Walleij

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

* Re: [PATCH v5 7/8] clk: lochnagar: Add support for the Cirrus Logic Lochnagar
  2018-11-30  7:53   ` Stephen Boyd
@ 2018-12-21 13:50     ` Charles Keepax
  2018-12-21 15:28       ` Charles Keepax
  2018-12-21 20:44       ` Stephen Boyd
  0 siblings, 2 replies; 21+ messages in thread
From: Charles Keepax @ 2018-12-21 13:50 UTC (permalink / raw)
  To: Stephen Boyd
  Cc: broonie, lee.jones, linus.walleij, mturquette, robh+dt,
	mark.rutland, lgirdwood, devicetree, linux-kernel, patches,
	linux-clk, linux-gpio

On Thu, Nov 29, 2018 at 11:53:51PM -0800, Stephen Boyd wrote:
> Quoting Charles Keepax (2018-11-20 06:16:30)

Apologies for the delay on this we have been very swamped at this
end lately.

> > diff --git a/drivers/clk/clk-lochnagar.c b/drivers/clk/clk-lochnagar.c
> > new file mode 100644
> > index 000000000000..8b2a78689715
> > --- /dev/null
> > +++ b/drivers/clk/clk-lochnagar.c
> > @@ -0,0 +1,360 @@
> [...]
> > +
> > +static int lochnagar_regmap_set_parent(struct clk_hw *hw, u8 index)
> > +{
> > +       struct lochnagar_clk *lclk = lochnagar_hw_to_lclk(hw);
> > +       struct lochnagar_clk_priv *priv = lclk->priv;
> > +       struct regmap *regmap = priv->regmap;
> > +       int ret;
> > +
> > +       /*
> > +        * Some clocks on Lochnagar can either generate a clock themselves
> > +        * or accept an external clock, these default to generating the clock
> > +        * themselves. If we set a parent however we should update the dir_mask
> > +        * to indicate to the hardware that this clock will now be receiving an
> > +        * external clock.
> 
> Hmm ok. So the plan is to configure parents in DT or from driver code if
> the configuration is to accept an external clk? I guess this works.
> 

Actually from further discussions on the hardware side it seems
this is handled automatically by the hardware so we no longer
need to set these direction bits. As such I will remove them in
the next spin.

> > +        */
> > +       if (lclk->dir_mask) {
> > +               ret = regmap_update_bits(regmap, lclk->cfg_reg,
> > +                                        lclk->dir_mask, lclk->dir_mask);
> > +               if (ret < 0) {
> > +                       dev_err(priv->dev, "Failed to set %s direction: %d\n",
> > +                               lclk->name, ret);
> > +                       return ret;
> > +               }
> > +       }
> > +
> > +       ret = regmap_update_bits(regmap, lclk->src_reg, lclk->src_mask, index);
> > +       if (ret < 0)
> > +               dev_err(priv->dev, "Failed to reparent %s: %d\n",
> > +                       lclk->name, ret);
> > +
> > +       return ret;
> > +}
> > +
> > +static u8 lochnagar_regmap_get_parent(struct clk_hw *hw)
> > +{
> > +       struct lochnagar_clk *lclk = lochnagar_hw_to_lclk(hw);
> > +       struct lochnagar_clk_priv *priv = lclk->priv;
> > +       struct regmap *regmap = priv->regmap;
> > +       unsigned int val;
> > +       int ret;
> > +
> > +       ret = regmap_read(regmap, lclk->src_reg, &val);
> > +       if (ret < 0) {
> > +               dev_err(priv->dev, "Failed to read parent of %s: %d\n",
> > +                       lclk->name, ret);
> 
> The error messages in the above functions could be spammy. Just let
> drivers who fail when using these clks ops print errors and maybe
> downgrade these to debug? If you don't agree with this it's fine, I'll
> just hope to never see these prints change to debug in the future.
> 

Seems reasonable to me I will change them to debug prints.

> > +               return priv->nparents;
> > +       }
> > +
> > +       val &= lclk->src_mask;
> > +
> > +       return val;
> > +}
> > +
> > +static const struct clk_ops lochnagar_clk_regmap_ops = {
> > +       .prepare = lochnagar_regmap_prepare,
> > +       .unprepare = lochnagar_regmap_unprepare,
> > +       .set_parent = lochnagar_regmap_set_parent,
> > +       .get_parent = lochnagar_regmap_get_parent,
> 
> Is regmap important to have in the name of these functions and struct?
> I'd prefer it was just clk instead of regmap.
> 

Again no objection happy to rename.

> > +};
> > +
> > +static int lochnagar_init_parents(struct lochnagar_clk_priv *priv)
> > +{
> > +       struct device_node *np = priv->dev->of_node;
> > +       int i, j;
> > +
> > +       switch (priv->type) {
> > +       case LOCHNAGAR1:
> > +               memcpy(priv->lclks, lochnagar1_clks, sizeof(lochnagar1_clks));
> > +
> > +               priv->nparents = ARRAY_SIZE(lochnagar1_clk_parents);
> > +               priv->parents = devm_kmemdup(priv->dev, lochnagar1_clk_parents,
> > +                                            sizeof(lochnagar1_clk_parents),
> > +                                            GFP_KERNEL);
> > +               break;
> > +       case LOCHNAGAR2:
> > +               memcpy(priv->lclks, lochnagar2_clks, sizeof(lochnagar2_clks));
> > +
> > +               priv->nparents = ARRAY_SIZE(lochnagar2_clk_parents);
> > +               priv->parents = devm_kmemdup(priv->dev, lochnagar2_clk_parents,
> > +                                            sizeof(lochnagar2_clk_parents),
> > +                                            GFP_KERNEL);
> 
> Why do we need to kmemdup it? The clk framework already deep copies
> everything from clk_init structure.
> 

The copy is needed for the updates to the list down below.

> > +               break;
> > +       default:
> > +               dev_err(priv->dev, "Unknown Lochnagar type: %d\n", priv->type);
> > +               return -EINVAL;
> > +       }
> > +
> > +       if (!priv->parents)
> > +               return -ENOMEM;
> > +
> > +       for (i = 0; i < priv->nparents; i++) {
> > +               j = of_property_match_string(np, "clock-names",
> > +                                            priv->parents[i]);
> > +               if (j >= 0)
> > +                       priv->parents[i] = of_clk_get_parent_name(np, j);
> 
> Isn't this of_clk_parent_fill()? But there are holes or something?
> 

I guess rather than a fill, this is perhaps more of a name and
replace. I could make this a core function if you prefer? I think
there are a couple of other drivers that could also use it,
although might be worth doing that as a separate series rather
than holding this one up.

> > +       }
> > +
> > +       return 0;
> > +}
> > +
> > +static int lochnagar_init_clks(struct lochnagar_clk_priv *priv)
> > +{
> > +       struct clk_init_data clk_init = {
> > +               .ops = &lochnagar_clk_regmap_ops,
> > +               .parent_names = priv->parents,
> > +               .num_parents = priv->nparents,
> > +       };
> > +       struct lochnagar_clk *lclk;
> > +       int ret, i;
> > +
> > +       for (i = 0; i < ARRAY_SIZE(priv->lclks); i++) {
> 
> We already have an array of clks.
> 
> > +               lclk = &priv->lclks[i];
> > +
> > +               if (!lclk->name)
> > +                       continue;
> > +
> > +               clk_init.name = lclk->name;
> > +
> > +               lclk->priv = priv;
> > +               lclk->hw.init = &clk_init;
> > +
> > +               ret = devm_clk_hw_register(priv->dev, &lclk->hw);
> > +               if (ret) {
> > +                       dev_err(priv->dev, "Failed to register %s: %d\n",
> > +                               lclk->name, ret);
> > +                       return ret;
> > +               }
> > +
> > +               priv->clk_data->hws[i] = &lclk->hw;
> 
> But then we copy the pointers into here to use of_clk_hw_onecell_get().
> Can you just roll your own function to use your own array of clk
> structures? I know it's sort of sad, but it avoids a copy.
> 

Apologies for not doing it this way the first time, looks much
clearer that way round.

> > +       }
> > +
> > +       priv->clk_data->num = ARRAY_SIZE(priv->lclks);
> > +
> > +       ret = devm_of_clk_add_hw_provider(priv->dev, of_clk_hw_onecell_get,
> > +                                         priv->clk_data);
> > +       if (ret < 0) {
> > +               dev_err(priv->dev, "Failed to register provider: %d\n", ret);
> > +               return ret;
> > +       }
> > +
> > +       return 0;
> 
> Simplify this to
> 
> 	if (ret < 0)
> 		dev_err(...)
> 
> 	return ret;
> 

No problem.

> > +}
> > +
> > +static const struct of_device_id lochnagar_of_match[] = {
> > +       { .compatible = "cirrus,lochnagar1-clk", .data = (void *)LOCHNAGAR1 },
> > +       { .compatible = "cirrus,lochnagar2-clk", .data = (void *)LOCHNAGAR2 },
> > +       {},
> 
> Nitpick: Drop the comma, it's the sentinel so nothing should come after.
> 

Again no problem.

> > +};
> 
> Any MODULE_DEVICE_TABLE?
> 

Yes oversight there, will add that.

> > +static struct platform_driver lochnagar_clk_driver = {
> > +       .driver = {
> > +               .name = "lochnagar-clk",
> > +               .of_match_table = of_match_ptr(lochnagar_of_match),
> 
> I suspect of_match_ptr() makes the build complain about unused match
> table when CONFIG_OF=N. Can you try building it that way?
> 

The driver depends on the MFD which in turn depends on CONFIG_OF
so that shouldn't be a problem.

> > +       },
> > +
> 
> Nitpick: Why the extra newline?
> 

Happy to remove.

> > +       .probe = lochnagar_clk_probe,
> > +};
> > +module_platform_driver(lochnagar_clk_driver);
> > +
> > +MODULE_AUTHOR("Charles Keepax <ckeepax@opensource.cirrus.com>");
> > +MODULE_DESCRIPTION("Clock driver for Cirrus Logic Lochnagar Board");
> > +MODULE_LICENSE("GPL v2");
> > +MODULE_ALIAS("platform:lochnagar-clk");
> 
> I think MODULE_ALIAS is not needed if it's this simple?
> 

Not actually sure on this one, to be honest its mostly cargo
culted from other drivers. I will investigate and see what I dig
up but if has any pointers I would greatly appreciate it.

Should be able to send another version very shortly.

Thanks,
Charles

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

* Re: [PATCH v5 7/8] clk: lochnagar: Add support for the Cirrus Logic Lochnagar
  2018-12-21 13:50     ` Charles Keepax
@ 2018-12-21 15:28       ` Charles Keepax
  2018-12-21 20:44       ` Stephen Boyd
  1 sibling, 0 replies; 21+ messages in thread
From: Charles Keepax @ 2018-12-21 15:28 UTC (permalink / raw)
  To: Stephen Boyd
  Cc: broonie, lee.jones, linus.walleij, mturquette, robh+dt,
	mark.rutland, lgirdwood, devicetree, linux-kernel, patches,
	linux-clk, linux-gpio

On Fri, Dec 21, 2018 at 01:50:37PM +0000, Charles Keepax wrote:
> On Thu, Nov 29, 2018 at 11:53:51PM -0800, Stephen Boyd wrote:
> > Quoting Charles Keepax (2018-11-20 06:16:30)
> > > +MODULE_AUTHOR("Charles Keepax <ckeepax@opensource.cirrus.com>");
> > > +MODULE_DESCRIPTION("Clock driver for Cirrus Logic Lochnagar Board");
> > > +MODULE_LICENSE("GPL v2");
> > > +MODULE_ALIAS("platform:lochnagar-clk");
> > 
> > I think MODULE_ALIAS is not needed if it's this simple?
> > 
> 
> Not actually sure on this one, to be honest its mostly cargo
> culted from other drivers. I will investigate and see what I dig
> up but if has any pointers I would greatly appreciate it.
> 

From what I can find out it looks like MODULE_ALIAS is indeed
redundant on DT only drivers, which these are at the moment so
will remove and give it a test.

Thanks,
Charles

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

* Re: [PATCH v5 7/8] clk: lochnagar: Add support for the Cirrus Logic Lochnagar
  2018-12-21 13:50     ` Charles Keepax
  2018-12-21 15:28       ` Charles Keepax
@ 2018-12-21 20:44       ` Stephen Boyd
  1 sibling, 0 replies; 21+ messages in thread
From: Stephen Boyd @ 2018-12-21 20:44 UTC (permalink / raw)
  To: Charles Keepax
  Cc: broonie, lee.jones, linus.walleij, mturquette, robh+dt,
	mark.rutland, lgirdwood, devicetree, linux-kernel, patches,
	linux-clk, linux-gpio

Quoting Charles Keepax (2018-12-21 05:50:37)
> On Thu, Nov 29, 2018 at 11:53:51PM -0800, Stephen Boyd wrote:
> > Quoting Charles Keepax (2018-11-20 06:16:30)
> 
> > > +               break;
> > > +       default:
> > > +               dev_err(priv->dev, "Unknown Lochnagar type: %d\n", priv->type);
> > > +               return -EINVAL;
> > > +       }
> > > +
> > > +       if (!priv->parents)
> > > +               return -ENOMEM;
> > > +
> > > +       for (i = 0; i < priv->nparents; i++) {
> > > +               j = of_property_match_string(np, "clock-names",
> > > +                                            priv->parents[i]);
> > > +               if (j >= 0)
> > > +                       priv->parents[i] = of_clk_get_parent_name(np, j);
> > 
> > Isn't this of_clk_parent_fill()? But there are holes or something?
> > 
> 
> I guess rather than a fill, this is perhaps more of a name and
> replace. I could make this a core function if you prefer? I think
> there are a couple of other drivers that could also use it,
> although might be worth doing that as a separate series rather
> than holding this one up.

No worries. I'm actively changing the parent_names design anyway so this
is fine.

> 
> 
> > > +static struct platform_driver lochnagar_clk_driver = {
> > > +       .driver = {
> > > +               .name = "lochnagar-clk",
> > > +               .of_match_table = of_match_ptr(lochnagar_of_match),
> > 
> > I suspect of_match_ptr() makes the build complain about unused match
> > table when CONFIG_OF=N. Can you try building it that way?
> > 
> 
> The driver depends on the MFD which in turn depends on CONFIG_OF
> so that shouldn't be a problem.

Ok. Then it's really not needed and it's better to drop the usage of
of_match_ptr() then.

> 

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

end of thread, other threads:[~2018-12-21 20:44 UTC | newest]

Thread overview: 21+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2018-11-20 14:16 [PATCH v5 1/8] regulator: lochnagar: Move driver to binding from DT Charles Keepax
2018-11-20 14:16 ` [PATCH v5 2/8] mfd: lochnagar: Add initial binding documentation Charles Keepax
2018-11-28  9:18   ` Lee Jones
2018-11-20 14:16 ` [PATCH v5 3/8] clk: " Charles Keepax
2018-11-26 20:16   ` Rob Herring
2018-11-27  9:34     ` Charles Keepax
2018-11-20 14:16 ` [PATCH v5 4/8] pinctrl: " Charles Keepax
2018-12-07 17:07   ` Rob Herring
2018-12-16  0:16   ` Linus Walleij
2018-11-20 14:16 ` [PATCH v5 5/8] regulator: " Charles Keepax
2018-11-20 14:16 ` [PATCH v5 6/8] mfd: lochnagar: Add support for the Cirrus Logic Lochnagar Charles Keepax
2018-11-23  9:00   ` kbuild test robot
2018-11-23  9:15     ` Charles Keepax
2018-11-28  9:22   ` Lee Jones
2018-11-20 14:16 ` [PATCH v5 7/8] clk: " Charles Keepax
2018-11-30  7:53   ` Stephen Boyd
2018-12-21 13:50     ` Charles Keepax
2018-12-21 15:28       ` Charles Keepax
2018-12-21 20:44       ` Stephen Boyd
2018-11-20 14:16 ` [PATCH v5 8/8] pinctrl: " Charles Keepax
2018-11-24 16:11   ` kbuild test robot

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).