linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH v3 0/8] mfd: ac100: Add support for X-Powers AC100 audio codec / RTC combo IC
@ 2016-06-20  2:52 Chen-Yu Tsai
  2016-06-20  2:52 ` [PATCH v3 1/8] regmap: Support bulk writes for devices without raw formatting Chen-Yu Tsai
                   ` (7 more replies)
  0 siblings, 8 replies; 20+ messages in thread
From: Chen-Yu Tsai @ 2016-06-20  2:52 UTC (permalink / raw)
  To: Mark Brown, Lee Jones, Alessandro Zummo, Alexandre Belloni,
	Rob Herring, Pawel Moll, Mark Rutland, Ian Campbell, Kumar Gala,
	Maxime Ripard, Michael Turquette, Stephen Boyd
  Cc: Chen-Yu Tsai, rtc-linux, linux-kernel, devicetree,
	linux-arm-kernel, linux-clk

Hi everyone,

This series adds support for X-Powers' AC100 audio codec / RTC combo IC.
This chip is found on Allwinner A80 SoC based boards, and is also part
of the AXP813/AXP818 PMIC found with Allwinner A83T SoCs.

The series focuses on the RTC side of the chip. The audio codec will
be done later, once the digital audio interface of the SoC is supported.

Changes since v2:

  - Fix ac100_codec interrupt line in DT binding example.

  - Fix copy-paste errors in RTC set_alarm. Alarm now works.

  - Drop file name from MFD driver.

  - Add / update copyright notices.

  - Change license of RTC driver to GPL v2, matching MFD driver.

  - Fix MFD driver MODULE_LICENSE to match license declaration in header.

Changes since v1:

  - Complete register definitions and regmap regions.

v1 was actually a working version that wasn't updated with the codec
register definitions.


Patch 1 adds bulk write support for regmaps without raw formatting.
This is used in the RTC driver to write out the date and time in one
call.

Patch 2 adds device tree bindings for the AC100.

Patch 3 adds the mfd driver for the AC100.

Patch 4 adds the RTC driver for the AC100.

Patch 5 adds RTC clk output support to the RTC driver.
This is a separate patch as the clk code is over 300 LoC. Having a
separate patch should make it easier for the clk maintainers to review.

Patch 6 adds the AC100 device nodes to the A80 Optimus board dts.

Patch 7 adds the AC100 device nodes to the Cubieboard4 board dts.

Patch 8 fixes the order of device nodes in the A80 Optimus board dts.

Patch 9 fixes the order of device nodes in the Cubieboard4 board dts.

Patch 10 changes the fixed osc_32k clk to a fixed factor clk,
representing the 32k clk input pin on the SoC, and also hooks up the
ac100 rtc clk output to this clk in the board dts files.

I'm hoping we can merge the driver bits (patches 2~5) through the
mfd tree, with acks from the rtc and clk maintainers for patches
4 and 5.


Regards
ChenYu



Chen-Yu Tsai (8):
  regmap: Support bulk writes for devices without raw formatting
  mfd: ac100: Add device tree bindings for X-Powers AC100 codec/RTC
    combo IC
  mfd: ac100: Add driver for X-Powers AC100 audio codec / RTC combo IC
  rtc: ac100: Add RTC driver for X-Powers AC100
  rtc: ac100: Add clk output support
  ARM: dts: sun9i: a80-optimus: Add device node for AC100
  ARM: dts: sun9i: cubieboard4: Add device node for AC100
  ARM: dts: sun9i: Switch to the AC100 RTC clock outputs for osc32k

 Documentation/devicetree/bindings/mfd/ac100.txt |  42 ++
 arch/arm/boot/dts/sun9i-a80-cubieboard4.dts     |  26 +
 arch/arm/boot/dts/sun9i-a80-optimus.dts         |  26 +
 arch/arm/boot/dts/sun9i-a80.dtsi                |   9 +-
 drivers/base/regmap/regmap.c                    |  31 +-
 drivers/mfd/Kconfig                             |  10 +
 drivers/mfd/Makefile                            |   2 +
 drivers/mfd/ac100.c                             | 137 +++++
 drivers/rtc/Kconfig                             |  10 +
 drivers/rtc/Makefile                            |   1 +
 drivers/rtc/rtc-ac100.c                         | 684 ++++++++++++++++++++++++
 include/linux/mfd/ac100.h                       | 178 ++++++
 12 files changed, 1147 insertions(+), 9 deletions(-)
 create mode 100644 Documentation/devicetree/bindings/mfd/ac100.txt
 create mode 100644 drivers/mfd/ac100.c
 create mode 100644 drivers/rtc/rtc-ac100.c
 create mode 100644 include/linux/mfd/ac100.h

-- 
2.8.1

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

* [PATCH v3 1/8] regmap: Support bulk writes for devices without raw formatting
  2016-06-20  2:52 [PATCH v3 0/8] mfd: ac100: Add support for X-Powers AC100 audio codec / RTC combo IC Chen-Yu Tsai
@ 2016-06-20  2:52 ` Chen-Yu Tsai
  2016-06-20  2:52 ` [PATCH v3 2/8] mfd: ac100: Add device tree bindings for X-Powers AC100 codec/RTC combo IC Chen-Yu Tsai
                   ` (6 subsequent siblings)
  7 siblings, 0 replies; 20+ messages in thread
From: Chen-Yu Tsai @ 2016-06-20  2:52 UTC (permalink / raw)
  To: Mark Brown, Lee Jones, Alessandro Zummo, Alexandre Belloni,
	Rob Herring, Pawel Moll, Mark Rutland, Ian Campbell, Kumar Gala,
	Maxime Ripard, Michael Turquette, Stephen Boyd
  Cc: Chen-Yu Tsai, rtc-linux, linux-kernel, devicetree,
	linux-arm-kernel, linux-clk

When doing a bulk writes from a device which lacks raw I/O support we
fall back to doing register at a time reads but we still use the raw
formatters in order to render the data into the word size used by the
device (since bulk reads still operate on the device word size rather
than unsigned ints).  This means that devices without raw formatting
such as those that provide reg_read() are not supported.  Provide
handling for them by copying the values read into native endian values
of the appropriate size.

This complements commit d5b98eb12420 ("regmap: Support bulk reads for
devices without raw formatting").

Signed-off-by: Chen-Yu Tsai <wens@csie.org>
---
Changes since v2: none
Changes since v1: none
---
 drivers/base/regmap/regmap.c | 31 ++++++++++++++++++++++++++++---
 1 file changed, 28 insertions(+), 3 deletions(-)

diff --git a/drivers/base/regmap/regmap.c b/drivers/base/regmap/regmap.c
index df2d2ef5d6b3..51fa7d66a393 100644
--- a/drivers/base/regmap/regmap.c
+++ b/drivers/base/regmap/regmap.c
@@ -1777,8 +1777,6 @@ int regmap_bulk_write(struct regmap *map, unsigned int reg, const void *val,
 	size_t val_bytes = map->format.val_bytes;
 	size_t total_size = val_bytes * val_count;
 
-	if (map->bus && !map->format.parse_inplace)
-		return -EINVAL;
 	if (!IS_ALIGNED(reg, map->reg_stride))
 		return -EINVAL;
 
@@ -1789,7 +1787,8 @@ int regmap_bulk_write(struct regmap *map, unsigned int reg, const void *val,
 	 *
 	 * The first if block is used for memory mapped io. It does not allow
 	 * val_bytes of 3 for example.
-	 * The second one is used for busses which do not have this limitation
+	 * The second one is for busses that do not provide raw I/O.
+	 * The third one is used for busses which do not have these limitations
 	 * and can write arbitrary value lengths.
 	 */
 	if (!map->bus) {
@@ -1825,6 +1824,32 @@ int regmap_bulk_write(struct regmap *map, unsigned int reg, const void *val,
 		}
 out:
 		map->unlock(map->lock_arg);
+	} else if (map->bus && !map->format.parse_inplace) {
+		const u8 *u8 = val;
+		const u16 *u16 = val;
+		const u32 *u32 = val;
+		unsigned int ival;
+
+		for (i = 0; i < val_count; i++) {
+			switch (map->format.val_bytes) {
+			case 4:
+				ival = u32[i];
+				break;
+			case 2:
+				ival = u16[i];
+				break;
+			case 1:
+				ival = u8[i];
+				break;
+			default:
+				return -EINVAL;
+			}
+
+			ret = regmap_write(map, reg + (i * map->reg_stride),
+					   ival);
+			if (ret)
+				return ret;
+		}
 	} else if (map->use_single_write ||
 		   (map->max_raw_write && map->max_raw_write < total_size)) {
 		int chunk_stride = map->reg_stride;
-- 
2.8.1

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

* [PATCH v3 2/8] mfd: ac100: Add device tree bindings for X-Powers AC100 codec/RTC combo IC
  2016-06-20  2:52 [PATCH v3 0/8] mfd: ac100: Add support for X-Powers AC100 audio codec / RTC combo IC Chen-Yu Tsai
  2016-06-20  2:52 ` [PATCH v3 1/8] regmap: Support bulk writes for devices without raw formatting Chen-Yu Tsai
@ 2016-06-20  2:52 ` Chen-Yu Tsai
  2016-06-21 13:14   ` Rob Herring
  2016-06-20  2:52 ` [PATCH v3 3/8] mfd: ac100: Add driver for X-Powers AC100 audio codec / RTC " Chen-Yu Tsai
                   ` (5 subsequent siblings)
  7 siblings, 1 reply; 20+ messages in thread
From: Chen-Yu Tsai @ 2016-06-20  2:52 UTC (permalink / raw)
  To: Mark Brown, Lee Jones, Alessandro Zummo, Alexandre Belloni,
	Rob Herring, Pawel Moll, Mark Rutland, Ian Campbell, Kumar Gala,
	Maxime Ripard, Michael Turquette, Stephen Boyd
  Cc: Chen-Yu Tsai, rtc-linux, linux-kernel, devicetree,
	linux-arm-kernel, linux-clk

Signed-off-by: Chen-Yu Tsai <wens@csie.org>
---
Changes since v2:

  - Fix interrupt line for ac100_codec in provided example.

---
 Documentation/devicetree/bindings/mfd/ac100.txt | 42 +++++++++++++++++++++++++
 1 file changed, 42 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/mfd/ac100.txt

diff --git a/Documentation/devicetree/bindings/mfd/ac100.txt b/Documentation/devicetree/bindings/mfd/ac100.txt
new file mode 100644
index 000000000000..a793954bb952
--- /dev/null
+++ b/Documentation/devicetree/bindings/mfd/ac100.txt
@@ -0,0 +1,42 @@
+X-Powers AC100 Codec/RTC IC device tree bindings
+
+AC100 is a audio codec and RTC subsystem combo IC. The 2 parts are
+separated, including power supplies and interrupt lines, but share
+a common register address space and host interface.
+
+Required properties:
+- compatible: "x-powers,ac100"
+- reg: The I2C slave address or RSB hardware address for the chip
+- sub-nodes:
+  - codec
+    - compatible: "x-powers,ac100-codec"
+    - interrupt-parent: The parent interrupt controller
+    - interrupts: SoC NMI / GPIO interrupt connected to the IRQ_AUDIO pin
+  - rtc
+    - compatible: "x-powers,ac100-rtc"
+    - interrupt-parent: The parent interrupt controller
+    - interrupts: SoC NMI / GPIO interrupt connected to the IRQ_RTC pin
+    - #clock-cells: shall be 1
+    - clock-output-names: "cko1_rtc", "cko2_rtc", "cko3_rtc"
+    - see clock/clock-bindings.txt for common clock bindings
+
+Example:
+
+ac100: codec@e89 {
+	compatible = "x-powers,ac100";
+	reg = <0xe89>;
+
+	ac100_codec {
+		compatible = "x-powers,ac100-codec";
+		interrupt-parent = <&r_pio>;
+		interrupts = <0 9 IRQ_TYPE_LEVEL_LOW>; /* PL9 */
+	};
+
+	ac100_rtc {
+		compatible = "x-powers,ac100-rtc";
+		interrupt-parent = <&nmi_intc>;
+		interrupts = <0 IRQ_TYPE_LEVEL_LOW>;
+		#clock-cells = <1>;
+		clock-output-names = "cko1_rtc", "cko2_rtc", "cko3_rtc";
+	};
+};
-- 
2.8.1

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

* [PATCH v3 3/8] mfd: ac100: Add driver for X-Powers AC100 audio codec / RTC combo IC
  2016-06-20  2:52 [PATCH v3 0/8] mfd: ac100: Add support for X-Powers AC100 audio codec / RTC combo IC Chen-Yu Tsai
  2016-06-20  2:52 ` [PATCH v3 1/8] regmap: Support bulk writes for devices without raw formatting Chen-Yu Tsai
  2016-06-20  2:52 ` [PATCH v3 2/8] mfd: ac100: Add device tree bindings for X-Powers AC100 codec/RTC combo IC Chen-Yu Tsai
@ 2016-06-20  2:52 ` Chen-Yu Tsai
  2016-06-20  2:52 ` [PATCH v3 4/8] rtc: ac100: Add RTC driver for X-Powers AC100 Chen-Yu Tsai
                   ` (4 subsequent siblings)
  7 siblings, 0 replies; 20+ messages in thread
From: Chen-Yu Tsai @ 2016-06-20  2:52 UTC (permalink / raw)
  To: Mark Brown, Lee Jones, Alessandro Zummo, Alexandre Belloni,
	Rob Herring, Pawel Moll, Mark Rutland, Ian Campbell, Kumar Gala,
	Maxime Ripard, Michael Turquette, Stephen Boyd
  Cc: Chen-Yu Tsai, rtc-linux, linux-kernel, devicetree,
	linux-arm-kernel, linux-clk

The AC100 is a multifunction device with an audio codec subsystem and
an RTC subsystem. These two subsystems share a common register space
and host interface.

Signed-off-by: Chen-Yu Tsai <wens@csie.org>
Acked-by: Lee Jones <lee.jones@linaro.org>
---
Changes since v2:

  - Dropped file name
  - Added copyright line.
  - Changed MODULE_LICENSE to GPL v2, matching the header
  - Added Lee's ack

---
 drivers/mfd/Kconfig       |  10 +++
 drivers/mfd/Makefile      |   2 +
 drivers/mfd/ac100.c       | 137 +++++++++++++++++++++++++++++++++++
 include/linux/mfd/ac100.h | 178 ++++++++++++++++++++++++++++++++++++++++++++++
 4 files changed, 327 insertions(+)
 create mode 100644 drivers/mfd/ac100.c
 create mode 100644 include/linux/mfd/ac100.h

diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig
index 00ec1290b639..c2ceb303c856 100644
--- a/drivers/mfd/Kconfig
+++ b/drivers/mfd/Kconfig
@@ -112,6 +112,16 @@ config MFD_BCM590XX
 	help
 	  Support for the BCM590xx PMUs from Broadcom
 
+config MFD_AC100
+	tristate "X-Powers AC100"
+	select MFD_CORE
+	depends on SUNXI_RSB
+	help
+	  If you say Y here you get support for the X-Powers AC100 audio codec
+	  IC.
+	  This driver include only the core APIs. You have to select individual
+	  components like codecs or RTC under the corresponding menus.
+
 config MFD_AXP20X
 	tristate
 	select MFD_CORE
diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile
index 2ba3ba35f745..bca83dbb5ed8 100644
--- a/drivers/mfd/Makefile
+++ b/drivers/mfd/Makefile
@@ -113,6 +113,8 @@ obj-$(CONFIG_PMIC_DA9052)	+= da9052-irq.o
 obj-$(CONFIG_PMIC_DA9052)	+= da9052-core.o
 obj-$(CONFIG_MFD_DA9052_SPI)	+= da9052-spi.o
 obj-$(CONFIG_MFD_DA9052_I2C)	+= da9052-i2c.o
+
+obj-$(CONFIG_MFD_AC100)		+= ac100.o
 obj-$(CONFIG_MFD_AXP20X)	+= axp20x.o
 obj-$(CONFIG_MFD_AXP20X_I2C)	+= axp20x-i2c.o
 obj-$(CONFIG_MFD_AXP20X_RSB)	+= axp20x-rsb.o
diff --git a/drivers/mfd/ac100.c b/drivers/mfd/ac100.c
new file mode 100644
index 000000000000..9713afcc7a2b
--- /dev/null
+++ b/drivers/mfd/ac100.c
@@ -0,0 +1,137 @@
+/*
+ * MFD core driver for X-Powers' AC100 Audio Codec IC
+ *
+ * The AC100 is a highly integrated audio codec and RTC subsystem designed
+ * for mobile applications. It has 3 I2S/PCM interfaces, a 2 channel DAC,
+ * a 2 channel ADC with 5 inputs and a builtin mixer. The RTC subsystem has
+ * 3 clock outputs.
+ *
+ * The audio codec and RTC parts are completely separate, sharing only the
+ * host interface for access to its registers.
+ *
+ * Copyright (2016) Chen-Yu Tsai
+ *
+ * Author: Chen-Yu Tsai <wens@csie.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/interrupt.h>
+#include <linux/kernel.h>
+#include <linux/mfd/core.h>
+#include <linux/mfd/ac100.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/regmap.h>
+#include <linux/sunxi-rsb.h>
+
+static const struct regmap_range ac100_writeable_ranges[] = {
+	regmap_reg_range(AC100_CHIP_AUDIO_RST, AC100_I2S_SR_CTRL),
+	regmap_reg_range(AC100_I2S1_CLK_CTRL, AC100_I2S1_MXR_GAIN),
+	regmap_reg_range(AC100_I2S2_CLK_CTRL, AC100_I2S2_MXR_GAIN),
+	regmap_reg_range(AC100_I2S3_CLK_CTRL, AC100_I2S3_SIG_PATH_CTRL),
+	regmap_reg_range(AC100_ADC_DIG_CTRL, AC100_ADC_VOL_CTRL),
+	regmap_reg_range(AC100_HMIC_CTRL1, AC100_HMIC_STATUS),
+	regmap_reg_range(AC100_DAC_DIG_CTRL, AC100_DAC_MXR_GAIN),
+	regmap_reg_range(AC100_ADC_APC_CTRL, AC100_LINEOUT_CTRL),
+	regmap_reg_range(AC100_ADC_DAP_L_CTRL, AC100_ADC_DAP_OPT),
+	regmap_reg_range(AC100_DAC_DAP_CTRL, AC100_DAC_DAP_OPT),
+	regmap_reg_range(AC100_ADC_DAP_ENA, AC100_DAC_DAP_ENA),
+	regmap_reg_range(AC100_SRC1_CTRL1, AC100_SRC1_CTRL2),
+	regmap_reg_range(AC100_SRC2_CTRL1, AC100_SRC2_CTRL2),
+	regmap_reg_range(AC100_CLK32K_ANALOG_CTRL, AC100_CLK32K_OUT_CTRL3),
+	regmap_reg_range(AC100_RTC_RST, AC100_RTC_UPD),
+	regmap_reg_range(AC100_ALM_INT_ENA, AC100_ALM_INT_STA),
+	regmap_reg_range(AC100_ALM_SEC, AC100_RTC_GP(15)),
+};
+
+static const struct regmap_range ac100_volatile_ranges[] = {
+	regmap_reg_range(AC100_CHIP_AUDIO_RST, AC100_PLL_CTRL2),
+	regmap_reg_range(AC100_HMIC_STATUS, AC100_HMIC_STATUS),
+	regmap_reg_range(AC100_ADC_DAP_L_STA, AC100_ADC_DAP_L_STA),
+	regmap_reg_range(AC100_SRC1_CTRL1, AC100_SRC1_CTRL1),
+	regmap_reg_range(AC100_SRC1_CTRL3, AC100_SRC2_CTRL1),
+	regmap_reg_range(AC100_SRC2_CTRL3, AC100_SRC2_CTRL4),
+	regmap_reg_range(AC100_RTC_RST, AC100_RTC_RST),
+	regmap_reg_range(AC100_RTC_SEC, AC100_ALM_INT_STA),
+	regmap_reg_range(AC100_ALM_SEC, AC100_ALM_UPD),
+};
+
+static const struct regmap_access_table ac100_writeable_table = {
+	.yes_ranges	= ac100_writeable_ranges,
+	.n_yes_ranges	= ARRAY_SIZE(ac100_writeable_ranges),
+};
+
+static const struct regmap_access_table ac100_volatile_table = {
+	.yes_ranges	= ac100_volatile_ranges,
+	.n_yes_ranges	= ARRAY_SIZE(ac100_volatile_ranges),
+};
+
+static const struct regmap_config ac100_regmap_config = {
+	.reg_bits	= 8,
+	.val_bits	= 16,
+	.wr_table	= &ac100_writeable_table,
+	.volatile_table	= &ac100_volatile_table,
+	.max_register	= AC100_RTC_GP(15),
+	.cache_type	= REGCACHE_RBTREE,
+};
+
+static struct mfd_cell ac100_cells[] = {
+	{
+		.name		= "ac100-codec",
+		.of_compatible	= "x-powers,ac100-codec",
+	}, {
+		.name		= "ac100-rtc",
+		.of_compatible	= "x-powers,ac100-rtc",
+	},
+};
+
+static int ac100_rsb_probe(struct sunxi_rsb_device *rdev)
+{
+	struct ac100_dev *ac100;
+	int ret;
+
+	ac100 = devm_kzalloc(&rdev->dev, sizeof(*ac100), GFP_KERNEL);
+	if (!ac100)
+		return -ENOMEM;
+
+	ac100->dev = &rdev->dev;
+	sunxi_rsb_device_set_drvdata(rdev, ac100);
+
+	ac100->regmap = devm_regmap_init_sunxi_rsb(rdev, &ac100_regmap_config);
+	if (IS_ERR(ac100->regmap)) {
+		ret = PTR_ERR(ac100->regmap);
+		dev_err(ac100->dev, "regmap init failed: %d\n", ret);
+		return ret;
+	}
+
+	ret = devm_mfd_add_devices(ac100->dev, PLATFORM_DEVID_NONE, ac100_cells,
+				   ARRAY_SIZE(ac100_cells), NULL, 0, NULL);
+	if (ret) {
+		dev_err(ac100->dev, "failed to add MFD devices: %d\n", ret);
+		return ret;
+	}
+
+	return 0;
+}
+
+static const struct of_device_id ac100_of_match[] = {
+	{ .compatible = "x-powers,ac100" },
+	{ },
+};
+MODULE_DEVICE_TABLE(of, ac100_of_match);
+
+static struct sunxi_rsb_driver ac100_rsb_driver = {
+	.driver = {
+		.name	= "ac100",
+		.of_match_table	= of_match_ptr(ac100_of_match),
+	},
+	.probe	= ac100_rsb_probe,
+};
+module_sunxi_rsb_driver(ac100_rsb_driver);
+
+MODULE_DESCRIPTION("Audio codec MFD core driver for AC100");
+MODULE_AUTHOR("Chen-Yu Tsai <wens@csie.org>");
+MODULE_LICENSE("GPL v2");
diff --git a/include/linux/mfd/ac100.h b/include/linux/mfd/ac100.h
new file mode 100644
index 000000000000..90cfaf775fea
--- /dev/null
+++ b/include/linux/mfd/ac100.h
@@ -0,0 +1,178 @@
+/*
+ * Functions and registers to access AC100 codec / RTC combo IC.
+ *
+ * Copyright (C) 2016 Chen-Yu Tsai
+ *
+ * Chen-Yu Tsai <wens@csie.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef __LINUX_MFD_AC100_H
+#define __LINUX_MFD_AC100_H
+
+#include <linux/regmap.h>
+
+struct ac100_dev {
+	struct device			*dev;
+	struct regmap			*regmap;
+};
+
+/* Audio codec related registers */
+#define AC100_CHIP_AUDIO_RST		0x00
+#define AC100_PLL_CTRL1			0x01
+#define AC100_PLL_CTRL2			0x02
+#define AC100_SYSCLK_CTRL		0x03
+#define AC100_MOD_CLK_ENA		0x04
+#define AC100_MOD_RST_CTRL		0x05
+#define AC100_I2S_SR_CTRL		0x06
+
+/* I2S1 interface */
+#define AC100_I2S1_CLK_CTRL		0x10
+#define AC100_I2S1_SND_OUT_CTRL		0x11
+#define AC100_I2S1_SND_IN_CTRL		0x12
+#define AC100_I2S1_MXR_SRC		0x13
+#define AC100_I2S1_VOL_CTRL1		0x14
+#define AC100_I2S1_VOL_CTRL2		0x15
+#define AC100_I2S1_VOL_CTRL3		0x16
+#define AC100_I2S1_VOL_CTRL4		0x17
+#define AC100_I2S1_MXR_GAIN		0x18
+
+/* I2S2 interface */
+#define AC100_I2S2_CLK_CTRL		0x20
+#define AC100_I2S2_SND_OUT_CTRL		0x21
+#define AC100_I2S2_SND_IN_CTRL		0x22
+#define AC100_I2S2_MXR_SRC		0x23
+#define AC100_I2S2_VOL_CTRL1		0x24
+#define AC100_I2S2_VOL_CTRL2		0x25
+#define AC100_I2S2_VOL_CTRL3		0x26
+#define AC100_I2S2_VOL_CTRL4		0x27
+#define AC100_I2S2_MXR_GAIN		0x28
+
+/* I2S3 interface */
+#define AC100_I2S3_CLK_CTRL		0x30
+#define AC100_I2S3_SND_OUT_CTRL		0x31
+#define AC100_I2S3_SND_IN_CTRL		0x32
+#define AC100_I2S3_SIG_PATH_CTRL	0x33
+
+/* ADC digital controls */
+#define AC100_ADC_DIG_CTRL		0x40
+#define AC100_ADC_VOL_CTRL		0x41
+
+/* HMIC plug sensing / key detection */
+#define AC100_HMIC_CTRL1		0x44
+#define AC100_HMIC_CTRL2		0x45
+#define AC100_HMIC_STATUS		0x46
+
+/* DAC digital controls */
+#define AC100_DAC_DIG_CTRL		0x48
+#define AC100_DAC_VOL_CTRL		0x49
+#define AC100_DAC_MXR_SRC		0x4c
+#define AC100_DAC_MXR_GAIN		0x4d
+
+/* Analog controls */
+#define AC100_ADC_APC_CTRL		0x50
+#define AC100_ADC_SRC			0x51
+#define AC100_ADC_SRC_BST_CTRL		0x52
+#define AC100_OUT_MXR_DAC_A_CTRL	0x53
+#define AC100_OUT_MXR_SRC		0x54
+#define AC100_OUT_MXR_SRC_BST		0x55
+#define AC100_HPOUT_CTRL		0x56
+#define AC100_ERPOUT_CTRL		0x57
+#define AC100_SPKOUT_CTRL		0x58
+#define AC100_LINEOUT_CTRL		0x59
+
+/* ADC digital audio processing (high pass filter & auto gain control */
+#define AC100_ADC_DAP_L_STA		0x80
+#define AC100_ADC_DAP_R_STA		0x81
+#define AC100_ADC_DAP_L_CTRL		0x82
+#define AC100_ADC_DAP_R_CTRL		0x83
+#define AC100_ADC_DAP_L_T_L		0x84 /* Left Target Level */
+#define AC100_ADC_DAP_R_T_L		0x85 /* Right Target Level */
+#define AC100_ADC_DAP_L_H_A_C		0x86 /* Left High Avg. Coef */
+#define AC100_ADC_DAP_L_L_A_C		0x87 /* Left Low Avg. Coef */
+#define AC100_ADC_DAP_R_H_A_C		0x88 /* Right High Avg. Coef */
+#define AC100_ADC_DAP_R_L_A_C		0x89 /* Right Low Avg. Coef */
+#define AC100_ADC_DAP_L_D_T		0x8a /* Left Decay Time */
+#define AC100_ADC_DAP_L_A_T		0x8b /* Left Attack Time */
+#define AC100_ADC_DAP_R_D_T		0x8c /* Right Decay Time */
+#define AC100_ADC_DAP_R_A_T		0x8d /* Right Attack Time */
+#define AC100_ADC_DAP_N_TH		0x8e /* Noise Threshold */
+#define AC100_ADC_DAP_L_H_N_A_C		0x8f /* Left High Noise Avg. Coef */
+#define AC100_ADC_DAP_L_L_N_A_C		0x90 /* Left Low Noise Avg. Coef */
+#define AC100_ADC_DAP_R_H_N_A_C		0x91 /* Right High Noise Avg. Coef */
+#define AC100_ADC_DAP_R_L_N_A_C		0x92 /* Right Low Noise Avg. Coef */
+#define AC100_ADC_DAP_H_HPF_C		0x93 /* High High-Pass-Filter Coef */
+#define AC100_ADC_DAP_L_HPF_C		0x94 /* Low High-Pass-Filter Coef */
+#define AC100_ADC_DAP_OPT		0x95 /* AGC Optimum */
+
+/* DAC digital audio processing (high pass filter & dynamic range control) */
+#define AC100_DAC_DAP_CTRL		0xa0
+#define AC100_DAC_DAP_H_HPF_C		0xa1 /* High High-Pass-Filter Coef */
+#define AC100_DAC_DAP_L_HPF_C		0xa2 /* Low High-Pass-Filter Coef */
+#define AC100_DAC_DAP_L_H_E_A_C		0xa3 /* Left High Energy Avg Coef */
+#define AC100_DAC_DAP_L_L_E_A_C		0xa4 /* Left Low Energy Avg Coef */
+#define AC100_DAC_DAP_R_H_E_A_C		0xa5 /* Right High Energy Avg Coef */
+#define AC100_DAC_DAP_R_L_E_A_C		0xa6 /* Right Low Energy Avg Coef */
+#define AC100_DAC_DAP_H_G_D_T_C		0xa7 /* High Gain Delay Time Coef */
+#define AC100_DAC_DAP_L_G_D_T_C		0xa8 /* Low Gain Delay Time Coef */
+#define AC100_DAC_DAP_H_G_A_T_C		0xa9 /* High Gain Attack Time Coef */
+#define AC100_DAC_DAP_L_G_A_T_C		0xaa /* Low Gain Attack Time Coef */
+#define AC100_DAC_DAP_H_E_TH		0xab /* High Energy Threshold */
+#define AC100_DAC_DAP_L_E_TH		0xac /* Low Energy Threshold */
+#define AC100_DAC_DAP_H_G_K		0xad /* High Gain K parameter */
+#define AC100_DAC_DAP_L_G_K		0xae /* Low Gain K parameter */
+#define AC100_DAC_DAP_H_G_OFF		0xaf /* High Gain offset */
+#define AC100_DAC_DAP_L_G_OFF		0xb0 /* Low Gain offset */
+#define AC100_DAC_DAP_OPT		0xb1 /* DRC optimum */
+
+/* Digital audio processing enable */
+#define AC100_ADC_DAP_ENA		0xb4
+#define AC100_DAC_DAP_ENA		0xb5
+
+/* SRC control */
+#define AC100_SRC1_CTRL1		0xb8
+#define AC100_SRC1_CTRL2		0xb9
+#define AC100_SRC1_CTRL3		0xba
+#define AC100_SRC1_CTRL4		0xbb
+#define AC100_SRC2_CTRL1		0xbc
+#define AC100_SRC2_CTRL2		0xbd
+#define AC100_SRC2_CTRL3		0xbe
+#define AC100_SRC2_CTRL4		0xbf
+
+/* RTC clk control */
+#define AC100_CLK32K_ANALOG_CTRL	0xc0
+#define AC100_CLK32K_OUT_CTRL1		0xc1
+#define AC100_CLK32K_OUT_CTRL2		0xc2
+#define AC100_CLK32K_OUT_CTRL3		0xc3
+
+/* RTC module */
+#define AC100_RTC_RST			0xc6
+#define AC100_RTC_CTRL			0xc7
+#define AC100_RTC_SEC			0xc8 /* second */
+#define AC100_RTC_MIN			0xc9 /* minute */
+#define AC100_RTC_HOU			0xca /* hour */
+#define AC100_RTC_WEE			0xcb /* weekday */
+#define AC100_RTC_DAY			0xcc /* day */
+#define AC100_RTC_MON			0xcd /* month */
+#define AC100_RTC_YEA			0xce /* year */
+#define AC100_RTC_UPD			0xcf /* update trigger */
+
+/* RTC alarm */
+#define AC100_ALM_INT_ENA		0xd0
+#define	AC100_ALM_INT_STA		0xd1
+#define AC100_ALM_SEC			0xd8
+#define AC100_ALM_MIN			0xd9
+#define AC100_ALM_HOU			0xda
+#define AC100_ALM_WEE			0xdb
+#define AC100_ALM_DAY			0xdc
+#define AC100_ALM_MON			0xdd
+#define AC100_ALM_YEA			0xde
+#define AC100_ALM_UPD			0xdf
+
+/* RTC general purpose register 0 ~ 15 */
+#define AC100_RTC_GP(x)			(0xe0 + (x))
+
+#endif /* __LINUX_MFD_AC100_H */
-- 
2.8.1

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

* [PATCH v3 4/8] rtc: ac100: Add RTC driver for X-Powers AC100
  2016-06-20  2:52 [PATCH v3 0/8] mfd: ac100: Add support for X-Powers AC100 audio codec / RTC combo IC Chen-Yu Tsai
                   ` (2 preceding siblings ...)
  2016-06-20  2:52 ` [PATCH v3 3/8] mfd: ac100: Add driver for X-Powers AC100 audio codec / RTC " Chen-Yu Tsai
@ 2016-06-20  2:52 ` Chen-Yu Tsai
  2016-06-26  0:30   ` Alexandre Belloni
  2016-06-26  1:02   ` Alexandre Belloni
  2016-06-20  2:52 ` [PATCH v3 5/8] rtc: ac100: Add clk output support Chen-Yu Tsai
                   ` (3 subsequent siblings)
  7 siblings, 2 replies; 20+ messages in thread
From: Chen-Yu Tsai @ 2016-06-20  2:52 UTC (permalink / raw)
  To: Mark Brown, Lee Jones, Alessandro Zummo, Alexandre Belloni,
	Rob Herring, Pawel Moll, Mark Rutland, Ian Campbell, Kumar Gala,
	Maxime Ripard, Michael Turquette, Stephen Boyd
  Cc: Chen-Yu Tsai, rtc-linux, linux-kernel, devicetree,
	linux-arm-kernel, linux-clk

X-Powers AC100 is a codec / RTC combo chip. This driver supports
the RTC sub-device.

The RTC block also has clock outputs and non-volatile storage.
Non-volatile storage wthin the RTC hardware is not supported.
Clock output support is added in the next patch.

Signed-off-by: Chen-Yu Tsai <wens@csie.org>
---
Changes since v2:

  - Fixed off-by-1 errors in register mask macros
  - Fixed copy-paste error in set_alarm function
  - Drop uie_unsupported, since the alarm works now
  - Fixed up copyright notice
  - Changed license to GPL v2, matching mfd driver

---
 drivers/rtc/Kconfig     |  10 ++
 drivers/rtc/Makefile    |   1 +
 drivers/rtc/rtc-ac100.c | 365 ++++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 376 insertions(+)
 create mode 100644 drivers/rtc/rtc-ac100.c

diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig
index 18639e0cb6e2..b9d7cbb6bd76 100644
--- a/drivers/rtc/Kconfig
+++ b/drivers/rtc/Kconfig
@@ -183,6 +183,16 @@ config RTC_DRV_ABX80X
 	  This driver can also be built as a module. If so, the module
 	  will be called rtc-abx80x.
 
+config RTC_DRV_AC100
+	tristate "X-Powers AC100"
+	depends on MFD_AC100
+	help
+	  If you say yes here you get support for the real-time clock found
+	  in X-Powers AC100 family peripheral ICs.
+
+	  This driver can also be built as a module. If so, the module
+	  will be called rtc-ac100.
+
 config RTC_DRV_AS3722
 	tristate "ams AS3722 RTC driver"
 	depends on MFD_AS3722
diff --git a/drivers/rtc/Makefile b/drivers/rtc/Makefile
index ea2833723fa9..b07c28779573 100644
--- a/drivers/rtc/Makefile
+++ b/drivers/rtc/Makefile
@@ -26,6 +26,7 @@ obj-$(CONFIG_RTC_DRV_AB3100)	+= rtc-ab3100.o
 obj-$(CONFIG_RTC_DRV_AB8500)	+= rtc-ab8500.o
 obj-$(CONFIG_RTC_DRV_ABB5ZES3)	+= rtc-ab-b5ze-s3.o
 obj-$(CONFIG_RTC_DRV_ABX80X)	+= rtc-abx80x.o
+obj-$(CONFIG_RTC_DRV_AC100)	+= rtc-ac100.o
 obj-$(CONFIG_RTC_DRV_ARMADA38X)	+= rtc-armada38x.o
 obj-$(CONFIG_RTC_DRV_AS3722)	+= rtc-as3722.o
 obj-$(CONFIG_RTC_DRV_ASM9260)	+= rtc-asm9260.o
diff --git a/drivers/rtc/rtc-ac100.c b/drivers/rtc/rtc-ac100.c
new file mode 100644
index 000000000000..752bc0771d71
--- /dev/null
+++ b/drivers/rtc/rtc-ac100.c
@@ -0,0 +1,365 @@
+/*
+ * RTC Driver for X-Powers AC100
+ *
+ * Copyright (c) 2016 Chen-Yu Tsai
+ *
+ * Chen-Yu Tsai <wens@csie.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ */
+
+#include <linux/bcd.h>
+#include <linux/device.h>
+#include <linux/interrupt.h>
+#include <linux/kernel.h>
+#include <linux/mfd/ac100.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/of.h>
+#include <linux/of_irq.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+#include <linux/rtc.h>
+#include <linux/types.h>
+
+/* Control register */
+#define AC100_RTC_CTRL_24HOUR	BIT(0)
+
+/* RTC */
+#define AC100_RTC_SEC_MASK	GENMASK(6, 0)
+#define AC100_RTC_MIN_MASK	GENMASK(6, 0)
+#define AC100_RTC_HOU_MASK	GENMASK(5, 0)
+#define AC100_RTC_WEE_MASK	GENMASK(2, 0)
+#define AC100_RTC_DAY_MASK	GENMASK(5, 0)
+#define AC100_RTC_MON_MASK	GENMASK(4, 0)
+#define AC100_RTC_YEA_MASK	GENMASK(7, 0)
+#define AC100_RTC_YEA_LEAP	BIT(15)
+#define AC100_RTC_UPD_TRIGGER	BIT(15)
+
+/* Alarm (wall clock) */
+#define AC100_ALM_INT_ENABLE	BIT(0)
+
+#define AC100_ALM_SEC_MASK	GENMASK(6, 0)
+#define AC100_ALM_MIN_MASK	GENMASK(6, 0)
+#define AC100_ALM_HOU_MASK	GENMASK(5, 0)
+#define AC100_ALM_WEE_MASK	GENMASK(2, 0)
+#define AC100_ALM_DAY_MASK	GENMASK(5, 0)
+#define AC100_ALM_MON_MASK	GENMASK(4, 0)
+#define AC100_ALM_YEA_MASK	GENMASK(7, 0)
+#define AC100_ALM_ENABLE_FLAG	BIT(15)
+#define AC100_ALM_UPD_TRIGGER	BIT(15)
+
+/*
+ * The year parameter passed to the driver is usually an offset relative to
+ * the year 1900. This macro is used to convert this offset to another one
+ * relative to the minimum year allowed by the hardware.
+ *
+ * The year range is 1970 - 2069. This range is selected to match Allwinner's
+ * driver.
+ */
+#define AC100_YEAR_MIN				1970
+#define AC100_YEAR_MAX				2069
+#define AC100_YEAR_OFF				(AC100_YEAR_MIN - 1900)
+
+struct ac100_rtc_dev {
+	struct rtc_device *rtc;
+	struct device *dev;
+	struct regmap *regmap;
+	struct mutex mutex;
+	int irq;
+	unsigned long alarm;
+};
+
+static int ac100_rtc_get_time(struct device *dev, struct rtc_time *rtc_tm)
+{
+	struct ac100_rtc_dev *chip = dev_get_drvdata(dev);
+	struct regmap *regmap = chip->regmap;
+	u16 reg[7];
+	int ret;
+
+	ret = regmap_bulk_read(regmap, AC100_RTC_SEC, reg, 7);
+	if (ret)
+		return ret;
+
+	rtc_tm->tm_sec  = bcd2bin(reg[0] & AC100_RTC_SEC_MASK);
+	rtc_tm->tm_min  = bcd2bin(reg[1] & AC100_RTC_MIN_MASK);
+	rtc_tm->tm_hour = bcd2bin(reg[2] & AC100_RTC_HOU_MASK);
+	rtc_tm->tm_wday = bcd2bin(reg[3] & AC100_RTC_WEE_MASK);
+	rtc_tm->tm_mday = bcd2bin(reg[4] & AC100_RTC_DAY_MASK);
+	rtc_tm->tm_mon  = bcd2bin(reg[5] & AC100_RTC_MON_MASK);
+	rtc_tm->tm_year = bcd2bin(reg[6] & AC100_RTC_YEA_MASK);
+
+	rtc_tm->tm_mon  -= 1;
+
+	/*
+	 * switch from (data_year->min)-relative offset to
+	 * a (1900)-relative one
+	 */
+	rtc_tm->tm_year += AC100_YEAR_OFF;
+
+	return rtc_valid_tm(rtc_tm);
+}
+
+static int ac100_rtc_set_time(struct device *dev, struct rtc_time *rtc_tm)
+{
+	struct ac100_rtc_dev *chip = dev_get_drvdata(dev);
+	struct regmap *regmap = chip->regmap;
+	int year;
+	u16 reg[8];
+
+	/* our RTC has a limited year range... */
+	year = rtc_tm->tm_year + 1900;
+	if (year < AC100_YEAR_MIN || year > AC100_YEAR_MAX) {
+		dev_err(dev, "rtc only supports year in range %d - %d\n",
+			AC100_YEAR_MIN, AC100_YEAR_MAX);
+		return -EINVAL;
+	}
+
+	/* correct offsets */
+	rtc_tm->tm_year -= AC100_YEAR_OFF;
+	rtc_tm->tm_mon += 1;
+
+	/* convert to BCD */
+	reg[0] = bin2bcd(rtc_tm->tm_sec)  & AC100_RTC_SEC_MASK;
+	reg[1] = bin2bcd(rtc_tm->tm_min)  & AC100_RTC_MIN_MASK;
+	reg[2] = bin2bcd(rtc_tm->tm_hour) & AC100_RTC_HOU_MASK;
+	reg[3] = bin2bcd(rtc_tm->tm_wday) & AC100_RTC_WEE_MASK;
+	reg[4] = bin2bcd(rtc_tm->tm_mday) & AC100_RTC_DAY_MASK;
+	reg[5] = bin2bcd(rtc_tm->tm_mon)  & AC100_RTC_MON_MASK;
+	reg[6] = bin2bcd(rtc_tm->tm_year) & AC100_RTC_YEA_MASK;
+	/* trigger write */
+	reg[7] = AC100_RTC_UPD_TRIGGER;
+
+	/* Is it a leap year? */
+	if (is_leap_year(year))
+		reg[6] |= AC100_RTC_YEA_LEAP;
+
+	return regmap_bulk_write(regmap, AC100_RTC_SEC, reg, 8);
+}
+
+static int _ac100_rtc_alarm_irq_enable(struct ac100_rtc_dev *chip,
+				       unsigned int en)
+{
+	struct regmap *regmap = chip->regmap;
+	unsigned int val;
+
+	val = en ? AC100_ALM_INT_ENABLE : 0;
+
+	return regmap_write(regmap, AC100_ALM_INT_ENA, val);
+}
+
+static int ac100_rtc_alarm_irq_enable(struct device *dev, unsigned int en)
+{
+	struct ac100_rtc_dev *chip = dev_get_drvdata(dev);
+	int ret;
+
+	mutex_lock(&chip->mutex);
+	ret = _ac100_rtc_alarm_irq_enable(chip, en);
+	mutex_unlock(&chip->mutex);
+
+	return ret;
+}
+
+static int ac100_rtc_get_alarm(struct device *dev, struct rtc_wkalrm *alrm)
+{
+	struct ac100_rtc_dev *chip = dev_get_drvdata(dev);
+	struct regmap *regmap = chip->regmap;
+	struct rtc_time *alrm_tm = &alrm->time;
+	u16 reg[7];
+	unsigned int val;
+	int ret;
+
+	mutex_lock(&chip->mutex);
+
+	ret = regmap_read(regmap, AC100_ALM_INT_ENA, &val);
+	if (ret)
+		goto out;
+
+	alrm->enabled = !!(val & AC100_ALM_INT_ENABLE);
+
+	ret = regmap_bulk_read(regmap, AC100_ALM_SEC, reg, 7);
+	if (ret)
+		goto out;
+
+	alrm_tm->tm_sec  = bcd2bin(reg[0] & AC100_ALM_SEC_MASK);
+	alrm_tm->tm_min  = bcd2bin(reg[1] & AC100_ALM_MIN_MASK);
+	alrm_tm->tm_hour = bcd2bin(reg[2] & AC100_ALM_HOU_MASK);
+	alrm_tm->tm_wday = bcd2bin(reg[3] & AC100_ALM_WEE_MASK);
+	alrm_tm->tm_mday = bcd2bin(reg[4] & AC100_ALM_DAY_MASK);
+	alrm_tm->tm_mon  = bcd2bin(reg[5] & AC100_ALM_MON_MASK);
+	alrm_tm->tm_year = bcd2bin(reg[6] & AC100_ALM_YEA_MASK);
+
+	alrm_tm->tm_mon  -= 1;
+
+	/*
+	 * switch from (data_year->min)-relative offset to
+	 * a (1900)-relative one
+	 */
+	alrm_tm->tm_year += AC100_YEAR_OFF;
+
+out:
+	mutex_unlock(&chip->mutex);
+	return ret;
+}
+
+static int ac100_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
+{
+	struct ac100_rtc_dev *chip = dev_get_drvdata(dev);
+	struct regmap *regmap = chip->regmap;
+	struct rtc_time *alrm_tm = &alrm->time;
+	u16 reg[8];
+	int year;
+	int ret;
+
+	/* our alarm has a limited year range... */
+	year = alrm_tm->tm_year + 1900;
+	if (year < AC100_YEAR_MIN || year > AC100_YEAR_MAX) {
+		dev_err(dev, "alarm only supports year in range %d - %d\n",
+			AC100_YEAR_MIN, AC100_YEAR_MAX);
+		return -EINVAL;
+	}
+
+	/* correct offsets */
+	alrm_tm->tm_year -= AC100_YEAR_OFF;
+	alrm_tm->tm_mon += 1;
+
+	/* convert to BCD */
+	reg[0] = (bin2bcd(alrm_tm->tm_sec)  & AC100_ALM_SEC_MASK) |
+			AC100_ALM_ENABLE_FLAG;
+	reg[1] = (bin2bcd(alrm_tm->tm_min)  & AC100_ALM_MIN_MASK) |
+			AC100_ALM_ENABLE_FLAG;
+	reg[2] = (bin2bcd(alrm_tm->tm_hour) & AC100_ALM_HOU_MASK) |
+			AC100_ALM_ENABLE_FLAG;
+	/* Do not enable weekday alarm */
+	reg[3] = bin2bcd(alrm_tm->tm_wday) & AC100_ALM_WEE_MASK;
+	reg[4] = (bin2bcd(alrm_tm->tm_mday) & AC100_ALM_DAY_MASK) |
+			AC100_ALM_ENABLE_FLAG;
+	reg[5] = (bin2bcd(alrm_tm->tm_mon)  & AC100_ALM_MON_MASK) |
+			AC100_ALM_ENABLE_FLAG;
+	reg[6] = (bin2bcd(alrm_tm->tm_year) & AC100_ALM_YEA_MASK) |
+			AC100_ALM_ENABLE_FLAG;
+	/* trigger write */
+	reg[7] = AC100_ALM_UPD_TRIGGER;
+
+	mutex_lock(&chip->mutex);
+
+	ret = regmap_bulk_write(regmap, AC100_ALM_SEC, reg, 8);
+	if (ret)
+		goto out;
+
+	ret = _ac100_rtc_alarm_irq_enable(chip, alrm->enabled);
+
+out:
+	mutex_unlock(&chip->mutex);
+	return ret;
+}
+
+static irqreturn_t ac100_rtc_irq(int irq, void *data)
+{
+	struct ac100_rtc_dev *chip = data;
+	struct regmap *regmap = chip->regmap;
+	unsigned int val = 0;
+	int ret;
+
+	mutex_lock(&chip->mutex);
+
+	/* read status */
+	ret = regmap_read(regmap, AC100_ALM_INT_STA, &val);
+	if (ret)
+		goto out;
+
+	if (val & AC100_ALM_INT_ENABLE) {
+		/* signal rtc framework */
+		rtc_update_irq(chip->rtc, 1, RTC_AF | RTC_IRQF);
+
+		/* clear status */
+		ret = regmap_write(regmap, AC100_ALM_INT_STA, val);
+		if (ret)
+			goto out;
+
+		/* disable interrupt */
+		ret = _ac100_rtc_alarm_irq_enable(chip, 0);
+		if (ret)
+			goto out;
+	}
+
+out:
+	mutex_unlock(&chip->mutex);
+	return IRQ_HANDLED;
+}
+
+static const struct rtc_class_ops ac100_rtc_ops = {
+	.read_time	  = ac100_rtc_get_time,
+	.set_time	  = ac100_rtc_set_time,
+	.read_alarm	  = ac100_rtc_get_alarm,
+	.set_alarm	  = ac100_rtc_set_alarm,
+	.alarm_irq_enable = ac100_rtc_alarm_irq_enable,
+};
+
+static int ac100_rtc_probe(struct platform_device *pdev)
+{
+	struct ac100_dev *ac100 = dev_get_drvdata(pdev->dev.parent);
+	struct ac100_rtc_dev *chip;
+	int ret;
+
+	chip = devm_kzalloc(&pdev->dev, sizeof(*chip), GFP_KERNEL);
+	platform_set_drvdata(pdev, chip);
+	chip->dev = &pdev->dev;
+	chip->regmap = ac100->regmap;
+	mutex_init(&chip->mutex);
+
+	chip->irq = of_irq_get(pdev->dev.of_node, 0);
+	if (chip->irq < 0) {
+		dev_err(&pdev->dev, "No IRQ resource\n");
+		return chip->irq;
+	}
+
+	ret = devm_request_threaded_irq(&pdev->dev, chip->irq, NULL,
+					ac100_rtc_irq,
+					IRQF_SHARED | IRQF_ONESHOT,
+					dev_name(&pdev->dev), chip);
+	if (ret) {
+		dev_err(&pdev->dev, "Could not request IRQ\n");
+		return ret;
+	}
+
+	/* always use 24 hour mode */
+	regmap_write_bits(chip->regmap, AC100_RTC_CTRL, AC100_RTC_CTRL_24HOUR,
+			  AC100_RTC_CTRL_24HOUR);
+
+	/* disable counter alarm interrupt */
+	regmap_write(chip->regmap, AC100_ALM_INT_ENA, 0);
+
+	/* clear counter alarm pending interrupts */
+	regmap_write(chip->regmap, AC100_ALM_INT_STA, AC100_ALM_INT_ENABLE);
+
+	chip->rtc = devm_rtc_device_register(&pdev->dev, "rtc-ac100",
+					     &ac100_rtc_ops, THIS_MODULE);
+	if (IS_ERR(chip->rtc)) {
+		dev_err(&pdev->dev, "unable to register device\n");
+		return PTR_ERR(chip->rtc);
+	}
+
+	dev_info(&pdev->dev, "RTC enabled\n");
+
+	return 0;
+}
+
+static struct platform_driver ac100_rtc_driver = {
+	.probe		= ac100_rtc_probe,
+	.driver		= {
+		.name		= "ac100-rtc",
+	},
+};
+module_platform_driver(ac100_rtc_driver);
+
+MODULE_DESCRIPTION("X-Powers AC100 RTC driver");
+MODULE_AUTHOR("Chen-Yu Tsai <wens@csie.org>");
+MODULE_LICENSE("GPL v2");
-- 
2.8.1

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

* [PATCH v3 5/8] rtc: ac100: Add clk output support
  2016-06-20  2:52 [PATCH v3 0/8] mfd: ac100: Add support for X-Powers AC100 audio codec / RTC combo IC Chen-Yu Tsai
                   ` (3 preceding siblings ...)
  2016-06-20  2:52 ` [PATCH v3 4/8] rtc: ac100: Add RTC driver for X-Powers AC100 Chen-Yu Tsai
@ 2016-06-20  2:52 ` Chen-Yu Tsai
  2016-06-22 10:02   ` Maxime Ripard
  2016-06-26  0:45   ` Alexandre Belloni
  2016-06-20  2:52 ` [PATCH v3 6/8] ARM: dts: sun9i: a80-optimus: Add device node for AC100 Chen-Yu Tsai
                   ` (2 subsequent siblings)
  7 siblings, 2 replies; 20+ messages in thread
From: Chen-Yu Tsai @ 2016-06-20  2:52 UTC (permalink / raw)
  To: Mark Brown, Lee Jones, Alessandro Zummo, Alexandre Belloni,
	Rob Herring, Pawel Moll, Mark Rutland, Ian Campbell, Kumar Gala,
	Maxime Ripard, Michael Turquette, Stephen Boyd
  Cc: Chen-Yu Tsai, rtc-linux, linux-kernel, devicetree,
	linux-arm-kernel, linux-clk

The AC100's RTC side has 3 clock outputs on external pins, which can
provide a clock signal to the SoC or other modules, such as WiFi or
GSM modules.

Support this with a custom clk driver integrated with the rtc driver.

Signed-off-by: Chen-Yu Tsai <wens@csie.org>
---
Changes since v2: none
Changes since v1: none
---
 drivers/rtc/rtc-ac100.c | 319 ++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 319 insertions(+)

diff --git a/drivers/rtc/rtc-ac100.c b/drivers/rtc/rtc-ac100.c
index 752bc0771d71..ef5bf102d2fc 100644
--- a/drivers/rtc/rtc-ac100.c
+++ b/drivers/rtc/rtc-ac100.c
@@ -16,6 +16,7 @@
  */
 
 #include <linux/bcd.h>
+#include <linux/clk-provider.h>
 #include <linux/device.h>
 #include <linux/interrupt.h>
 #include <linux/kernel.h>
@@ -32,6 +33,15 @@
 /* Control register */
 #define AC100_RTC_CTRL_24HOUR	BIT(0)
 
+/* Clock output register bits */
+#define AC100_CLK32K_PRE_DIV_SHIFT	5
+#define AC100_CLK32K_PRE_DIV_WIDTH	3
+#define AC100_CLK32K_MUX_SHIFT		4
+#define AC100_CLK32K_MUX_WIDTH		1
+#define AC100_CLK32K_DIV_SHIFT		1
+#define AC100_CLK32K_DIV_WIDTH		3
+#define AC100_CLK32K_EN			BIT(0)
+
 /* RTC */
 #define AC100_RTC_SEC_MASK	GENMASK(6, 0)
 #define AC100_RTC_MIN_MASK	GENMASK(6, 0)
@@ -68,6 +78,26 @@
 #define AC100_YEAR_MAX				2069
 #define AC100_YEAR_OFF				(AC100_YEAR_MIN - 1900)
 
+struct ac100_clk32k {
+	struct clk_hw hw;
+	struct regmap *regmap;
+	u8 offset;
+};
+
+#define to_ac100_clk32k(_hw) container_of(_hw, struct ac100_clk32k, hw)
+
+#define AC100_RTC_32K_NAME	"ac100-rtc-32k"
+#define AC100_RTC_32K_RATE	32768
+#define AC100_ADDA_4M_NAME	"ac100-adda-4M"
+#define AC100_ADDA_4M_RATE	4000000
+#define AC100_CLK32K_NUM	3
+
+static const char * const ac100_clk32k_names[] = {
+	"ac100-clk32k-ap",
+	"ac100-clk32k-bb",
+	"ac100-clk32k-md",
+};
+
 struct ac100_rtc_dev {
 	struct rtc_device *rtc;
 	struct device *dev;
@@ -75,8 +105,283 @@ struct ac100_rtc_dev {
 	struct mutex mutex;
 	int irq;
 	unsigned long alarm;
+
+	struct clk_hw *rtc_32k_clk;
+	struct clk_hw *adda_4M_clk;
+	struct ac100_clk32k clks[AC100_CLK32K_NUM];
+	struct clk_hw_onecell_data *clk_data;
+};
+
+/**
+ * Clock controls for 3 clock output pins
+ */
+
+static const struct clk_div_table ac100_clk32k_prediv[] = {
+	{ .val = 0, .div = 1 },
+	{ .val = 1, .div = 2 },
+	{ .val = 2, .div = 4 },
+	{ .val = 3, .div = 8 },
+	{ .val = 4, .div = 16 },
+	{ .val = 5, .div = 32 },
+	{ .val = 6, .div = 64 },
+	{ .val = 7, .div = 122 },
+	{ },
+};
+
+/* Abuse the fact that one parent is 32768 Hz, and the other is 4 MHz */
+static unsigned long ac100_clk32k_recalc_rate(struct clk_hw *hw,
+					      unsigned long prate)
+{
+	struct ac100_clk32k *clk = to_ac100_clk32k(hw);
+	unsigned int reg, div;
+
+	regmap_read(clk->regmap, clk->offset, &reg);
+
+	/* Handle pre-divider first */
+	if (prate != AC100_RTC_32K_RATE) {
+		div = (reg >> AC100_CLK32K_PRE_DIV_SHIFT) &
+			((1 << AC100_CLK32K_PRE_DIV_WIDTH) - 1);
+		prate = divider_recalc_rate(hw, prate, div,
+					    ac100_clk32k_prediv, 0);
+	}
+
+	div = (reg >> AC100_CLK32K_DIV_SHIFT) &
+		(BIT(AC100_CLK32K_DIV_WIDTH) - 1);
+	return divider_recalc_rate(hw, prate, div, NULL,
+				   CLK_DIVIDER_POWER_OF_TWO);
+}
+
+static long ac100_clk32k_round_rate(struct clk_hw *hw, unsigned long rate,
+				    unsigned long prate)
+{
+	unsigned long best_rate = 0, tmp_rate, tmp_prate;
+	int i;
+
+	if (prate == AC100_RTC_32K_RATE)
+		return divider_round_rate(hw, rate, &prate, NULL,
+					  AC100_CLK32K_DIV_WIDTH,
+					  CLK_DIVIDER_POWER_OF_TWO);
+
+	for (i = 0; ac100_clk32k_prediv[i].div; i++) {
+		tmp_prate = DIV_ROUND_UP(prate, ac100_clk32k_prediv[i].val);
+		tmp_rate = divider_round_rate(hw, rate, &tmp_prate, NULL,
+					      AC100_CLK32K_DIV_WIDTH,
+					      CLK_DIVIDER_POWER_OF_TWO);
+
+		if (tmp_rate > rate)
+			continue;
+		if (rate - tmp_rate < best_rate - tmp_rate)
+			best_rate = tmp_rate;
+	}
+
+	return best_rate;
+}
+
+static int ac100_clk32k_determine_rate(struct clk_hw *hw,
+				       struct clk_rate_request *req)
+{
+	struct clk_hw *best_parent;
+	unsigned long best = 0;
+	int i, num_parents = clk_hw_get_num_parents(hw);
+
+	for (i = 0; i < num_parents; i++) {
+		struct clk_hw *parent = clk_hw_get_parent_by_index(hw, i);
+		unsigned long tmp, prate = clk_hw_get_rate(parent);
+
+		tmp = ac100_clk32k_round_rate(hw, req->rate, prate);
+
+		if (tmp > req->rate)
+			continue;
+		if (req->rate - tmp < req->rate - best) {
+			best = tmp;
+			best_parent = parent;
+		}
+	}
+
+	if (!best)
+		return -EINVAL;
+
+	req->best_parent_hw = best_parent;
+	req->best_parent_rate = best;
+	req->rate = best;
+
+	return 0;
+}
+
+static int ac100_clk32k_set_rate(struct clk_hw *hw, unsigned long rate,
+				 unsigned long prate)
+{
+	struct ac100_clk32k *clk = to_ac100_clk32k(hw);
+	int div = 0, pre_div = 0;
+
+	do {
+		div = divider_get_val(rate * ac100_clk32k_prediv[pre_div].div,
+				      prate, NULL, AC100_CLK32K_DIV_WIDTH,
+				      CLK_DIVIDER_POWER_OF_TWO);
+		if (div >= 0)
+			break;
+	} while (prate == AC100_ADDA_4M_RATE &&
+		 ac100_clk32k_prediv[++pre_div].div);
+
+	if (div < 0)
+		return div;
+
+	pre_div = ac100_clk32k_prediv[pre_div].val;
+
+	regmap_update_bits(clk->regmap, clk->offset,
+			   ((1 << AC100_CLK32K_DIV_WIDTH) - 1) << AC100_CLK32K_DIV_SHIFT |
+			   ((1 << AC100_CLK32K_PRE_DIV_WIDTH) - 1) << AC100_CLK32K_PRE_DIV_SHIFT,
+			   (div - 1) << AC100_CLK32K_DIV_SHIFT |
+			   (pre_div - 1) << AC100_CLK32K_PRE_DIV_SHIFT);
+
+	return 0;
+}
+
+static int ac100_clk32k_prepare(struct clk_hw *hw)
+{
+	struct ac100_clk32k *clk = to_ac100_clk32k(hw);
+
+	return regmap_update_bits(clk->regmap, clk->offset, AC100_CLK32K_EN,
+				  AC100_CLK32K_EN);
+}
+
+static void ac100_clk32k_unprepare(struct clk_hw *hw)
+{
+	struct ac100_clk32k *clk = to_ac100_clk32k(hw);
+
+	regmap_update_bits(clk->regmap, clk->offset, AC100_CLK32K_EN, 0);
+}
+
+static int ac100_clk32k_is_prepared(struct clk_hw *hw)
+{
+	struct ac100_clk32k *clk = to_ac100_clk32k(hw);
+	unsigned int reg;
+
+	regmap_read(clk->regmap, clk->offset, &reg);
+
+	return reg & AC100_CLK32K_EN;
+}
+
+static u8 ac100_clk32k_get_parent(struct clk_hw *hw)
+{
+	struct ac100_clk32k *clk = to_ac100_clk32k(hw);
+	unsigned int reg;
+
+	regmap_read(clk->regmap, clk->offset, &reg);
+
+	return (reg >> AC100_CLK32K_MUX_SHIFT) & 0x1;
+}
+
+static int ac100_clk32k_set_parent(struct clk_hw *hw, u8 index)
+{
+	struct ac100_clk32k *clk = to_ac100_clk32k(hw);
+
+	return regmap_update_bits(clk->regmap, clk->offset,
+				  BIT(AC100_CLK32K_MUX_SHIFT),
+				  index ? BIT(AC100_CLK32K_MUX_SHIFT) : 0);
+}
+
+static const struct clk_ops ac100_clk32k_ops = {
+	.prepare	= ac100_clk32k_prepare,
+	.unprepare	= ac100_clk32k_unprepare,
+	.is_prepared	= ac100_clk32k_is_prepared,
+	.recalc_rate	= ac100_clk32k_recalc_rate,
+	.determine_rate	= ac100_clk32k_determine_rate,
+	.get_parent	= ac100_clk32k_get_parent,
+	.set_parent	= ac100_clk32k_set_parent,
+	.set_rate	= ac100_clk32k_set_rate,
 };
 
+static int ac100_rtc_register_clks(struct ac100_rtc_dev *chip)
+{
+	struct device_node *np = chip->dev->of_node;
+	const char *parents[2] = {AC100_RTC_32K_NAME, AC100_ADDA_4M_NAME};
+	int i, ret;
+
+	chip->clk_data = devm_kzalloc(chip->dev, sizeof(*chip->clk_data) +
+						 sizeof(*chip->clk_data->hws) *
+						 AC100_CLK32K_NUM,
+						 GFP_KERNEL);
+	if (!chip->clk_data)
+		return -ENOMEM;
+
+	chip->rtc_32k_clk = clk_hw_register_fixed_rate(chip->dev,
+						       AC100_RTC_32K_NAME,
+						       NULL, 0,
+						       AC100_RTC_32K_RATE);
+	if (IS_ERR(chip->rtc_32k_clk)) {
+		ret = PTR_ERR(chip->rtc_32k_clk);
+		dev_err(chip->dev, "Failed to register RTC-32k clock: %d\n",
+			ret);
+		return ret;
+	}
+
+	/*
+	 * The ADDA 4 MHz clock is from the codec side of the AC100,
+	 * which is likely a different power domain. However, boards
+	 * always have both sides powered on, so it is impossible to
+	 * test this.
+	 */
+	chip->adda_4M_clk = clk_hw_register_fixed_rate(chip->dev,
+						       AC100_ADDA_4M_NAME,
+						       NULL, 0,
+						       AC100_ADDA_4M_RATE);
+	if (IS_ERR(chip->adda_4M_clk)) {
+		ret = PTR_ERR(chip->adda_4M_clk);
+		dev_err(chip->dev, "Failed to register ADDA-4M clock: %d\n",
+			ret);
+		goto err_unregister_rtc_32k;
+	}
+
+	for (i = 0; i < AC100_CLK32K_NUM; i++) {
+		struct ac100_clk32k *clk = &chip->clks[i];
+		struct clk_init_data init = {
+			.name = ac100_clk32k_names[i],
+			.ops = &ac100_clk32k_ops,
+			.parent_names = parents,
+			.num_parents = ARRAY_SIZE(parents),
+			.flags = 0,
+		};
+
+		clk->regmap = chip->regmap;
+		clk->offset = AC100_CLK32K_OUT_CTRL1 + i;
+		clk->hw.init = &init;
+
+		ret = devm_clk_hw_register(chip->dev, &clk->hw);
+		if (ret) {
+			dev_err(chip->dev, "Failed to register clk '%s': %d\n",
+				init.name, ret);
+			goto err_unregister_adda_4M;
+		}
+
+		chip->clk_data->hws[i] = &clk->hw;
+	}
+
+	chip->clk_data->num = i;
+	ret = of_clk_add_hw_provider(np, of_clk_hw_onecell_get, chip->clk_data);
+	if (ret)
+		goto err_unregister_adda_4M;
+
+	return 0;
+
+err_unregister_adda_4M:
+	clk_unregister_fixed_rate(chip->adda_4M_clk->clk);
+err_unregister_rtc_32k:
+	clk_unregister_fixed_rate(chip->rtc_32k_clk->clk);
+
+	return ret;
+}
+
+static void ac100_rtc_unregister_clks(struct ac100_rtc_dev *chip)
+{
+	of_clk_del_provider(chip->dev->of_node);
+	clk_unregister_fixed_rate(chip->adda_4M_clk->clk);
+	clk_unregister_fixed_rate(chip->rtc_32k_clk->clk);
+}
+
+/**
+ * RTC related bits
+ */
 static int ac100_rtc_get_time(struct device *dev, struct rtc_time *rtc_tm)
 {
 	struct ac100_rtc_dev *chip = dev_get_drvdata(dev);
@@ -347,13 +652,27 @@ static int ac100_rtc_probe(struct platform_device *pdev)
 		return PTR_ERR(chip->rtc);
 	}
 
+	ret = ac100_rtc_register_clks(chip);
+	if (ret)
+		return ret;
+
 	dev_info(&pdev->dev, "RTC enabled\n");
 
 	return 0;
 }
 
+static int ac100_rtc_remove(struct platform_device *pdev)
+{
+	struct ac100_rtc_dev *chip = platform_get_drvdata(pdev);
+
+	ac100_rtc_unregister_clks(chip);
+
+	return 0;
+}
+
 static struct platform_driver ac100_rtc_driver = {
 	.probe		= ac100_rtc_probe,
+	.remove		= ac100_rtc_remove,
 	.driver		= {
 		.name		= "ac100-rtc",
 	},
-- 
2.8.1

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

* [PATCH v3 6/8] ARM: dts: sun9i: a80-optimus: Add device node for AC100
  2016-06-20  2:52 [PATCH v3 0/8] mfd: ac100: Add support for X-Powers AC100 audio codec / RTC combo IC Chen-Yu Tsai
                   ` (4 preceding siblings ...)
  2016-06-20  2:52 ` [PATCH v3 5/8] rtc: ac100: Add clk output support Chen-Yu Tsai
@ 2016-06-20  2:52 ` Chen-Yu Tsai
  2016-06-20  2:52 ` [PATCH v3 7/8] ARM: dts: sun9i: cubieboard4: " Chen-Yu Tsai
  2016-06-20  2:52 ` [PATCH v3 8/8] ARM: dts: sun9i: Switch to the AC100 RTC clock outputs for osc32k Chen-Yu Tsai
  7 siblings, 0 replies; 20+ messages in thread
From: Chen-Yu Tsai @ 2016-06-20  2:52 UTC (permalink / raw)
  To: Mark Brown, Lee Jones, Alessandro Zummo, Alexandre Belloni,
	Rob Herring, Pawel Moll, Mark Rutland, Ian Campbell, Kumar Gala,
	Maxime Ripard, Michael Turquette, Stephen Boyd
  Cc: Chen-Yu Tsai, rtc-linux, linux-kernel, devicetree,
	linux-arm-kernel, linux-clk

Signed-off-by: Chen-Yu Tsai <wens@csie.org>
---
Changes since v2: none
Changes since v1: none
---
 arch/arm/boot/dts/sun9i-a80-optimus.dts | 21 +++++++++++++++++++++
 1 file changed, 21 insertions(+)

diff --git a/arch/arm/boot/dts/sun9i-a80-optimus.dts b/arch/arm/boot/dts/sun9i-a80-optimus.dts
index 7fd22e888602..3b013dc5fef1 100644
--- a/arch/arm/boot/dts/sun9i-a80-optimus.dts
+++ b/arch/arm/boot/dts/sun9i-a80-optimus.dts
@@ -322,6 +322,27 @@
 			};
 		};
 	};
+
+	ac100: codec@e89 {
+		compatible = "x-powers,ac100";
+		reg = <0xe89>;
+
+		ac100_codec: codec {
+			compatible = "x-powers,ac100-codec";
+			interrupt-parent = <&r_pio>;
+			interrupts = <0 9 IRQ_TYPE_LEVEL_LOW>; /* PL9 */
+		};
+
+		ac100_rtc: rtc {
+			compatible = "x-powers,ac100-rtc";
+			interrupt-parent = <&nmi_intc>;
+			interrupts = <0 IRQ_TYPE_LEVEL_LOW>;
+			#clock-cells = <1>;
+			clock-output-names = "cko1_rtc",
+					     "cko2_rtc",
+					     "cko3_rtc";
+		};
+	};
 };
 
 #include "axp809.dtsi"
-- 
2.8.1

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

* [PATCH v3 7/8] ARM: dts: sun9i: cubieboard4: Add device node for AC100
  2016-06-20  2:52 [PATCH v3 0/8] mfd: ac100: Add support for X-Powers AC100 audio codec / RTC combo IC Chen-Yu Tsai
                   ` (5 preceding siblings ...)
  2016-06-20  2:52 ` [PATCH v3 6/8] ARM: dts: sun9i: a80-optimus: Add device node for AC100 Chen-Yu Tsai
@ 2016-06-20  2:52 ` Chen-Yu Tsai
  2016-06-20  2:52 ` [PATCH v3 8/8] ARM: dts: sun9i: Switch to the AC100 RTC clock outputs for osc32k Chen-Yu Tsai
  7 siblings, 0 replies; 20+ messages in thread
From: Chen-Yu Tsai @ 2016-06-20  2:52 UTC (permalink / raw)
  To: Mark Brown, Lee Jones, Alessandro Zummo, Alexandre Belloni,
	Rob Herring, Pawel Moll, Mark Rutland, Ian Campbell, Kumar Gala,
	Maxime Ripard, Michael Turquette, Stephen Boyd
  Cc: Chen-Yu Tsai, rtc-linux, linux-kernel, devicetree,
	linux-arm-kernel, linux-clk

Signed-off-by: Chen-Yu Tsai <wens@csie.org>
---
Changes since v2: none
Changes since v1: none
---
 arch/arm/boot/dts/sun9i-a80-cubieboard4.dts | 21 +++++++++++++++++++++
 1 file changed, 21 insertions(+)

diff --git a/arch/arm/boot/dts/sun9i-a80-cubieboard4.dts b/arch/arm/boot/dts/sun9i-a80-cubieboard4.dts
index 1526b41c70f1..65f4f32f89ad 100644
--- a/arch/arm/boot/dts/sun9i-a80-cubieboard4.dts
+++ b/arch/arm/boot/dts/sun9i-a80-cubieboard4.dts
@@ -250,6 +250,27 @@
 			};
 		};
 	};
+
+	ac100: codec@e89 {
+		compatible = "x-powers,ac100";
+		reg = <0xe89>;
+
+		ac100_codec: codec {
+			compatible = "x-powers,ac100-codec";
+			interrupt-parent = <&r_pio>;
+			interrupts = <0 9 IRQ_TYPE_LEVEL_LOW>; /* PL9 */
+		};
+
+		ac100_rtc: rtc {
+			compatible = "x-powers,ac100-rtc";
+			interrupt-parent = <&nmi_intc>;
+			interrupts = <0 IRQ_TYPE_LEVEL_LOW>;
+			#clock-cells = <1>;
+			clock-output-names = "cko1_rtc",
+					     "cko2_rtc",
+					     "cko3_rtc";
+		};
+	};
 };
 
 #include "axp809.dtsi"
-- 
2.8.1

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

* [PATCH v3 8/8] ARM: dts: sun9i: Switch to the AC100 RTC clock outputs for osc32k
  2016-06-20  2:52 [PATCH v3 0/8] mfd: ac100: Add support for X-Powers AC100 audio codec / RTC combo IC Chen-Yu Tsai
                   ` (6 preceding siblings ...)
  2016-06-20  2:52 ` [PATCH v3 7/8] ARM: dts: sun9i: cubieboard4: " Chen-Yu Tsai
@ 2016-06-20  2:52 ` Chen-Yu Tsai
  7 siblings, 0 replies; 20+ messages in thread
From: Chen-Yu Tsai @ 2016-06-20  2:52 UTC (permalink / raw)
  To: Mark Brown, Lee Jones, Alessandro Zummo, Alexandre Belloni,
	Rob Herring, Pawel Moll, Mark Rutland, Ian Campbell, Kumar Gala,
	Maxime Ripard, Michael Turquette, Stephen Boyd
  Cc: Chen-Yu Tsai, rtc-linux, linux-kernel, devicetree,
	linux-arm-kernel, linux-clk

The 32.768 kHz clock inside the A80 SoC is fed from an external source,
typically the AC100 RTC module.

Make the osc32k placeholder a fixed-factor clock so board dts files can
specify its source.

Signed-off-by: Chen-Yu Tsai <wens@csie.org>
---
Changes since v2: none
Changes since v1: none
---
 arch/arm/boot/dts/sun9i-a80-cubieboard4.dts | 5 +++++
 arch/arm/boot/dts/sun9i-a80-optimus.dts     | 5 +++++
 arch/arm/boot/dts/sun9i-a80.dtsi            | 9 +++------
 3 files changed, 13 insertions(+), 6 deletions(-)

diff --git a/arch/arm/boot/dts/sun9i-a80-cubieboard4.dts b/arch/arm/boot/dts/sun9i-a80-cubieboard4.dts
index 65f4f32f89ad..b6299a9c14e3 100644
--- a/arch/arm/boot/dts/sun9i-a80-cubieboard4.dts
+++ b/arch/arm/boot/dts/sun9i-a80-cubieboard4.dts
@@ -103,6 +103,11 @@
 	allwinner,drive = <SUN4I_PINCTRL_40_MA>;
 };
 
+&osc32k {
+	/* osc32k input is from AC100 */
+	clocks = <&ac100_rtc 0>;
+};
+
 &pio {
 	led_pins_cubieboard4: led-pins@0 {
 		allwinner,pins = "PH6", "PH17";
diff --git a/arch/arm/boot/dts/sun9i-a80-optimus.dts b/arch/arm/boot/dts/sun9i-a80-optimus.dts
index 3b013dc5fef1..2f079cbd2025 100644
--- a/arch/arm/boot/dts/sun9i-a80-optimus.dts
+++ b/arch/arm/boot/dts/sun9i-a80-optimus.dts
@@ -152,6 +152,11 @@
 	status = "okay";
 };
 
+&osc32k {
+	/* osc32k input is from AC100 */
+	clocks = <&ac100_rtc 0>;
+};
+
 &pio {
 	led_pins_optimus: led-pins@0 {
 		allwinner,pins = "PH0", "PH1";
diff --git a/arch/arm/boot/dts/sun9i-a80.dtsi b/arch/arm/boot/dts/sun9i-a80.dtsi
index f68b3242b33a..dd11115ec087 100644
--- a/arch/arm/boot/dts/sun9i-a80.dtsi
+++ b/arch/arm/boot/dts/sun9i-a80.dtsi
@@ -148,15 +148,12 @@
 
 		/*
 		 * The 32k clock is from an external source, normally the
-		 * AC100 codec/RTC chip. This clock is by default enabled
-		 * and clocked at 32768 Hz, from the oscillator connected
-		 * to the AC100. It is configurable, but no such driver or
-		 * bindings exist yet.
+		 * AC100 codec/RTC chip. This serves as a placeholder for
+		 * board dts files to specify the source.
 		 */
 		osc32k: osc32k_clk {
 			#clock-cells = <0>;
-			compatible = "fixed-clock";
-			clock-frequency = <32768>;
+			compatible = "fixed-factor-clock";
 			clock-output-names = "osc32k";
 		};
 
-- 
2.8.1

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

* Re: [PATCH v3 2/8] mfd: ac100: Add device tree bindings for X-Powers AC100 codec/RTC combo IC
  2016-06-20  2:52 ` [PATCH v3 2/8] mfd: ac100: Add device tree bindings for X-Powers AC100 codec/RTC combo IC Chen-Yu Tsai
@ 2016-06-21 13:14   ` Rob Herring
  2016-06-22  4:16     ` Chen-Yu Tsai
  0 siblings, 1 reply; 20+ messages in thread
From: Rob Herring @ 2016-06-21 13:14 UTC (permalink / raw)
  To: Chen-Yu Tsai
  Cc: Mark Brown, Lee Jones, Alessandro Zummo, Alexandre Belloni,
	Pawel Moll, Mark Rutland, Ian Campbell, Kumar Gala,
	Maxime Ripard, Michael Turquette, Stephen Boyd, rtc-linux,
	linux-kernel, devicetree, linux-arm-kernel, linux-clk

On Mon, Jun 20, 2016 at 10:52:12AM +0800, Chen-Yu Tsai wrote:
> Signed-off-by: Chen-Yu Tsai <wens@csie.org>
> ---
> Changes since v2:
> 
>   - Fix interrupt line for ac100_codec in provided example.
> 
> ---
>  Documentation/devicetree/bindings/mfd/ac100.txt | 42 +++++++++++++++++++++++++
>  1 file changed, 42 insertions(+)
>  create mode 100644 Documentation/devicetree/bindings/mfd/ac100.txt
> 
> diff --git a/Documentation/devicetree/bindings/mfd/ac100.txt b/Documentation/devicetree/bindings/mfd/ac100.txt
> new file mode 100644
> index 000000000000..a793954bb952
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/mfd/ac100.txt
> @@ -0,0 +1,42 @@
> +X-Powers AC100 Codec/RTC IC device tree bindings
> +
> +AC100 is a audio codec and RTC subsystem combo IC. The 2 parts are
> +separated, including power supplies and interrupt lines, but share
> +a common register address space and host interface.
> +
> +Required properties:
> +- compatible: "x-powers,ac100"
> +- reg: The I2C slave address or RSB hardware address for the chip
> +- sub-nodes:
> +  - codec
> +    - compatible: "x-powers,ac100-codec"
> +    - interrupt-parent: The parent interrupt controller
> +    - interrupts: SoC NMI / GPIO interrupt connected to the IRQ_AUDIO pin
> +  - rtc
> +    - compatible: "x-powers,ac100-rtc"
> +    - interrupt-parent: The parent interrupt controller
> +    - interrupts: SoC NMI / GPIO interrupt connected to the IRQ_RTC pin
> +    - #clock-cells: shall be 1
> +    - clock-output-names: "cko1_rtc", "cko2_rtc", "cko3_rtc"
> +    - see clock/clock-bindings.txt for common clock bindings
> +
> +Example:
> +
> +ac100: codec@e89 {
> +	compatible = "x-powers,ac100";
> +	reg = <0xe89>;
> +
> +	ac100_codec {

Use generic node names and no underscores:

codec {

> +		compatible = "x-powers,ac100-codec";
> +		interrupt-parent = <&r_pio>;
> +		interrupts = <0 9 IRQ_TYPE_LEVEL_LOW>; /* PL9 */
> +	};
> +
> +	ac100_rtc {

rtc {

> +		compatible = "x-powers,ac100-rtc";
> +		interrupt-parent = <&nmi_intc>;
> +		interrupts = <0 IRQ_TYPE_LEVEL_LOW>;
> +		#clock-cells = <1>;
> +		clock-output-names = "cko1_rtc", "cko2_rtc", "cko3_rtc";
> +	};
> +};
> -- 
> 2.8.1
> 

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

* Re: [PATCH v3 2/8] mfd: ac100: Add device tree bindings for X-Powers AC100 codec/RTC combo IC
  2016-06-21 13:14   ` Rob Herring
@ 2016-06-22  4:16     ` Chen-Yu Tsai
  0 siblings, 0 replies; 20+ messages in thread
From: Chen-Yu Tsai @ 2016-06-22  4:16 UTC (permalink / raw)
  To: Rob Herring
  Cc: Chen-Yu Tsai, Mark Brown, Lee Jones, Alessandro Zummo,
	Alexandre Belloni, Pawel Moll, Mark Rutland, Ian Campbell,
	Kumar Gala, Maxime Ripard, Michael Turquette, Stephen Boyd,
	rtc-linux, linux-kernel, devicetree, linux-arm-kernel, linux-clk

On Tue, Jun 21, 2016 at 9:14 PM, Rob Herring <robh@kernel.org> wrote:
> On Mon, Jun 20, 2016 at 10:52:12AM +0800, Chen-Yu Tsai wrote:
>> Signed-off-by: Chen-Yu Tsai <wens@csie.org>
>> ---
>> Changes since v2:
>>
>>   - Fix interrupt line for ac100_codec in provided example.
>>
>> ---
>>  Documentation/devicetree/bindings/mfd/ac100.txt | 42 +++++++++++++++++++++++++
>>  1 file changed, 42 insertions(+)
>>  create mode 100644 Documentation/devicetree/bindings/mfd/ac100.txt
>>
>> diff --git a/Documentation/devicetree/bindings/mfd/ac100.txt b/Documentation/devicetree/bindings/mfd/ac100.txt
>> new file mode 100644
>> index 000000000000..a793954bb952
>> --- /dev/null
>> +++ b/Documentation/devicetree/bindings/mfd/ac100.txt
>> @@ -0,0 +1,42 @@
>> +X-Powers AC100 Codec/RTC IC device tree bindings
>> +
>> +AC100 is a audio codec and RTC subsystem combo IC. The 2 parts are
>> +separated, including power supplies and interrupt lines, but share
>> +a common register address space and host interface.
>> +
>> +Required properties:
>> +- compatible: "x-powers,ac100"
>> +- reg: The I2C slave address or RSB hardware address for the chip
>> +- sub-nodes:
>> +  - codec
>> +    - compatible: "x-powers,ac100-codec"
>> +    - interrupt-parent: The parent interrupt controller
>> +    - interrupts: SoC NMI / GPIO interrupt connected to the IRQ_AUDIO pin
>> +  - rtc
>> +    - compatible: "x-powers,ac100-rtc"
>> +    - interrupt-parent: The parent interrupt controller
>> +    - interrupts: SoC NMI / GPIO interrupt connected to the IRQ_RTC pin
>> +    - #clock-cells: shall be 1
>> +    - clock-output-names: "cko1_rtc", "cko2_rtc", "cko3_rtc"
>> +    - see clock/clock-bindings.txt for common clock bindings
>> +
>> +Example:
>> +
>> +ac100: codec@e89 {
>> +     compatible = "x-powers,ac100";
>> +     reg = <0xe89>;
>> +
>> +     ac100_codec {
>
> Use generic node names and no underscores:
>
> codec {

Right. I intended to add them as labels, not change the node names.

Thanks
ChenYu

>
>> +             compatible = "x-powers,ac100-codec";
>> +             interrupt-parent = <&r_pio>;
>> +             interrupts = <0 9 IRQ_TYPE_LEVEL_LOW>; /* PL9 */
>> +     };
>> +
>> +     ac100_rtc {
>
> rtc {
>
>> +             compatible = "x-powers,ac100-rtc";
>> +             interrupt-parent = <&nmi_intc>;
>> +             interrupts = <0 IRQ_TYPE_LEVEL_LOW>;
>> +             #clock-cells = <1>;
>> +             clock-output-names = "cko1_rtc", "cko2_rtc", "cko3_rtc";
>> +     };
>> +};
>> --
>> 2.8.1
>>

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

* Re: [PATCH v3 5/8] rtc: ac100: Add clk output support
  2016-06-20  2:52 ` [PATCH v3 5/8] rtc: ac100: Add clk output support Chen-Yu Tsai
@ 2016-06-22 10:02   ` Maxime Ripard
  2016-06-22 10:11     ` Chen-Yu Tsai
  2016-06-26  0:45   ` Alexandre Belloni
  1 sibling, 1 reply; 20+ messages in thread
From: Maxime Ripard @ 2016-06-22 10:02 UTC (permalink / raw)
  To: Chen-Yu Tsai
  Cc: Mark Brown, Lee Jones, Alessandro Zummo, Alexandre Belloni,
	Rob Herring, Pawel Moll, Mark Rutland, Ian Campbell, Kumar Gala,
	Michael Turquette, Stephen Boyd, rtc-linux, linux-kernel,
	devicetree, linux-arm-kernel, linux-clk

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

Hi,

On Mon, Jun 20, 2016 at 10:52:15AM +0800, Chen-Yu Tsai wrote:
> +	/*
> +	 * The ADDA 4 MHz clock is from the codec side of the AC100,
> +	 * which is likely a different power domain. However, boards
> +	 * always have both sides powered on, so it is impossible to
> +	 * test this.
> +	 */

If that ADDA clock is exposed by the codec, why are you putting it in
the RTC?

Thanks,
Maxime

-- 
Maxime Ripard, Free Electrons
Embedded Linux, Kernel and Android engineering
http://free-electrons.com

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

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

* Re: [PATCH v3 5/8] rtc: ac100: Add clk output support
  2016-06-22 10:02   ` Maxime Ripard
@ 2016-06-22 10:11     ` Chen-Yu Tsai
  2016-06-27 19:23       ` Maxime Ripard
  0 siblings, 1 reply; 20+ messages in thread
From: Chen-Yu Tsai @ 2016-06-22 10:11 UTC (permalink / raw)
  To: Maxime Ripard
  Cc: Chen-Yu Tsai, Mark Brown, Lee Jones, Alessandro Zummo,
	Alexandre Belloni, Rob Herring, Pawel Moll, Mark Rutland,
	Ian Campbell, Kumar Gala, Michael Turquette, Stephen Boyd,
	rtc-linux, linux-kernel, devicetree, linux-arm-kernel, linux-clk

On Wed, Jun 22, 2016 at 6:02 PM, Maxime Ripard
<maxime.ripard@free-electrons.com> wrote:
> Hi,
>
> On Mon, Jun 20, 2016 at 10:52:15AM +0800, Chen-Yu Tsai wrote:
>> +     /*
>> +      * The ADDA 4 MHz clock is from the codec side of the AC100,
>> +      * which is likely a different power domain. However, boards
>> +      * always have both sides powered on, so it is impossible to
>> +      * test this.
>> +      */
>
> If that ADDA clock is exposed by the codec, why are you putting it in
> the RTC?

The thing is it's not entirely clear that it's from the codec side.
I'm just inferring this from the name. (I'll make the comment clearer.)
The codec parts of the datasheet don't mention this clock at all.

Allwinner's SDK puts all the clocks under the RTC module. And the
are always on, so I can't really turn off the codec and see what
happens. That and I don't have an oscilloscope or logic analyzer.

Regards
ChenYu

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

* Re: [PATCH v3 4/8] rtc: ac100: Add RTC driver for X-Powers AC100
  2016-06-20  2:52 ` [PATCH v3 4/8] rtc: ac100: Add RTC driver for X-Powers AC100 Chen-Yu Tsai
@ 2016-06-26  0:30   ` Alexandre Belloni
  2016-06-26 14:54     ` Chen-Yu Tsai
  2016-06-26  1:02   ` Alexandre Belloni
  1 sibling, 1 reply; 20+ messages in thread
From: Alexandre Belloni @ 2016-06-26  0:30 UTC (permalink / raw)
  To: Chen-Yu Tsai
  Cc: Mark Brown, Lee Jones, Alessandro Zummo, Rob Herring, Pawel Moll,
	Mark Rutland, Ian Campbell, Kumar Gala, Maxime Ripard,
	Michael Turquette, Stephen Boyd, rtc-linux, linux-kernel,
	devicetree, linux-arm-kernel, linux-clk

Hi,

A few comments, mostly about style.

On 20/06/2016 at 10:52:14 +0800, Chen-Yu Tsai wrote :
> +struct ac100_rtc_dev {
> +	struct rtc_device *rtc;
> +	struct device *dev;
> +	struct regmap *regmap;
> +	struct mutex mutex;

I don't think that mutex is needed. Instead, you can take rtc->ops_lock
from the interrupt handler.

> +	int irq;
> +	unsigned long alarm;
> +};
> +
> +static int ac100_rtc_get_time(struct device *dev, struct rtc_time *rtc_tm)
> +{
> +	struct ac100_rtc_dev *chip = dev_get_drvdata(dev);
> +	struct regmap *regmap = chip->regmap;
> +	u16 reg[7];
> +	int ret;
> +
> +	ret = regmap_bulk_read(regmap, AC100_RTC_SEC, reg, 7);
> +	if (ret)
> +		return ret;
> +
> +	rtc_tm->tm_sec  = bcd2bin(reg[0] & AC100_RTC_SEC_MASK);
> +	rtc_tm->tm_min  = bcd2bin(reg[1] & AC100_RTC_MIN_MASK);
> +	rtc_tm->tm_hour = bcd2bin(reg[2] & AC100_RTC_HOU_MASK);
> +	rtc_tm->tm_wday = bcd2bin(reg[3] & AC100_RTC_WEE_MASK);
> +	rtc_tm->tm_mday = bcd2bin(reg[4] & AC100_RTC_DAY_MASK);
> +	rtc_tm->tm_mon  = bcd2bin(reg[5] & AC100_RTC_MON_MASK);
> +	rtc_tm->tm_year = bcd2bin(reg[6] & AC100_RTC_YEA_MASK);
> +
> +	rtc_tm->tm_mon  -= 1;

I would put the - 1 inline with the first tm_mon assignment.

> +
> +	/*
> +	 * switch from (data_year->min)-relative offset to
> +	 * a (1900)-relative one
> +	 */
> +	rtc_tm->tm_year += AC100_YEAR_OFF;

Unless you feel the comment is absolutely necessary, I'd also put that
with the first tm_year assignment.

BTW, is that RTC aware that 0 is actually 1970? And so 2000 (30) is not
a leap year but 2016 is? I'd say that this is not the case, seeing
AC100_RTC_YEA_LEAP but it is worth checking.

Is this bit (AC100_RTC_YEA_LEAP) updated by the rtc? IF that is not the
case, the time will have to be set at least once between first of
January and 28th of February of leap years else it will fail...

> +
> +	return rtc_valid_tm(rtc_tm);
> +}
> +
> +static int ac100_rtc_set_time(struct device *dev, struct rtc_time *rtc_tm)
> +{
> +	struct ac100_rtc_dev *chip = dev_get_drvdata(dev);
> +	struct regmap *regmap = chip->regmap;
> +	int year;
> +	u16 reg[8];
> +
> +	/* our RTC has a limited year range... */
> +	year = rtc_tm->tm_year + 1900;
> +	if (year < AC100_YEAR_MIN || year > AC100_YEAR_MAX) {
> +		dev_err(dev, "rtc only supports year in range %d - %d\n",
> +			AC100_YEAR_MIN, AC100_YEAR_MAX);
> +		return -EINVAL;
> +	}
> +

What about:

year = rtc_tm->tm_year - AC100_YEAR_OFF
if (year < 0 || year > (AC100_YEAR_MAX - 1900))

It allows to reuse year for the reg[6] assignment. IT is a simple
suggestion, maybe the compiler is smarter than I am ;).

> +	/* correct offsets */
> +	rtc_tm->tm_year -= AC100_YEAR_OFF;
> +	rtc_tm->tm_mon += 1;
> +

Those could also got inline with their respective reg[] assignment


> +	/* convert to BCD */
> +	reg[0] = bin2bcd(rtc_tm->tm_sec)  & AC100_RTC_SEC_MASK;
> +	reg[1] = bin2bcd(rtc_tm->tm_min)  & AC100_RTC_MIN_MASK;
> +	reg[2] = bin2bcd(rtc_tm->tm_hour) & AC100_RTC_HOU_MASK;
> +	reg[3] = bin2bcd(rtc_tm->tm_wday) & AC100_RTC_WEE_MASK;
> +	reg[4] = bin2bcd(rtc_tm->tm_mday) & AC100_RTC_DAY_MASK;
> +	reg[5] = bin2bcd(rtc_tm->tm_mon)  & AC100_RTC_MON_MASK;
> +	reg[6] = bin2bcd(rtc_tm->tm_year) & AC100_RTC_YEA_MASK;
> +	/* trigger write */
> +	reg[7] = AC100_RTC_UPD_TRIGGER;
> +
> +	/* Is it a leap year? */
> +	if (is_leap_year(year))
> +		reg[6] |= AC100_RTC_YEA_LEAP;
> +
> +	return regmap_bulk_write(regmap, AC100_RTC_SEC, reg, 8);
> +}
> +
> +

[...]

> +	alrm_tm->tm_sec  = bcd2bin(reg[0] & AC100_ALM_SEC_MASK);
> +	alrm_tm->tm_min  = bcd2bin(reg[1] & AC100_ALM_MIN_MASK);
> +	alrm_tm->tm_hour = bcd2bin(reg[2] & AC100_ALM_HOU_MASK);
> +	alrm_tm->tm_wday = bcd2bin(reg[3] & AC100_ALM_WEE_MASK);
> +	alrm_tm->tm_mday = bcd2bin(reg[4] & AC100_ALM_DAY_MASK);
> +	alrm_tm->tm_mon  = bcd2bin(reg[5] & AC100_ALM_MON_MASK);
> +	alrm_tm->tm_year = bcd2bin(reg[6] & AC100_ALM_YEA_MASK);
> +
> +	alrm_tm->tm_mon  -= 1;
> +
> +	/*
> +	 * switch from (data_year->min)-relative offset to
> +	 * a (1900)-relative one
> +	 */
> +	alrm_tm->tm_year += AC100_YEAR_OFF;
> +

Well, same comments as in ac100_rtc_get_time()


> +out:
> +	mutex_unlock(&chip->mutex);
> +	return ret;
> +}
> +
> +static int ac100_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
> +{
> +	struct ac100_rtc_dev *chip = dev_get_drvdata(dev);
> +	struct regmap *regmap = chip->regmap;
> +	struct rtc_time *alrm_tm = &alrm->time;
> +	u16 reg[8];
> +	int year;
> +	int ret;
> +
> +	/* our alarm has a limited year range... */
> +	year = alrm_tm->tm_year + 1900;
> +	if (year < AC100_YEAR_MIN || year > AC100_YEAR_MAX) {
> +		dev_err(dev, "alarm only supports year in range %d - %d\n",
> +			AC100_YEAR_MIN, AC100_YEAR_MAX);
> +		return -EINVAL;
> +	}
> +
> +	/* correct offsets */
> +	alrm_tm->tm_year -= AC100_YEAR_OFF;
> +	alrm_tm->tm_mon += 1;
> +

Same comment as ac100_rtc_set_time()

> +	/* convert to BCD */
> +	reg[0] = (bin2bcd(alrm_tm->tm_sec)  & AC100_ALM_SEC_MASK) |
> +			AC100_ALM_ENABLE_FLAG;
> +	reg[1] = (bin2bcd(alrm_tm->tm_min)  & AC100_ALM_MIN_MASK) |
> +			AC100_ALM_ENABLE_FLAG;
> +	reg[2] = (bin2bcd(alrm_tm->tm_hour) & AC100_ALM_HOU_MASK) |
> +			AC100_ALM_ENABLE_FLAG;
> +	/* Do not enable weekday alarm */
> +	reg[3] = bin2bcd(alrm_tm->tm_wday) & AC100_ALM_WEE_MASK;
> +	reg[4] = (bin2bcd(alrm_tm->tm_mday) & AC100_ALM_DAY_MASK) |
> +			AC100_ALM_ENABLE_FLAG;
> +	reg[5] = (bin2bcd(alrm_tm->tm_mon)  & AC100_ALM_MON_MASK) |
> +			AC100_ALM_ENABLE_FLAG;
> +	reg[6] = (bin2bcd(alrm_tm->tm_year) & AC100_ALM_YEA_MASK) |
> +			AC100_ALM_ENABLE_FLAG;
> +	/* trigger write */
> +	reg[7] = AC100_ALM_UPD_TRIGGER;
> +
> +	mutex_lock(&chip->mutex);
> +
> +	ret = regmap_bulk_write(regmap, AC100_ALM_SEC, reg, 8);
> +	if (ret)
> +		goto out;
> +
> +	ret = _ac100_rtc_alarm_irq_enable(chip, alrm->enabled);
> +
> +out:
> +	mutex_unlock(&chip->mutex);
> +	return ret;
> +}
> +

-- 
Alexandre Belloni, Free Electrons
Embedded Linux, Kernel and Android engineering
http://free-electrons.com

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

* Re: [PATCH v3 5/8] rtc: ac100: Add clk output support
  2016-06-20  2:52 ` [PATCH v3 5/8] rtc: ac100: Add clk output support Chen-Yu Tsai
  2016-06-22 10:02   ` Maxime Ripard
@ 2016-06-26  0:45   ` Alexandre Belloni
  2016-06-26 14:58     ` Chen-Yu Tsai
  1 sibling, 1 reply; 20+ messages in thread
From: Alexandre Belloni @ 2016-06-26  0:45 UTC (permalink / raw)
  To: Chen-Yu Tsai
  Cc: Mark Brown, Lee Jones, Alessandro Zummo, Rob Herring, Pawel Moll,
	Mark Rutland, Ian Campbell, Kumar Gala, Maxime Ripard,
	Michael Turquette, Stephen Boyd, rtc-linux, linux-kernel,
	devicetree, linux-arm-kernel, linux-clk

On 20/06/2016 at 10:52:15 +0800, Chen-Yu Tsai wrote :
> +struct ac100_clk32k {
> +	struct clk_hw hw;
> +	struct regmap *regmap;
> +	u8 offset;
> +};
> +
> +#define to_ac100_clk32k(_hw) container_of(_hw, struct ac100_clk32k, hw)
> +
> +#define AC100_RTC_32K_NAME	"ac100-rtc-32k"
> +#define AC100_RTC_32K_RATE	32768
> +#define AC100_ADDA_4M_NAME	"ac100-adda-4M"
> +#define AC100_ADDA_4M_RATE	4000000
> +#define AC100_CLK32K_NUM	3
> +
> +static const char * const ac100_clk32k_names[] = {
> +	"ac100-clk32k-ap",
> +	"ac100-clk32k-bb",
> +	"ac100-clk32k-md",
> +};
> +

Well, naming things is hard but I don't feel ac100_clk32k and
ac100-clk32k are good prefixes for those clocks as they are actually
dividing a 32KHz or 4MHz clock (one configuration out of 128 is 32KHz).

Else, I don't have any objection.

-- 
Alexandre Belloni, Free Electrons
Embedded Linux, Kernel and Android engineering
http://free-electrons.com

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

* Re: [PATCH v3 4/8] rtc: ac100: Add RTC driver for X-Powers AC100
  2016-06-20  2:52 ` [PATCH v3 4/8] rtc: ac100: Add RTC driver for X-Powers AC100 Chen-Yu Tsai
  2016-06-26  0:30   ` Alexandre Belloni
@ 2016-06-26  1:02   ` Alexandre Belloni
  1 sibling, 0 replies; 20+ messages in thread
From: Alexandre Belloni @ 2016-06-26  1:02 UTC (permalink / raw)
  To: Chen-Yu Tsai
  Cc: Mark Brown, Lee Jones, Alessandro Zummo, Rob Herring, Pawel Moll,
	Mark Rutland, Ian Campbell, Kumar Gala, Maxime Ripard,
	Michael Turquette, Stephen Boyd, rtc-linux, linux-kernel,
	devicetree, linux-arm-kernel, linux-clk

On 20/06/2016 at 10:52:14 +0800, Chen-Yu Tsai wrote :
> +static int ac100_rtc_probe(struct platform_device *pdev)
> +{
> +	struct ac100_dev *ac100 = dev_get_drvdata(pdev->dev.parent);
> +	struct ac100_rtc_dev *chip;
> +	int ret;
> +
> +	chip = devm_kzalloc(&pdev->dev, sizeof(*chip), GFP_KERNEL);
> +	platform_set_drvdata(pdev, chip);
> +	chip->dev = &pdev->dev;
> +	chip->regmap = ac100->regmap;
> +	mutex_init(&chip->mutex);
> +
> +	chip->irq = of_irq_get(pdev->dev.of_node, 0);

Forgot that one, platform_get_irq() is probably more common but I don't
care that much. I think you can then avoid including of.h and of_irq.h.

> +	if (chip->irq < 0) {
> +		dev_err(&pdev->dev, "No IRQ resource\n");
> +		return chip->irq;
> +	}
> +

-- 
Alexandre Belloni, Free Electrons
Embedded Linux, Kernel and Android engineering
http://free-electrons.com

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

* Re: [PATCH v3 4/8] rtc: ac100: Add RTC driver for X-Powers AC100
  2016-06-26  0:30   ` Alexandre Belloni
@ 2016-06-26 14:54     ` Chen-Yu Tsai
  0 siblings, 0 replies; 20+ messages in thread
From: Chen-Yu Tsai @ 2016-06-26 14:54 UTC (permalink / raw)
  To: Alexandre Belloni
  Cc: Chen-Yu Tsai, Mark Brown, Lee Jones, Alessandro Zummo,
	Rob Herring, Pawel Moll, Mark Rutland, Ian Campbell, Kumar Gala,
	Maxime Ripard, Michael Turquette, Stephen Boyd, rtc-linux,
	linux-kernel, devicetree, linux-arm-kernel, linux-clk

On Sun, Jun 26, 2016 at 8:30 AM, Alexandre Belloni
<alexandre.belloni@free-electrons.com> wrote:
> Hi,
>
> A few comments, mostly about style.
>
> On 20/06/2016 at 10:52:14 +0800, Chen-Yu Tsai wrote :
>> +struct ac100_rtc_dev {
>> +     struct rtc_device *rtc;
>> +     struct device *dev;
>> +     struct regmap *regmap;
>> +     struct mutex mutex;
>
> I don't think that mutex is needed. Instead, you can take rtc->ops_lock
> from the interrupt handler.

OK. I didn't think using the lock from the rtc device was a good idea.

>
>> +     int irq;
>> +     unsigned long alarm;
>> +};
>> +
>> +static int ac100_rtc_get_time(struct device *dev, struct rtc_time *rtc_tm)
>> +{
>> +     struct ac100_rtc_dev *chip = dev_get_drvdata(dev);
>> +     struct regmap *regmap = chip->regmap;
>> +     u16 reg[7];
>> +     int ret;
>> +
>> +     ret = regmap_bulk_read(regmap, AC100_RTC_SEC, reg, 7);
>> +     if (ret)
>> +             return ret;
>> +
>> +     rtc_tm->tm_sec  = bcd2bin(reg[0] & AC100_RTC_SEC_MASK);
>> +     rtc_tm->tm_min  = bcd2bin(reg[1] & AC100_RTC_MIN_MASK);
>> +     rtc_tm->tm_hour = bcd2bin(reg[2] & AC100_RTC_HOU_MASK);
>> +     rtc_tm->tm_wday = bcd2bin(reg[3] & AC100_RTC_WEE_MASK);
>> +     rtc_tm->tm_mday = bcd2bin(reg[4] & AC100_RTC_DAY_MASK);
>> +     rtc_tm->tm_mon  = bcd2bin(reg[5] & AC100_RTC_MON_MASK);
>> +     rtc_tm->tm_year = bcd2bin(reg[6] & AC100_RTC_YEA_MASK);
>> +
>> +     rtc_tm->tm_mon  -= 1;
>
> I would put the - 1 inline with the first tm_mon assignment.

OK

>
>> +
>> +     /*
>> +      * switch from (data_year->min)-relative offset to
>> +      * a (1900)-relative one
>> +      */
>> +     rtc_tm->tm_year += AC100_YEAR_OFF;
>
> Unless you feel the comment is absolutely necessary, I'd also put that
> with the first tm_year assignment.
>
> BTW, is that RTC aware that 0 is actually 1970? And so 2000 (30) is not
> a leap year but 2016 is? I'd say that this is not the case, seeing
> AC100_RTC_YEA_LEAP but it is worth checking.
>
> Is this bit (AC100_RTC_YEA_LEAP) updated by the rtc? IF that is not the
> case, the time will have to be set at least once between first of
> January and 28th of February of leap years else it will fail...

Unfortunately it is not. The datasheet explicitly said the RTC does not
update the leap year bit. So yes, the RTC will have to be updated at
least once a year...

>> +
>> +     return rtc_valid_tm(rtc_tm);
>> +}
>> +
>> +static int ac100_rtc_set_time(struct device *dev, struct rtc_time *rtc_tm)
>> +{
>> +     struct ac100_rtc_dev *chip = dev_get_drvdata(dev);
>> +     struct regmap *regmap = chip->regmap;
>> +     int year;
>> +     u16 reg[8];
>> +
>> +     /* our RTC has a limited year range... */
>> +     year = rtc_tm->tm_year + 1900;
>> +     if (year < AC100_YEAR_MIN || year > AC100_YEAR_MAX) {
>> +             dev_err(dev, "rtc only supports year in range %d - %d\n",
>> +                     AC100_YEAR_MIN, AC100_YEAR_MAX);
>> +             return -EINVAL;
>> +     }
>> +
>
> What about:
>
> year = rtc_tm->tm_year - AC100_YEAR_OFF
> if (year < 0 || year > (AC100_YEAR_MAX - 1900))
>
> It allows to reuse year for the reg[6] assignment. IT is a simple
> suggestion, maybe the compiler is smarter than I am ;).
>
>> +     /* correct offsets */
>> +     rtc_tm->tm_year -= AC100_YEAR_OFF;
>> +     rtc_tm->tm_mon += 1;
>> +
>
> Those could also got inline with their respective reg[] assignment

OK. I'll see if I can still fit everything in a single line, to keep
the nice table-like formatting.

>
>
>> +     /* convert to BCD */
>> +     reg[0] = bin2bcd(rtc_tm->tm_sec)  & AC100_RTC_SEC_MASK;
>> +     reg[1] = bin2bcd(rtc_tm->tm_min)  & AC100_RTC_MIN_MASK;
>> +     reg[2] = bin2bcd(rtc_tm->tm_hour) & AC100_RTC_HOU_MASK;
>> +     reg[3] = bin2bcd(rtc_tm->tm_wday) & AC100_RTC_WEE_MASK;
>> +     reg[4] = bin2bcd(rtc_tm->tm_mday) & AC100_RTC_DAY_MASK;
>> +     reg[5] = bin2bcd(rtc_tm->tm_mon)  & AC100_RTC_MON_MASK;
>> +     reg[6] = bin2bcd(rtc_tm->tm_year) & AC100_RTC_YEA_MASK;
>> +     /* trigger write */
>> +     reg[7] = AC100_RTC_UPD_TRIGGER;
>> +
>> +     /* Is it a leap year? */
>> +     if (is_leap_year(year))
>> +             reg[6] |= AC100_RTC_YEA_LEAP;
>> +
>> +     return regmap_bulk_write(regmap, AC100_RTC_SEC, reg, 8);
>> +}
>> +
>> +
>
> [...]
>
>> +     alrm_tm->tm_sec  = bcd2bin(reg[0] & AC100_ALM_SEC_MASK);
>> +     alrm_tm->tm_min  = bcd2bin(reg[1] & AC100_ALM_MIN_MASK);
>> +     alrm_tm->tm_hour = bcd2bin(reg[2] & AC100_ALM_HOU_MASK);
>> +     alrm_tm->tm_wday = bcd2bin(reg[3] & AC100_ALM_WEE_MASK);
>> +     alrm_tm->tm_mday = bcd2bin(reg[4] & AC100_ALM_DAY_MASK);
>> +     alrm_tm->tm_mon  = bcd2bin(reg[5] & AC100_ALM_MON_MASK);
>> +     alrm_tm->tm_year = bcd2bin(reg[6] & AC100_ALM_YEA_MASK);
>> +
>> +     alrm_tm->tm_mon  -= 1;
>> +
>> +     /*
>> +      * switch from (data_year->min)-relative offset to
>> +      * a (1900)-relative one
>> +      */
>> +     alrm_tm->tm_year += AC100_YEAR_OFF;
>> +
>
> Well, same comments as in ac100_rtc_get_time()
>
>
>> +out:
>> +     mutex_unlock(&chip->mutex);
>> +     return ret;
>> +}
>> +
>> +static int ac100_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
>> +{
>> +     struct ac100_rtc_dev *chip = dev_get_drvdata(dev);
>> +     struct regmap *regmap = chip->regmap;
>> +     struct rtc_time *alrm_tm = &alrm->time;
>> +     u16 reg[8];
>> +     int year;
>> +     int ret;
>> +
>> +     /* our alarm has a limited year range... */
>> +     year = alrm_tm->tm_year + 1900;
>> +     if (year < AC100_YEAR_MIN || year > AC100_YEAR_MAX) {
>> +             dev_err(dev, "alarm only supports year in range %d - %d\n",
>> +                     AC100_YEAR_MIN, AC100_YEAR_MAX);
>> +             return -EINVAL;
>> +     }
>> +
>> +     /* correct offsets */
>> +     alrm_tm->tm_year -= AC100_YEAR_OFF;
>> +     alrm_tm->tm_mon += 1;
>> +
>
> Same comment as ac100_rtc_set_time()
>
>> +     /* convert to BCD */
>> +     reg[0] = (bin2bcd(alrm_tm->tm_sec)  & AC100_ALM_SEC_MASK) |
>> +                     AC100_ALM_ENABLE_FLAG;
>> +     reg[1] = (bin2bcd(alrm_tm->tm_min)  & AC100_ALM_MIN_MASK) |
>> +                     AC100_ALM_ENABLE_FLAG;
>> +     reg[2] = (bin2bcd(alrm_tm->tm_hour) & AC100_ALM_HOU_MASK) |
>> +                     AC100_ALM_ENABLE_FLAG;
>> +     /* Do not enable weekday alarm */
>> +     reg[3] = bin2bcd(alrm_tm->tm_wday) & AC100_ALM_WEE_MASK;
>> +     reg[4] = (bin2bcd(alrm_tm->tm_mday) & AC100_ALM_DAY_MASK) |
>> +                     AC100_ALM_ENABLE_FLAG;
>> +     reg[5] = (bin2bcd(alrm_tm->tm_mon)  & AC100_ALM_MON_MASK) |
>> +                     AC100_ALM_ENABLE_FLAG;
>> +     reg[6] = (bin2bcd(alrm_tm->tm_year) & AC100_ALM_YEA_MASK) |
>> +                     AC100_ALM_ENABLE_FLAG;
>> +     /* trigger write */
>> +     reg[7] = AC100_ALM_UPD_TRIGGER;
>> +
>> +     mutex_lock(&chip->mutex);
>> +
>> +     ret = regmap_bulk_write(regmap, AC100_ALM_SEC, reg, 8);
>> +     if (ret)
>> +             goto out;
>> +
>> +     ret = _ac100_rtc_alarm_irq_enable(chip, alrm->enabled);
>> +
>> +out:
>> +     mutex_unlock(&chip->mutex);
>> +     return ret;
>> +}
>> +

Thanks for the review!

ChenYu

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

* Re: [PATCH v3 5/8] rtc: ac100: Add clk output support
  2016-06-26  0:45   ` Alexandre Belloni
@ 2016-06-26 14:58     ` Chen-Yu Tsai
  0 siblings, 0 replies; 20+ messages in thread
From: Chen-Yu Tsai @ 2016-06-26 14:58 UTC (permalink / raw)
  To: Alexandre Belloni
  Cc: Chen-Yu Tsai, Mark Brown, Lee Jones, Alessandro Zummo,
	Rob Herring, Pawel Moll, Mark Rutland, Ian Campbell, Kumar Gala,
	Maxime Ripard, Michael Turquette, Stephen Boyd, rtc-linux,
	linux-kernel, devicetree, linux-arm-kernel, linux-clk

On Sun, Jun 26, 2016 at 8:45 AM, Alexandre Belloni
<alexandre.belloni@free-electrons.com> wrote:
> On 20/06/2016 at 10:52:15 +0800, Chen-Yu Tsai wrote :
>> +struct ac100_clk32k {
>> +     struct clk_hw hw;
>> +     struct regmap *regmap;
>> +     u8 offset;
>> +};
>> +
>> +#define to_ac100_clk32k(_hw) container_of(_hw, struct ac100_clk32k, hw)
>> +
>> +#define AC100_RTC_32K_NAME   "ac100-rtc-32k"
>> +#define AC100_RTC_32K_RATE   32768
>> +#define AC100_ADDA_4M_NAME   "ac100-adda-4M"
>> +#define AC100_ADDA_4M_RATE   4000000
>> +#define AC100_CLK32K_NUM     3
>> +
>> +static const char * const ac100_clk32k_names[] = {
>> +     "ac100-clk32k-ap",
>> +     "ac100-clk32k-bb",
>> +     "ac100-clk32k-md",
>> +};
>> +
>
> Well, naming things is hard but I don't feel ac100_clk32k and
> ac100-clk32k are good prefixes for those clocks as they are actually
> dividing a 32KHz or 4MHz clock (one configuration out of 128 is 32KHz).

I agree it's a bit misleading. There are 2 names used throughout the
datasheet: 1) CKOn_RTC for the pin names, and 2) CLK32Kxx for the
register names and block diagram.

I'll switch to the pin names, since this is probably what is shown on
board schematics.

> Else, I don't have any objection.

Thanks!
ChenYu

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

* Re: [PATCH v3 5/8] rtc: ac100: Add clk output support
  2016-06-22 10:11     ` Chen-Yu Tsai
@ 2016-06-27 19:23       ` Maxime Ripard
  2016-06-28  2:27         ` Chen-Yu Tsai
  0 siblings, 1 reply; 20+ messages in thread
From: Maxime Ripard @ 2016-06-27 19:23 UTC (permalink / raw)
  To: Chen-Yu Tsai
  Cc: Mark Brown, Lee Jones, Alessandro Zummo, Alexandre Belloni,
	Rob Herring, Pawel Moll, Mark Rutland, Ian Campbell, Kumar Gala,
	Michael Turquette, Stephen Boyd, rtc-linux, linux-kernel,
	devicetree, linux-arm-kernel, linux-clk

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

On Wed, Jun 22, 2016 at 06:11:55PM +0800, Chen-Yu Tsai wrote:
> On Wed, Jun 22, 2016 at 6:02 PM, Maxime Ripard
> <maxime.ripard@free-electrons.com> wrote:
> > Hi,
> >
> > On Mon, Jun 20, 2016 at 10:52:15AM +0800, Chen-Yu Tsai wrote:
> >> +     /*
> >> +      * The ADDA 4 MHz clock is from the codec side of the AC100,
> >> +      * which is likely a different power domain. However, boards
> >> +      * always have both sides powered on, so it is impossible to
> >> +      * test this.
> >> +      */
> >
> > If that ADDA clock is exposed by the codec, why are you putting it in
> > the RTC?
> 
> The thing is it's not entirely clear that it's from the codec side.
> I'm just inferring this from the name. (I'll make the comment clearer.)
> The codec parts of the datasheet don't mention this clock at all.
> 
> Allwinner's SDK puts all the clocks under the RTC module. And the
> are always on, so I can't really turn off the codec and see what
> happens. That and I don't have an oscilloscope or logic analyzer.

Why not just create a separate clock driver then?

Thanks,
Maxime

-- 
Maxime Ripard, Free Electrons
Embedded Linux, Kernel and Android engineering
http://free-electrons.com

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

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

* Re: [PATCH v3 5/8] rtc: ac100: Add clk output support
  2016-06-27 19:23       ` Maxime Ripard
@ 2016-06-28  2:27         ` Chen-Yu Tsai
  0 siblings, 0 replies; 20+ messages in thread
From: Chen-Yu Tsai @ 2016-06-28  2:27 UTC (permalink / raw)
  To: Maxime Ripard
  Cc: Chen-Yu Tsai, Mark Brown, Lee Jones, Alessandro Zummo,
	Alexandre Belloni, Rob Herring, Pawel Moll, Mark Rutland,
	Ian Campbell, Kumar Gala, Michael Turquette, Stephen Boyd,
	rtc-linux, linux-kernel, devicetree, linux-arm-kernel, linux-clk

On Tue, Jun 28, 2016 at 3:23 AM, Maxime Ripard
<maxime.ripard@free-electrons.com> wrote:
> On Wed, Jun 22, 2016 at 06:11:55PM +0800, Chen-Yu Tsai wrote:
>> On Wed, Jun 22, 2016 at 6:02 PM, Maxime Ripard
>> <maxime.ripard@free-electrons.com> wrote:
>> > Hi,
>> >
>> > On Mon, Jun 20, 2016 at 10:52:15AM +0800, Chen-Yu Tsai wrote:
>> >> +     /*
>> >> +      * The ADDA 4 MHz clock is from the codec side of the AC100,
>> >> +      * which is likely a different power domain. However, boards
>> >> +      * always have both sides powered on, so it is impossible to
>> >> +      * test this.
>> >> +      */
>> >
>> > If that ADDA clock is exposed by the codec, why are you putting it in
>> > the RTC?
>>
>> The thing is it's not entirely clear that it's from the codec side.
>> I'm just inferring this from the name. (I'll make the comment clearer.)
>> The codec parts of the datasheet don't mention this clock at all.
>>
>> Allwinner's SDK puts all the clocks under the RTC module. And the
>> are always on, so I can't really turn off the codec and see what
>> happens. That and I don't have an oscilloscope or logic analyzer.
>
> Why not just create a separate clock driver then?

That would mean a separate device node as well. I'd like to keep
the bindings close to how the hardware is organized.

I can move the ADDA clock over to the codec side.

ChenYu

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

end of thread, other threads:[~2016-06-28  2:28 UTC | newest]

Thread overview: 20+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2016-06-20  2:52 [PATCH v3 0/8] mfd: ac100: Add support for X-Powers AC100 audio codec / RTC combo IC Chen-Yu Tsai
2016-06-20  2:52 ` [PATCH v3 1/8] regmap: Support bulk writes for devices without raw formatting Chen-Yu Tsai
2016-06-20  2:52 ` [PATCH v3 2/8] mfd: ac100: Add device tree bindings for X-Powers AC100 codec/RTC combo IC Chen-Yu Tsai
2016-06-21 13:14   ` Rob Herring
2016-06-22  4:16     ` Chen-Yu Tsai
2016-06-20  2:52 ` [PATCH v3 3/8] mfd: ac100: Add driver for X-Powers AC100 audio codec / RTC " Chen-Yu Tsai
2016-06-20  2:52 ` [PATCH v3 4/8] rtc: ac100: Add RTC driver for X-Powers AC100 Chen-Yu Tsai
2016-06-26  0:30   ` Alexandre Belloni
2016-06-26 14:54     ` Chen-Yu Tsai
2016-06-26  1:02   ` Alexandre Belloni
2016-06-20  2:52 ` [PATCH v3 5/8] rtc: ac100: Add clk output support Chen-Yu Tsai
2016-06-22 10:02   ` Maxime Ripard
2016-06-22 10:11     ` Chen-Yu Tsai
2016-06-27 19:23       ` Maxime Ripard
2016-06-28  2:27         ` Chen-Yu Tsai
2016-06-26  0:45   ` Alexandre Belloni
2016-06-26 14:58     ` Chen-Yu Tsai
2016-06-20  2:52 ` [PATCH v3 6/8] ARM: dts: sun9i: a80-optimus: Add device node for AC100 Chen-Yu Tsai
2016-06-20  2:52 ` [PATCH v3 7/8] ARM: dts: sun9i: cubieboard4: " Chen-Yu Tsai
2016-06-20  2:52 ` [PATCH v3 8/8] ARM: dts: sun9i: Switch to the AC100 RTC clock outputs for osc32k Chen-Yu Tsai

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).