Linux-ARM-Kernel Archive on lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v2] ASoC: atmel_ssc_dai: Remove wrong spinlock usage
From: Gregory CLEMENT @ 2019-09-18 10:03 UTC (permalink / raw)
  To: Codrin Ciubotariu, Liam Girdwood, Mark Brown, alsa-devel,
	linux-kernel
  Cc: Alexandre Belloni, Ludovic Desroches, linux-arm-kernel,
	Gregory CLEMENT

A potential bug was reported in the email "[BUG] atmel_ssc_dai: a
possible sleep-in-atomic bug in atmel_ssc_shutdown"[1]

Indeed in the function atmel_ssc_shutdown() free_irq() was called in a
critical section protected by spinlock.

However this spinlock is only used in atmel_ssc_shutdown() and
atmel_ssc_startup() functions. After further analysis, it occurred that
the call to these function are already protected by mutex used on the
calling functions.

Then we can remove the spinlock which will fix this bug as a side
effect. Thanks to this patch the following message disappears:

"BUG: sleeping function called from invalid context at
kernel/locking/mutex.c:909"

[1]: https://www.spinics.net/lists/alsa-devel/msg71286.html

Reviewed-by: Alexandre Belloni <alexandre.belloni@bootlin.com>
Signed-off-by: Gregory CLEMENT <gregory.clement@bootlin.com>
---

Changelog:

v1 -> v2:

   - Removed the spinlock from the atmel_ssc_info struct
   - Added the Reviewed-by flag form Alex

 sound/soc/atmel/atmel_ssc_dai.c | 12 ++----------
 sound/soc/atmel/atmel_ssc_dai.h |  1 -
 2 files changed, 2 insertions(+), 11 deletions(-)

diff --git a/sound/soc/atmel/atmel_ssc_dai.c b/sound/soc/atmel/atmel_ssc_dai.c
index 6f89483ac88c..786b48ae4905 100644
--- a/sound/soc/atmel/atmel_ssc_dai.c
+++ b/sound/soc/atmel/atmel_ssc_dai.c
@@ -116,19 +116,16 @@ static struct atmel_pcm_dma_params ssc_dma_params[NUM_SSC_DEVICES][2] = {
 static struct atmel_ssc_info ssc_info[NUM_SSC_DEVICES] = {
 	{
 	.name		= "ssc0",
-	.lock		= __SPIN_LOCK_UNLOCKED(ssc_info[0].lock),
 	.dir_mask	= SSC_DIR_MASK_UNUSED,
 	.initialized	= 0,
 	},
 	{
 	.name		= "ssc1",
-	.lock		= __SPIN_LOCK_UNLOCKED(ssc_info[1].lock),
 	.dir_mask	= SSC_DIR_MASK_UNUSED,
 	.initialized	= 0,
 	},
 	{
 	.name		= "ssc2",
-	.lock		= __SPIN_LOCK_UNLOCKED(ssc_info[2].lock),
 	.dir_mask	= SSC_DIR_MASK_UNUSED,
 	.initialized	= 0,
 	},
@@ -317,13 +314,10 @@ static int atmel_ssc_startup(struct snd_pcm_substream *substream,
 
 	snd_soc_dai_set_dma_data(dai, substream, dma_params);
 
-	spin_lock_irq(&ssc_p->lock);
-	if (ssc_p->dir_mask & dir_mask) {
-		spin_unlock_irq(&ssc_p->lock);
+	if (ssc_p->dir_mask & dir_mask)
 		return -EBUSY;
-	}
+
 	ssc_p->dir_mask |= dir_mask;
-	spin_unlock_irq(&ssc_p->lock);
 
 	return 0;
 }
@@ -355,7 +349,6 @@ static void atmel_ssc_shutdown(struct snd_pcm_substream *substream,
 
 	dir_mask = 1 << dir;
 
-	spin_lock_irq(&ssc_p->lock);
 	ssc_p->dir_mask &= ~dir_mask;
 	if (!ssc_p->dir_mask) {
 		if (ssc_p->initialized) {
@@ -369,7 +362,6 @@ static void atmel_ssc_shutdown(struct snd_pcm_substream *substream,
 		ssc_p->cmr_div = ssc_p->tcmr_period = ssc_p->rcmr_period = 0;
 		ssc_p->forced_divider = 0;
 	}
-	spin_unlock_irq(&ssc_p->lock);
 
 	/* Shutdown the SSC clock. */
 	pr_debug("atmel_ssc_dai: Stopping clock\n");
diff --git a/sound/soc/atmel/atmel_ssc_dai.h b/sound/soc/atmel/atmel_ssc_dai.h
index ae764cb541c7..3470b966e449 100644
--- a/sound/soc/atmel/atmel_ssc_dai.h
+++ b/sound/soc/atmel/atmel_ssc_dai.h
@@ -93,7 +93,6 @@ struct atmel_ssc_state {
 struct atmel_ssc_info {
 	char *name;
 	struct ssc_device *ssc;
-	spinlock_t lock;	/* lock for dir_mask */
 	unsigned short dir_mask;	/* 0=unused, 1=playback, 2=capture */
 	unsigned short initialized;	/* true if SSC has been initialized */
 	unsigned short daifmt;
-- 
2.23.0


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply related

* [PATCH] mfd: mt6360: add pmic mt6360 driver
From: Gene Chen @ 2019-09-18 10:15 UTC (permalink / raw)
  To: lee.jones, matthias.bgg
  Cc: gene_chen, linux-kernel, linux-mediatek, Wilma.Wu,
	linux-arm-kernel, shufan_lee

From: Gene Chen <gene_chen@richtek.com>

Add mfd driver for mt6360 pmic chip include
Battery Charger/USB_PD/Flash LED/RGB LED/LDO/Buck

Signed-off-by: Gene Chen <gene_chen@richtek.com
---
 drivers/mfd/Kconfig                |  12 +
 drivers/mfd/Makefile               |   1 +
 drivers/mfd/mt6360-core.c          | 463 +++++++++++++++++++++++++++++++++++++
 include/linux/mfd/mt6360-private.h | 279 ++++++++++++++++++++++
 include/linux/mfd/mt6360.h         |  33 +++
 5 files changed, 788 insertions(+)
 create mode 100644 drivers/mfd/mt6360-core.c
 create mode 100644 include/linux/mfd/mt6360-private.h
 create mode 100644 include/linux/mfd/mt6360.h

diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig
index f129f96..a422c76 100644
--- a/drivers/mfd/Kconfig
+++ b/drivers/mfd/Kconfig
@@ -862,6 +862,18 @@ config MFD_MAX8998
 	  additional drivers must be enabled in order to use the functionality
 	  of the device.
 
+config MFD_MT6360
+	tristate "Mediatek MT6360 SubPMIC"
+	select MFD_CORE
+	select REGMAP_I2C
+	select REGMAP_IRQ
+	depends on I2C
+	help
+	  Say Y here to enable MT6360 PMU/PMIC/LDO functional support.
+	  PMU part include charger, flashlight, rgb led
+	  PMIC part include 2-channel BUCKs and 2-channel LDOs
+	  LDO part include 4-channel LDOs
+
 config MFD_MT6397
 	tristate "MediaTek MT6397 PMIC Support"
 	select MFD_CORE
diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile
index f026ada..77a8f0b 100644
--- a/drivers/mfd/Makefile
+++ b/drivers/mfd/Makefile
@@ -241,6 +241,7 @@ obj-$(CONFIG_INTEL_SOC_PMIC)	+= intel-soc-pmic.o
 obj-$(CONFIG_INTEL_SOC_PMIC_BXTWC)	+= intel_soc_pmic_bxtwc.o
 obj-$(CONFIG_INTEL_SOC_PMIC_CHTWC)	+= intel_soc_pmic_chtwc.o
 obj-$(CONFIG_INTEL_SOC_PMIC_CHTDC_TI)	+= intel_soc_pmic_chtdc_ti.o
+obj-$(CONFIG_MFD_MT6360)	+= mt6360-core.o
 obj-$(CONFIG_MFD_MT6397)	+= mt6397-core.o
 
 obj-$(CONFIG_MFD_ALTERA_A10SR)	+= altera-a10sr.o
diff --git a/drivers/mfd/mt6360-core.c b/drivers/mfd/mt6360-core.c
new file mode 100644
index 0000000..d3580618
--- /dev/null
+++ b/drivers/mfd/mt6360-core.c
@@ -0,0 +1,463 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2019 MediaTek Inc.
+ */
+
+#include <linux/i2c.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/mfd/core.h>
+#include <linux/module.h>
+#include <linux/of_irq.h>
+#include <linux/of_platform.h>
+#include <linux/version.h>
+
+#include <linux/mfd/mt6360.h>
+#include <linux/mfd/mt6360-private.h>
+
+/* reg 0 -> 0 ~ 7 */
+#define MT6360_CHG_TREG_EVT		(4)
+#define MT6360_CHG_AICR_EVT		(5)
+#define MT6360_CHG_MIVR_EVT		(6)
+#define MT6360_PWR_RDY_EVT		(7)
+/* REG 1 -> 8 ~ 15 */
+#define MT6360_CHG_BATSYSUV_EVT		(9)
+#define MT6360_FLED_CHG_VINOVP_EVT	(11)
+#define MT6360_CHG_VSYSUV_EVT		(12)
+#define MT6360_CHG_VSYSOV_EVT		(13)
+#define MT6360_CHG_VBATOV_EVT		(14)
+#define MT6360_CHG_VBUSOV_EVT		(15)
+/* REG 2 -> 16 ~ 23 */
+/* REG 3 -> 24 ~ 31 */
+#define MT6360_WD_PMU_DET		(25)
+#define MT6360_WD_PMU_DONE		(26)
+#define MT6360_CHG_TMRI			(27)
+#define MT6360_CHG_ADPBADI		(29)
+#define MT6360_CHG_RVPI			(30)
+#define MT6360_OTPI			(31)
+/* REG 4 -> 32 ~ 39 */
+#define MT6360_CHG_AICCMEASL		(32)
+#define MT6360_CHGDET_DONEI		(34)
+#define MT6360_WDTMRI			(35)
+#define MT6360_SSFINISHI		(36)
+#define MT6360_CHG_RECHGI		(37)
+#define MT6360_CHG_TERMI		(38)
+#define MT6360_CHG_IEOCI		(39)
+/* REG 5 -> 40 ~ 47 */
+#define MT6360_PUMPX_DONEI		(40)
+#define MT6360_BAT_OVP_ADC_EVT		(41)
+#define MT6360_TYPEC_OTP_EVT		(42)
+#define MT6360_ADC_WAKEUP_EVT		(43)
+#define MT6360_ADC_DONEI		(44)
+#define MT6360_BST_BATUVI		(45)
+#define MT6360_BST_VBUSOVI		(46)
+#define MT6360_BST_OLPI			(47)
+/* REG 6 -> 48 ~ 55 */
+#define MT6360_ATTACH_I			(48)
+#define MT6360_DETACH_I			(49)
+#define MT6360_QC30_STPDONE		(51)
+#define MT6360_QC_VBUSDET_DONE		(52)
+#define MT6360_HVDCP_DET		(53)
+#define MT6360_CHGDETI			(54)
+#define MT6360_DCDTI			(55)
+/* REG 7 -> 56 ~ 63 */
+#define MT6360_FOD_DONE_EVT		(56)
+#define MT6360_FOD_OV_EVT		(57)
+#define MT6360_CHRDET_UVP_EVT		(58)
+#define MT6360_CHRDET_OVP_EVT		(59)
+#define MT6360_CHRDET_EXT_EVT		(60)
+#define MT6360_FOD_LR_EVT		(61)
+#define MT6360_FOD_HR_EVT		(62)
+#define MT6360_FOD_DISCHG_FAIL_EVT	(63)
+/* REG 8 -> 64 ~ 71 */
+#define MT6360_USBID_EVT		(64)
+#define MT6360_APWDTRST_EVT		(65)
+#define MT6360_EN_EVT			(66)
+#define MT6360_QONB_RST_EVT		(67)
+#define MT6360_MRSTB_EVT		(68)
+#define MT6360_OTP_EVT			(69)
+#define MT6360_VDDAOV_EVT		(70)
+#define MT6360_SYSUV_EVT		(71)
+/* REG 9 -> 72 ~ 79 */
+#define MT6360_FLED_STRBPIN_EVT		(72)
+#define MT6360_FLED_TORPIN_EVT		(73)
+#define MT6360_FLED_TX_EVT		(74)
+#define MT6360_FLED_LVF_EVT		(75)
+#define MT6360_FLED2_SHORT_EVT		(78)
+#define MT6360_FLED1_SHORT_EVT		(79)
+/* REG 10 -> 80 ~ 87 */
+#define MT6360_FLED2_STRB_EVT		(80)
+#define MT6360_FLED1_STRB_EVT		(81)
+#define MT6360_FLED2_STRB_TO_EVT	(82)
+#define MT6360_FLED1_STRB_TO_EVT	(83)
+#define MT6360_FLED2_TOR_EVT		(84)
+#define MT6360_FLED1_TOR_EVT		(85)
+/* REG 11 -> 88 ~ 95 */
+/* REG 12 -> 96 ~ 103 */
+#define MT6360_BUCK1_PGB_EVT		(96)
+#define MT6360_BUCK1_OC_EVT		(100)
+#define MT6360_BUCK1_OV_EVT		(101)
+#define MT6360_BUCK1_UV_EVT		(102)
+/* REG 13 -> 104 ~ 111 */
+#define MT6360_BUCK2_PGB_EVT		(104)
+#define MT6360_BUCK2_OC_EVT		(108)
+#define MT6360_BUCK2_OV_EVT		(109)
+#define MT6360_BUCK2_UV_EVT		(110)
+/* REG 14 -> 112 ~ 119 */
+#define MT6360_LDO1_OC_EVT		(113)
+#define MT6360_LDO2_OC_EVT		(114)
+#define MT6360_LDO3_OC_EVT		(115)
+#define MT6360_LDO5_OC_EVT		(117)
+#define MT6360_LDO6_OC_EVT		(118)
+#define MT6360_LDO7_OC_EVT		(119)
+/* REG 15 -> 120 ~ 127 */
+#define MT6360_LDO1_PGB_EVT		(121)
+#define MT6360_LDO2_PGB_EVT		(122)
+#define MT6360_LDO3_PGB_EVT		(123)
+#define MT6360_LDO5_PGB_EVT		(125)
+#define MT6360_LDO6_PGB_EVT		(126)
+#define MT6360_LDO7_PGB_EVT		(127)
+
+#define MT6360_REGMAP_IRQ_REG(_irq_evt)		\
+	REGMAP_IRQ_REG(_irq_evt, (_irq_evt) / 8, BIT((_irq_evt) % 8))
+
+#define MT6360_MFD_CELL(_name)					\
+	{							\
+		.name = #_name,					\
+		.of_compatible = "mediatek," #_name,		\
+		.num_resources = ARRAY_SIZE(_name##_resources),	\
+		.resources = _name##_resources,			\
+	}
+
+static const struct regmap_irq mt6360_pmu_irqs[] =  {
+	MT6360_REGMAP_IRQ_REG(MT6360_CHG_TREG_EVT),
+	MT6360_REGMAP_IRQ_REG(MT6360_CHG_AICR_EVT),
+	MT6360_REGMAP_IRQ_REG(MT6360_CHG_MIVR_EVT),
+	MT6360_REGMAP_IRQ_REG(MT6360_PWR_RDY_EVT),
+	MT6360_REGMAP_IRQ_REG(MT6360_CHG_BATSYSUV_EVT),
+	MT6360_REGMAP_IRQ_REG(MT6360_FLED_CHG_VINOVP_EVT),
+	MT6360_REGMAP_IRQ_REG(MT6360_CHG_VSYSUV_EVT),
+	MT6360_REGMAP_IRQ_REG(MT6360_CHG_VSYSOV_EVT),
+	MT6360_REGMAP_IRQ_REG(MT6360_CHG_VBATOV_EVT),
+	MT6360_REGMAP_IRQ_REG(MT6360_CHG_VBUSOV_EVT),
+	MT6360_REGMAP_IRQ_REG(MT6360_WD_PMU_DET),
+	MT6360_REGMAP_IRQ_REG(MT6360_WD_PMU_DONE),
+	MT6360_REGMAP_IRQ_REG(MT6360_CHG_TMRI),
+	MT6360_REGMAP_IRQ_REG(MT6360_CHG_ADPBADI),
+	MT6360_REGMAP_IRQ_REG(MT6360_CHG_RVPI),
+	MT6360_REGMAP_IRQ_REG(MT6360_OTPI),
+	MT6360_REGMAP_IRQ_REG(MT6360_CHG_AICCMEASL),
+	MT6360_REGMAP_IRQ_REG(MT6360_CHGDET_DONEI),
+	MT6360_REGMAP_IRQ_REG(MT6360_WDTMRI),
+	MT6360_REGMAP_IRQ_REG(MT6360_SSFINISHI),
+	MT6360_REGMAP_IRQ_REG(MT6360_CHG_RECHGI),
+	MT6360_REGMAP_IRQ_REG(MT6360_CHG_TERMI),
+	MT6360_REGMAP_IRQ_REG(MT6360_CHG_IEOCI),
+	MT6360_REGMAP_IRQ_REG(MT6360_PUMPX_DONEI),
+	MT6360_REGMAP_IRQ_REG(MT6360_CHG_TREG_EVT),
+	MT6360_REGMAP_IRQ_REG(MT6360_BAT_OVP_ADC_EVT),
+	MT6360_REGMAP_IRQ_REG(MT6360_TYPEC_OTP_EVT),
+	MT6360_REGMAP_IRQ_REG(MT6360_ADC_WAKEUP_EVT),
+	MT6360_REGMAP_IRQ_REG(MT6360_ADC_DONEI),
+	MT6360_REGMAP_IRQ_REG(MT6360_BST_BATUVI),
+	MT6360_REGMAP_IRQ_REG(MT6360_BST_VBUSOVI),
+	MT6360_REGMAP_IRQ_REG(MT6360_BST_OLPI),
+	MT6360_REGMAP_IRQ_REG(MT6360_ATTACH_I),
+	MT6360_REGMAP_IRQ_REG(MT6360_DETACH_I),
+	MT6360_REGMAP_IRQ_REG(MT6360_QC30_STPDONE),
+	MT6360_REGMAP_IRQ_REG(MT6360_QC_VBUSDET_DONE),
+	MT6360_REGMAP_IRQ_REG(MT6360_HVDCP_DET),
+	MT6360_REGMAP_IRQ_REG(MT6360_CHGDETI),
+	MT6360_REGMAP_IRQ_REG(MT6360_DCDTI),
+	MT6360_REGMAP_IRQ_REG(MT6360_FOD_DONE_EVT),
+	MT6360_REGMAP_IRQ_REG(MT6360_FOD_OV_EVT),
+	MT6360_REGMAP_IRQ_REG(MT6360_CHRDET_UVP_EVT),
+	MT6360_REGMAP_IRQ_REG(MT6360_CHRDET_OVP_EVT),
+	MT6360_REGMAP_IRQ_REG(MT6360_CHRDET_EXT_EVT),
+	MT6360_REGMAP_IRQ_REG(MT6360_FOD_LR_EVT),
+	MT6360_REGMAP_IRQ_REG(MT6360_FOD_HR_EVT),
+	MT6360_REGMAP_IRQ_REG(MT6360_FOD_DISCHG_FAIL_EVT),
+	MT6360_REGMAP_IRQ_REG(MT6360_USBID_EVT),
+	MT6360_REGMAP_IRQ_REG(MT6360_APWDTRST_EVT),
+	MT6360_REGMAP_IRQ_REG(MT6360_EN_EVT),
+	MT6360_REGMAP_IRQ_REG(MT6360_QONB_RST_EVT),
+	MT6360_REGMAP_IRQ_REG(MT6360_MRSTB_EVT),
+	MT6360_REGMAP_IRQ_REG(MT6360_OTP_EVT),
+	MT6360_REGMAP_IRQ_REG(MT6360_VDDAOV_EVT),
+	MT6360_REGMAP_IRQ_REG(MT6360_SYSUV_EVT),
+	MT6360_REGMAP_IRQ_REG(MT6360_FLED_STRBPIN_EVT),
+	MT6360_REGMAP_IRQ_REG(MT6360_FLED_TORPIN_EVT),
+	MT6360_REGMAP_IRQ_REG(MT6360_FLED_TX_EVT),
+	MT6360_REGMAP_IRQ_REG(MT6360_FLED_LVF_EVT),
+	MT6360_REGMAP_IRQ_REG(MT6360_FLED2_SHORT_EVT),
+	MT6360_REGMAP_IRQ_REG(MT6360_FLED1_SHORT_EVT),
+	MT6360_REGMAP_IRQ_REG(MT6360_FLED2_STRB_EVT),
+	MT6360_REGMAP_IRQ_REG(MT6360_FLED1_STRB_EVT),
+	MT6360_REGMAP_IRQ_REG(MT6360_FLED2_STRB_TO_EVT),
+	MT6360_REGMAP_IRQ_REG(MT6360_FLED1_STRB_TO_EVT),
+	MT6360_REGMAP_IRQ_REG(MT6360_FLED2_TOR_EVT),
+	MT6360_REGMAP_IRQ_REG(MT6360_FLED1_TOR_EVT),
+	MT6360_REGMAP_IRQ_REG(MT6360_BUCK1_PGB_EVT),
+	MT6360_REGMAP_IRQ_REG(MT6360_BUCK1_OC_EVT),
+	MT6360_REGMAP_IRQ_REG(MT6360_BUCK1_OV_EVT),
+	MT6360_REGMAP_IRQ_REG(MT6360_BUCK1_UV_EVT),
+	MT6360_REGMAP_IRQ_REG(MT6360_BUCK2_PGB_EVT),
+	MT6360_REGMAP_IRQ_REG(MT6360_BUCK2_OC_EVT),
+	MT6360_REGMAP_IRQ_REG(MT6360_BUCK2_OV_EVT),
+	MT6360_REGMAP_IRQ_REG(MT6360_BUCK2_UV_EVT),
+	MT6360_REGMAP_IRQ_REG(MT6360_LDO1_OC_EVT),
+	MT6360_REGMAP_IRQ_REG(MT6360_LDO2_OC_EVT),
+	MT6360_REGMAP_IRQ_REG(MT6360_LDO3_OC_EVT),
+	MT6360_REGMAP_IRQ_REG(MT6360_LDO5_OC_EVT),
+	MT6360_REGMAP_IRQ_REG(MT6360_LDO6_OC_EVT),
+	MT6360_REGMAP_IRQ_REG(MT6360_LDO7_OC_EVT),
+	MT6360_REGMAP_IRQ_REG(MT6360_LDO1_PGB_EVT),
+	MT6360_REGMAP_IRQ_REG(MT6360_LDO2_PGB_EVT),
+	MT6360_REGMAP_IRQ_REG(MT6360_LDO3_PGB_EVT),
+	MT6360_REGMAP_IRQ_REG(MT6360_LDO5_PGB_EVT),
+	MT6360_REGMAP_IRQ_REG(MT6360_LDO6_PGB_EVT),
+	MT6360_REGMAP_IRQ_REG(MT6360_LDO7_PGB_EVT),
+};
+
+static int mt6360_pmu_handle_post_irq(void *irq_drv_data)
+{
+	struct mt6360_pmu_info *mpi = irq_drv_data;
+
+	return regmap_update_bits(mpi->regmap,
+		MT6360_PMU_IRQ_SET, MT6360_IRQ_RETRIG, MT6360_IRQ_RETRIG);
+}
+
+static const struct regmap_irq_chip mt6360_pmu_irq_chip = {
+	.irqs = mt6360_pmu_irqs,
+	.num_irqs = ARRAY_SIZE(mt6360_pmu_irqs),
+	.num_regs = MT6360_PMU_IRQ_REGNUM,
+	.mask_base = MT6360_PMU_CHG_MASK1,
+	.status_base = MT6360_PMU_CHG_IRQ1,
+	.ack_base = MT6360_PMU_CHG_IRQ1,
+	.init_ack_masked = true,
+	.use_ack = true,
+	.handle_post_irq = mt6360_pmu_handle_post_irq,
+};
+
+static const struct regmap_config mt6360_pmu_regmap_config = {
+	.reg_bits = 8,
+	.val_bits = 8,
+	.max_register = MT6360_PMU_MAXREG,
+};
+
+static const struct resource mt6360_adc_resources[] = {
+	DEFINE_RES_IRQ_NAMED(MT6360_ADC_DONEI, "adc_donei"),
+};
+
+static const struct resource mt6360_chg_resources[] = {
+	DEFINE_RES_IRQ_NAMED(MT6360_CHG_TREG_EVT, "chg_treg_evt"),
+	DEFINE_RES_IRQ_NAMED(MT6360_PWR_RDY_EVT, "pwr_rdy_evt"),
+	DEFINE_RES_IRQ_NAMED(MT6360_CHG_BATSYSUV_EVT, "chg_batsysuv_evt"),
+	DEFINE_RES_IRQ_NAMED(MT6360_CHG_VSYSUV_EVT, "chg_vsysuv_evt"),
+	DEFINE_RES_IRQ_NAMED(MT6360_CHG_VSYSOV_EVT, "chg_vsysov_evt"),
+	DEFINE_RES_IRQ_NAMED(MT6360_CHG_VBATOV_EVT, "chg_vbatov_evt"),
+	DEFINE_RES_IRQ_NAMED(MT6360_CHG_VBUSOV_EVT, "chg_vbusov_evt"),
+	DEFINE_RES_IRQ_NAMED(MT6360_CHG_AICCMEASL, "chg_aiccmeasl"),
+	DEFINE_RES_IRQ_NAMED(MT6360_WDTMRI, "wdtmri"),
+	DEFINE_RES_IRQ_NAMED(MT6360_CHG_RECHGI, "chg_rechgi"),
+	DEFINE_RES_IRQ_NAMED(MT6360_CHG_TERMI, "chg_termi"),
+	DEFINE_RES_IRQ_NAMED(MT6360_CHG_IEOCI, "chg_ieoci"),
+	DEFINE_RES_IRQ_NAMED(MT6360_PUMPX_DONEI, "pumpx_donei"),
+	DEFINE_RES_IRQ_NAMED(MT6360_ATTACH_I, "attach_i"),
+	DEFINE_RES_IRQ_NAMED(MT6360_CHRDET_EXT_EVT, "chrdet_ext_evt"),
+};
+
+static const struct resource mt6360_led_resources[] = {
+	DEFINE_RES_IRQ_NAMED(MT6360_FLED_CHG_VINOVP_EVT, "fled_chg_vinovp_evt"),
+	DEFINE_RES_IRQ_NAMED(MT6360_FLED_LVF_EVT, "fled_lvf_evt"),
+	DEFINE_RES_IRQ_NAMED(MT6360_FLED2_SHORT_EVT, "fled2_short_evt"),
+	DEFINE_RES_IRQ_NAMED(MT6360_FLED1_SHORT_EVT, "fled1_short_evt"),
+	DEFINE_RES_IRQ_NAMED(MT6360_FLED2_STRB_TO_EVT, "fled2_strb_to_evt"),
+	DEFINE_RES_IRQ_NAMED(MT6360_FLED1_STRB_TO_EVT, "fled1_strb_to_evt"),
+};
+
+static const struct resource mt6360_pmic_resources[] = {
+	DEFINE_RES_IRQ_NAMED(MT6360_BUCK1_PGB_EVT, "buck1_pgb_evt"),
+	DEFINE_RES_IRQ_NAMED(MT6360_BUCK1_OC_EVT, "buck1_oc_evt"),
+	DEFINE_RES_IRQ_NAMED(MT6360_BUCK1_OV_EVT, "buck1_ov_evt"),
+	DEFINE_RES_IRQ_NAMED(MT6360_BUCK1_UV_EVT, "buck1_uv_evt"),
+	DEFINE_RES_IRQ_NAMED(MT6360_BUCK2_PGB_EVT, "buck2_pgb_evt"),
+	DEFINE_RES_IRQ_NAMED(MT6360_BUCK2_OC_EVT, "buck2_oc_evt"),
+	DEFINE_RES_IRQ_NAMED(MT6360_BUCK2_OV_EVT, "buck2_ov_evt"),
+	DEFINE_RES_IRQ_NAMED(MT6360_BUCK2_UV_EVT, "buck2_uv_evt"),
+	DEFINE_RES_IRQ_NAMED(MT6360_LDO6_OC_EVT, "ldo6_oc_evt"),
+	DEFINE_RES_IRQ_NAMED(MT6360_LDO7_OC_EVT, "ldo7_oc_evt"),
+	DEFINE_RES_IRQ_NAMED(MT6360_LDO6_PGB_EVT, "ldo6_pgb_evt"),
+	DEFINE_RES_IRQ_NAMED(MT6360_LDO7_PGB_EVT, "ldo7_pgb_evt"),
+};
+
+static const struct resource mt6360_ldo_resources[] = {
+	DEFINE_RES_IRQ_NAMED(MT6360_LDO1_OC_EVT, "ldo1_oc_evt"),
+	DEFINE_RES_IRQ_NAMED(MT6360_LDO2_OC_EVT, "ldo2_oc_evt"),
+	DEFINE_RES_IRQ_NAMED(MT6360_LDO3_OC_EVT, "ldo3_oc_evt"),
+	DEFINE_RES_IRQ_NAMED(MT6360_LDO5_OC_EVT, "ldo5_oc_evt"),
+	DEFINE_RES_IRQ_NAMED(MT6360_LDO1_PGB_EVT, "ldo1_pgb_evt"),
+	DEFINE_RES_IRQ_NAMED(MT6360_LDO2_PGB_EVT, "ldo2_pgb_evt"),
+	DEFINE_RES_IRQ_NAMED(MT6360_LDO3_PGB_EVT, "ldo3_pgb_evt"),
+	DEFINE_RES_IRQ_NAMED(MT6360_LDO5_PGB_EVT, "ldo5_pgb_evt"),
+};
+
+static const struct mfd_cell mt6360_devs[] = {
+	MT6360_MFD_CELL(mt6360_adc),
+	MT6360_MFD_CELL(mt6360_chg),
+	MT6360_MFD_CELL(mt6360_led),
+	MT6360_MFD_CELL(mt6360_pmic),
+	MT6360_MFD_CELL(mt6360_ldo),
+	/* tcpc dev */
+	{
+		.name = "mt6360_tcpc",
+		.of_compatible = "mediatek,mt6360_tcpc",
+	},
+};
+
+static const unsigned short mt6360_slave_addr[MT6360_SLAVE_MAX] = {
+	MT6360_PMU_SLAVEID,
+	MT6360_PMIC_SLAVEID,
+	MT6360_LDO_SLAVEID,
+	MT6360_TCPC_SLAVEID,
+};
+
+static int mt6360_pmu_probe(struct i2c_client *client,
+			    const struct i2c_device_id *id)
+{
+	struct mt6360_pmu_info *mpi;
+	unsigned int reg_data = 0;
+	int i, ret;
+
+	mpi = devm_kzalloc(&client->dev, sizeof(*mpi), GFP_KERNEL);
+	if (!mpi)
+		return -ENOMEM;
+	mpi->dev = &client->dev;
+	i2c_set_clientdata(client, mpi);
+
+	/* regmap regiser */
+	mpi->regmap = devm_regmap_init_i2c(client, &mt6360_pmu_regmap_config);
+	if (IS_ERR(mpi->regmap)) {
+		dev_err(&client->dev, "regmap register fail\n");
+		return PTR_ERR(mpi->regmap);
+	}
+	/* chip id check */
+	ret = regmap_read(mpi->regmap, MT6360_PMU_DEV_INFO, &reg_data);
+	if (ret < 0) {
+		dev_err(&client->dev, "device not found\n");
+		return ret;
+	}
+	if ((reg_data & CHIP_VEN_MASK) != CHIP_VEN_MT6360) {
+		dev_err(&client->dev, "not mt6360 chip\n");
+		return -ENODEV;
+	}
+	mpi->chip_rev = reg_data & CHIP_REV_MASK;
+	/* irq register */
+	memcpy(&mpi->irq_chip, &mt6360_pmu_irq_chip, sizeof(mpi->irq_chip));
+	mpi->irq_chip.name = dev_name(&client->dev);
+	mpi->irq_chip.irq_drv_data = mpi;
+	ret = devm_regmap_add_irq_chip(&client->dev, mpi->regmap, client->irq,
+				       IRQF_TRIGGER_FALLING, 0, &mpi->irq_chip,
+				       &mpi->irq_data);
+	if (ret < 0) {
+		dev_err(&client->dev, "regmap irq chip add fail\n");
+		return ret;
+	}
+	/* new i2c slave device */
+	for (i = 0; i < MT6360_SLAVE_MAX; i++) {
+		if (mt6360_slave_addr[i] == client->addr) {
+			mpi->i2c[i] = client;
+			continue;
+		}
+		mpi->i2c[i] = i2c_new_dummy(client->adapter,
+					    mt6360_slave_addr[i]);
+		if (!mpi->i2c[i]) {
+			dev_err(&client->dev, "new i2c dev [%d] fail\n", i);
+			ret = -ENODEV;
+			goto out;
+		}
+		i2c_set_clientdata(mpi->i2c[i], mpi);
+	}
+	/* mfd cell register */
+	ret = devm_mfd_add_devices(&client->dev, PLATFORM_DEVID_AUTO,
+				   mt6360_devs, ARRAY_SIZE(mt6360_devs), NULL,
+				   0, regmap_irq_get_domain(mpi->irq_data));
+	if (ret < 0) {
+		dev_err(&client->dev, "mfd add cells fail\n");
+		goto out;
+	}
+	dev_info(&client->dev, "Successfully probed\n");
+	return 0;
+out:
+	while (--i >= 0) {
+		if (mpi->i2c[i]->addr == client->addr)
+			continue;
+		i2c_unregister_device(mpi->i2c[i]);
+	}
+	return ret;
+}
+
+static int mt6360_pmu_remove(struct i2c_client *client)
+{
+	struct mt6360_pmu_info *mpi = i2c_get_clientdata(client);
+	int i;
+
+	for (i = 0; i < MT6360_SLAVE_MAX; i++) {
+		if (mpi->i2c[i]->addr == client->addr)
+			continue;
+		i2c_unregister_device(mpi->i2c[i]);
+	}
+	return 0;
+}
+
+static int __maybe_unused mt6360_pmu_suspend(struct device *dev)
+{
+	struct i2c_client *i2c = to_i2c_client(dev);
+
+	if (device_may_wakeup(dev))
+		enable_irq_wake(i2c->irq);
+	return 0;
+}
+
+static int __maybe_unused mt6360_pmu_resume(struct device *dev)
+{
+
+	struct i2c_client *i2c = to_i2c_client(dev);
+
+	if (device_may_wakeup(dev))
+		disable_irq_wake(i2c->irq);
+	return 0;
+}
+
+static SIMPLE_DEV_PM_OPS(mt6360_pmu_pm_ops,
+			 mt6360_pmu_suspend, mt6360_pmu_resume);
+
+static const struct of_device_id __maybe_unused mt6360_pmu_of_id[] = {
+	{ .compatible = "mediatek,mt6360_pmu", },
+	{},
+};
+MODULE_DEVICE_TABLE(of, mt6360_pmu_of_id);
+
+static const struct i2c_device_id mt6360_pmu_id[] = {
+	{ "mt6360_pmu", 0 },
+	{},
+};
+MODULE_DEVICE_TABLE(i2c, mt6360_pmu_id);
+
+static struct i2c_driver mt6360_pmu_driver = {
+	.driver = {
+		.name = "mt6360_pmu",
+		.owner = THIS_MODULE,
+		.pm = &mt6360_pmu_pm_ops,
+		.of_match_table = of_match_ptr(mt6360_pmu_of_id),
+	},
+	.probe = mt6360_pmu_probe,
+	.remove = mt6360_pmu_remove,
+	.id_table = mt6360_pmu_id,
+};
+module_i2c_driver(mt6360_pmu_driver);
+
+MODULE_AUTHOR("CY_Huang <cy_huang@richtek.com>");
+MODULE_DESCRIPTION("MT6360 PMU I2C Driver");
+MODULE_LICENSE("GPL");
+MODULE_VERSION("1.0.0");
diff --git a/include/linux/mfd/mt6360-private.h b/include/linux/mfd/mt6360-private.h
new file mode 100644
index 0000000..b07b3d9
--- /dev/null
+++ b/include/linux/mfd/mt6360-private.h
@@ -0,0 +1,279 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (c) 2019 MediaTek Inc.
+ */
+
+#ifndef __MT6360_PRIVATE_H__
+#define __MT6360_PRIVATE_H__
+
+#include <linux/interrupt.h>
+
+/* PMU register defininition */
+#define MT6360_PMU_DEV_INFO			(0x00)
+#define MT6360_PMU_CORE_CTRL1			(0x01)
+#define MT6360_PMU_RST1				(0x02)
+#define MT6360_PMU_CRCEN			(0x03)
+#define MT6360_PMU_RST_PAS_CODE1		(0x04)
+#define MT6360_PMU_RST_PAS_CODE2		(0x05)
+#define MT6360_PMU_CORE_CTRL2			(0x06)
+#define MT6360_PMU_TM_PAS_CODE1			(0x07)
+#define MT6360_PMU_TM_PAS_CODE2			(0x08)
+#define MT6360_PMU_TM_PAS_CODE3			(0x09)
+#define MT6360_PMU_TM_PAS_CODE4			(0x0A)
+#define MT6360_PMU_IRQ_IND			(0x0B)
+#define MT6360_PMU_IRQ_MASK			(0x0C)
+#define MT6360_PMU_IRQ_SET			(0x0D)
+#define MT6360_PMU_SHDN_CTRL			(0x0E)
+#define MT6360_PMU_TM_INF			(0x0F)
+#define MT6360_PMU_I2C_CTRL			(0x10)
+#define MT6360_PMU_CHG_CTRL1			(0x11)
+#define MT6360_PMU_CHG_CTRL2			(0x12)
+#define MT6360_PMU_CHG_CTRL3			(0x13)
+#define MT6360_PMU_CHG_CTRL4			(0x14)
+#define MT6360_PMU_CHG_CTRL5			(0x15)
+#define MT6360_PMU_CHG_CTRL6			(0x16)
+#define MT6360_PMU_CHG_CTRL7			(0x17)
+#define MT6360_PMU_CHG_CTRL8			(0x18)
+#define MT6360_PMU_CHG_CTRL9			(0x19)
+#define MT6360_PMU_CHG_CTRL10			(0x1A)
+#define MT6360_PMU_CHG_CTRL11			(0x1B)
+#define MT6360_PMU_CHG_CTRL12			(0x1C)
+#define MT6360_PMU_CHG_CTRL13			(0x1D)
+#define MT6360_PMU_CHG_CTRL14			(0x1E)
+#define MT6360_PMU_CHG_CTRL15			(0x1F)
+#define MT6360_PMU_CHG_CTRL16			(0x20)
+#define MT6360_PMU_CHG_AICC_RESULT		(0x21)
+#define MT6360_PMU_DEVICE_TYPE			(0x22)
+#define MT6360_PMU_QC_CONTROL1			(0x23)
+#define MT6360_PMU_QC_CONTROL2			(0x24)
+#define MT6360_PMU_QC30_CONTROL1		(0x25)
+#define MT6360_PMU_QC30_CONTROL2		(0x26)
+#define MT6360_PMU_USB_STATUS1			(0x27)
+#define MT6360_PMU_QC_STATUS1			(0x28)
+#define MT6360_PMU_QC_STATUS2			(0x29)
+#define MT6360_PMU_CHG_PUMP			(0x2A)
+#define MT6360_PMU_CHG_CTRL17			(0x2B)
+#define MT6360_PMU_CHG_CTRL18			(0x2C)
+#define MT6360_PMU_CHRDET_CTRL1			(0x2D)
+#define MT6360_PMU_CHRDET_CTRL2			(0x2E)
+#define MT6360_PMU_DPDN_CTRL			(0x2F)
+#define MT6360_PMU_CHG_HIDDEN_CTRL1		(0x30)
+#define MT6360_PMU_CHG_HIDDEN_CTRL2		(0x31)
+#define MT6360_PMU_CHG_HIDDEN_CTRL3		(0x32)
+#define MT6360_PMU_CHG_HIDDEN_CTRL4		(0x33)
+#define MT6360_PMU_CHG_HIDDEN_CTRL5		(0x34)
+#define MT6360_PMU_CHG_HIDDEN_CTRL6		(0x35)
+#define MT6360_PMU_CHG_HIDDEN_CTRL7		(0x36)
+#define MT6360_PMU_CHG_HIDDEN_CTRL8		(0x37)
+#define MT6360_PMU_CHG_HIDDEN_CTRL9		(0x38)
+#define MT6360_PMU_CHG_HIDDEN_CTRL10		(0x39)
+#define MT6360_PMU_CHG_HIDDEN_CTRL11		(0x3A)
+#define MT6360_PMU_CHG_HIDDEN_CTRL12		(0x3B)
+#define MT6360_PMU_CHG_HIDDEN_CTRL13		(0x3C)
+#define MT6360_PMU_CHG_HIDDEN_CTRL14		(0x3D)
+#define MT6360_PMU_CHG_HIDDEN_CTRL15		(0x3E)
+#define MT6360_PMU_CHG_HIDDEN_CTRL16		(0x3F)
+#define MT6360_PMU_CHG_HIDDEN_CTRL17		(0x40)
+#define MT6360_PMU_CHG_HIDDEN_CTRL18		(0x41)
+#define MT6360_PMU_CHG_HIDDEN_CTRL19		(0x42)
+#define MT6360_PMU_CHG_HIDDEN_CTRL20		(0x43)
+#define MT6360_PMU_CHG_HIDDEN_CTRL21		(0x44)
+#define MT6360_PMU_CHG_HIDDEN_CTRL22		(0x45)
+#define MT6360_PMU_CHG_HIDDEN_CTRL23		(0x46)
+#define MT6360_PMU_CHG_HIDDEN_CTRL24		(0x47)
+#define MT6360_PMU_CHG_HIDDEN_CTRL25		(0x48)
+#define MT6360_PMU_BC12_CTRL			(0x49)
+#define MT6360_PMU_CHG_STAT			(0x4A)
+#define MT6360_PMU_RESV1			(0x4B)
+#define MT6360_PMU_TYPEC_OTP_TH_SEL_CODEH	(0x4E)
+#define MT6360_PMU_TYPEC_OTP_TH_SEL_CODEL	(0x4F)
+#define MT6360_PMU_TYPEC_OTP_HYST_TH		(0x50)
+#define MT6360_PMU_TYPEC_OTP_CTRL		(0x51)
+#define MT6360_PMU_ADC_BAT_DATA_H		(0x52)
+#define MT6360_PMU_ADC_BAT_DATA_L		(0x53)
+#define MT6360_PMU_IMID_BACKBST_ON		(0x54)
+#define MT6360_PMU_IMID_BACKBST_OFF		(0x55)
+#define MT6360_PMU_ADC_CONFIG			(0x56)
+#define MT6360_PMU_ADC_EN2			(0x57)
+#define MT6360_PMU_ADC_IDLE_T			(0x58)
+#define MT6360_PMU_ADC_RPT_1			(0x5A)
+#define MT6360_PMU_ADC_RPT_2			(0x5B)
+#define MT6360_PMU_ADC_RPT_3			(0x5C)
+#define MT6360_PMU_ADC_RPT_ORG1			(0x5D)
+#define MT6360_PMU_ADC_RPT_ORG2			(0x5E)
+#define MT6360_PMU_BAT_OVP_TH_SEL_CODEH		(0x5F)
+#define MT6360_PMU_BAT_OVP_TH_SEL_CODEL		(0x60)
+#define MT6360_PMU_CHG_CTRL19			(0x61)
+#define MT6360_PMU_VDDASUPPLY			(0x62)
+#define MT6360_PMU_BC12_MANUAL			(0x63)
+#define MT6360_PMU_CHGDET_FUNC			(0x64)
+#define MT6360_PMU_FOD_CTRL			(0x65)
+#define MT6360_PMU_CHG_CTRL20			(0x66)
+#define MT6360_PMU_CHG_HIDDEN_CTRL26		(0x67)
+#define MT6360_PMU_CHG_HIDDEN_CTRL27		(0x68)
+#define MT6360_PMU_RESV2			(0x69)
+#define MT6360_PMU_USBID_CTRL1			(0x6D)
+#define MT6360_PMU_USBID_CTRL2			(0x6E)
+#define MT6360_PMU_USBID_CTRL3			(0x6F)
+#define MT6360_PMU_FLED_CFG			(0x70)
+#define MT6360_PMU_RESV3			(0x71)
+#define MT6360_PMU_FLED1_CTRL			(0x72)
+#define MT6360_PMU_FLED_STRB_CTRL		(0x73)
+#define MT6360_PMU_FLED1_STRB_CTRL2		(0x74)
+#define MT6360_PMU_FLED1_TOR_CTRL		(0x75)
+#define MT6360_PMU_FLED2_CTRL			(0x76)
+#define MT6360_PMU_RESV4			(0x77)
+#define MT6360_PMU_FLED2_STRB_CTRL2		(0x78)
+#define MT6360_PMU_FLED2_TOR_CTRL		(0x79)
+#define MT6360_PMU_FLED_VMIDTRK_CTRL1		(0x7A)
+#define MT6360_PMU_FLED_VMID_RTM		(0x7B)
+#define MT6360_PMU_FLED_VMIDTRK_CTRL2		(0x7C)
+#define MT6360_PMU_FLED_PWSEL			(0x7D)
+#define MT6360_PMU_FLED_EN			(0x7E)
+#define MT6360_PMU_FLED_Hidden1			(0x7F)
+#define MT6360_PMU_RGB_EN			(0x80)
+#define MT6360_PMU_RGB1_ISNK			(0x81)
+#define MT6360_PMU_RGB2_ISNK			(0x82)
+#define MT6360_PMU_RGB3_ISNK			(0x83)
+#define MT6360_PMU_RGB_ML_ISNK			(0x84)
+#define MT6360_PMU_RGB1_DIM			(0x85)
+#define MT6360_PMU_RGB2_DIM			(0x86)
+#define MT6360_PMU_RGB3_DIM			(0x87)
+#define MT6360_PMU_RESV5			(0x88)
+#define MT6360_PMU_RGB12_Freq			(0x89)
+#define MT6360_PMU_RGB34_Freq			(0x8A)
+#define MT6360_PMU_RGB1_Tr			(0x8B)
+#define MT6360_PMU_RGB1_Tf			(0x8C)
+#define MT6360_PMU_RGB1_TON_TOFF		(0x8D)
+#define MT6360_PMU_RGB2_Tr			(0x8E)
+#define MT6360_PMU_RGB2_Tf			(0x8F)
+#define MT6360_PMU_RGB2_TON_TOFF		(0x90)
+#define MT6360_PMU_RGB3_Tr			(0x91)
+#define MT6360_PMU_RGB3_Tf			(0x92)
+#define MT6360_PMU_RGB3_TON_TOFF		(0x93)
+#define MT6360_PMU_RGB_Hidden_CTRL1		(0x94)
+#define MT6360_PMU_RGB_Hidden_CTRL2		(0x95)
+#define MT6360_PMU_RESV6			(0x97)
+#define MT6360_PMU_SPARE1			(0x9A)
+#define MT6360_PMU_SPARE2			(0xA0)
+#define MT6360_PMU_SPARE3			(0xB0)
+#define MT6360_PMU_SPARE4			(0xC0)
+#define MT6360_PMU_CHG_IRQ1			(0xD0)
+#define MT6360_PMU_CHG_IRQ2			(0xD1)
+#define MT6360_PMU_CHG_IRQ3			(0xD2)
+#define MT6360_PMU_CHG_IRQ4			(0xD3)
+#define MT6360_PMU_CHG_IRQ5			(0xD4)
+#define MT6360_PMU_CHG_IRQ6			(0xD5)
+#define MT6360_PMU_QC_IRQ			(0xD6)
+#define MT6360_PMU_FOD_IRQ			(0xD7)
+#define MT6360_PMU_BASE_IRQ			(0xD8)
+#define MT6360_PMU_FLED_IRQ1			(0xD9)
+#define MT6360_PMU_FLED_IRQ2			(0xDA)
+#define MT6360_PMU_RGB_IRQ			(0xDB)
+#define MT6360_PMU_BUCK1_IRQ			(0xDC)
+#define MT6360_PMU_BUCK2_IRQ			(0xDD)
+#define MT6360_PMU_LDO_IRQ1			(0xDE)
+#define MT6360_PMU_LDO_IRQ2			(0xDF)
+#define MT6360_PMU_CHG_STAT1			(0xE0)
+#define MT6360_PMU_CHG_STAT2			(0xE1)
+#define MT6360_PMU_CHG_STAT3			(0xE2)
+#define MT6360_PMU_CHG_STAT4			(0xE3)
+#define MT6360_PMU_CHG_STAT5			(0xE4)
+#define MT6360_PMU_CHG_STAT6			(0xE5)
+#define MT6360_PMU_QC_STAT			(0xE6)
+#define MT6360_PMU_FOD_STAT			(0xE7)
+#define MT6360_PMU_BASE_STAT			(0xE8)
+#define MT6360_PMU_FLED_STAT1			(0xE9)
+#define MT6360_PMU_FLED_STAT2			(0xEA)
+#define MT6360_PMU_RGB_STAT			(0xEB)
+#define MT6360_PMU_BUCK1_STAT			(0xEC)
+#define MT6360_PMU_BUCK2_STAT			(0xED)
+#define MT6360_PMU_LDO_STAT1			(0xEE)
+#define MT6360_PMU_LDO_STAT2			(0xEF)
+#define MT6360_PMU_CHG_MASK1			(0xF0)
+#define MT6360_PMU_CHG_MASK2			(0xF1)
+#define MT6360_PMU_CHG_MASK3			(0xF2)
+#define MT6360_PMU_CHG_MASK4			(0xF3)
+#define MT6360_PMU_CHG_MASK5			(0xF4)
+#define MT6360_PMU_CHG_MASK6			(0xF5)
+#define MT6360_PMU_QC_MASK			(0xF6)
+#define MT6360_PMU_FOD_MASK			(0xF7)
+#define MT6360_PMU_BASE_MASK			(0xF8)
+#define MT6360_PMU_FLED_MASK1			(0xF9)
+#define MT6360_PMU_FLED_MASK2			(0xFA)
+#define MT6360_PMU_FAULTB_MASK			(0xFB)
+#define MT6360_PMU_BUCK1_MASK			(0xFC)
+#define MT6360_PMU_BUCK2_MASK			(0xFD)
+#define MT6360_PMU_LDO_MASK1			(0xFE)
+#define MT6360_PMU_LDO_MASK2			(0xFF)
+#define MT6360_PMU_MAXREG			(MT6360_PMU_LDO_MASK2)
+
+
+/* MT6360_PMU_IRQ_SET */
+#define MT6360_PMU_IRQ_REGNUM	(MT6360_PMU_LDO_IRQ2 - MT6360_PMU_CHG_IRQ1 + 1)
+#define MT6360_IRQ_RETRIG	BIT(2)
+
+#define CHIP_VEN_MASK				(0xF0)
+#define CHIP_VEN_MT6360				(0x50)
+#define CHIP_REV_MASK				(0x0F)
+
+/* IRQ definitions */
+struct mt6360_pmu_irq_desc {
+	const char *name;
+	irq_handler_t irq_handler;
+};
+
+#define  MT6360_DT_VALPROP(name, type) \
+			{#name, offsetof(type, name)}
+
+struct mt6360_val_prop {
+	const char *name;
+	size_t offset;
+};
+
+static inline void mt6360_dt_parser_helper(struct device_node *np, void *data,
+					   const struct mt6360_val_prop *props,
+					   int prop_cnt)
+{
+	int i;
+
+	for (i = 0; i < prop_cnt; i++) {
+		if (unlikely(!props[i].name))
+			continue;
+		of_property_read_u32(np, props[i].name, data + props[i].offset);
+	}
+}
+
+#define MT6360_PDATA_VALPROP(name, type, reg, shift, mask, func, base) \
+			{offsetof(type, name), reg, shift, mask, func, base}
+
+struct mt6360_pdata_prop {
+	size_t offset;
+	u8 reg;
+	u8 shift;
+	u8 mask;
+	u32 (*transform)(u32 val);
+	u8 base;
+};
+
+static inline int mt6360_pdata_apply_helper(void *context, void *pdata,
+					   const struct mt6360_pdata_prop *prop,
+					   int prop_cnt)
+{
+	int i, ret;
+	u32 val;
+
+	for (i = 0; i < prop_cnt; i++) {
+		val = *(u32 *)(pdata + prop[i].offset);
+		if (prop[i].transform)
+			val = prop[i].transform(val);
+		val += prop[i].base;
+		ret = regmap_update_bits(context,
+			     prop[i].reg, prop[i].mask, val << prop[i].shift);
+		if (ret < 0)
+			return ret;
+	}
+	return 0;
+}
+
+#endif /* __MT6360_PRIVATE_H__ */
diff --git a/include/linux/mfd/mt6360.h b/include/linux/mfd/mt6360.h
new file mode 100644
index 0000000..ba2e80a
--- /dev/null
+++ b/include/linux/mfd/mt6360.h
@@ -0,0 +1,33 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (c) 2019 MediaTek Inc.
+ */
+
+#ifndef __MT6360_H__
+#define __MT6360_H__
+
+#include <linux/regmap.h>
+
+enum {
+	MT6360_SLAVE_PMU = 0,
+	MT6360_SLAVE_PMIC,
+	MT6360_SLAVE_LDO,
+	MT6360_SLAVE_TCPC,
+	MT6360_SLAVE_MAX,
+};
+
+#define MT6360_PMU_SLAVEID	(0x34)
+#define MT6360_PMIC_SLAVEID	(0x1A)
+#define MT6360_LDO_SLAVEID	(0x64)
+#define MT6360_TCPC_SLAVEID	(0x4E)
+
+struct mt6360_pmu_info {
+	struct i2c_client *i2c[MT6360_SLAVE_MAX];
+	struct device *dev;
+	struct regmap *regmap;
+	struct regmap_irq_chip_data *irq_data;
+	struct regmap_irq_chip irq_chip;
+	unsigned int chip_rev;
+};
+
+#endif /* __MT6360_H__ */
-- 
1.9.1


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply related

* Re: [PATCH v6 01/11] kselftest: arm64: extend toplevel skeleton Makefile
From: Dave Martin @ 2019-09-18 10:17 UTC (permalink / raw)
  To: shuah
  Cc: amit.kachhap, andreyknvl, linux-kselftest, linux-arm-kernel,
	Cristian Marussi
In-Reply-To: <119aaea7-10b5-0fdf-269d-e86df07b4831@kernel.org>

On Tue, Sep 17, 2019 at 10:18:55AM -0600, shuah wrote:
> On 9/17/19 10:05 AM, Dave Martin wrote:
> >On Tue, Sep 10, 2019 at 01:31:01pm +0100, Cristian Marussi wrote:
> >>Modify KSFT arm64 toplevel Makefile to maintain arm64 kselftests organized
> >>by subsystem, keeping them into distinct subdirectories under arm64 custom
> >>KSFT directory: tools/testing/selftests/arm64/
> >>
> >>Add to such toplevel Makefile a mechanism to guess the effective location
> >>of Kernel headers as installed by KSFT framework.
> >>
> >>Fit existing arm64 tags kselftest into this new schema moving them into
> >>their own subdirectory (arm64/tags).
> >>
> >>Signed-off-by: Cristian Marussi <cristian.marussi@arm.com>
> >>---
> >>Based on:
> >>commit 9ce1263033cd ("selftests, arm64: add a selftest for passing
> >>		     tagged pointers to kernel")
> >>---
> >>v5 --> v6
> >>- using realpath to avoid passing down relative paths
> >>- fix commit msg & Copyright
> >>- removed unneded Makefile export
> >>- added SUBTARGETS specification, to allow building specific only some
> >>   arm64 test subsystems
> >>v4 --> v5
> >>- rebased on arm64/for-next/core
> >>- merged this patch with KSFT arm64 tags patch, while moving the latter
> >>   into its own subdir
> >>- moved kernel header includes search mechanism from KSFT arm64
> >>   SIGNAL Makefile
> >>- export proper top_srcdir ENV for lib.mk
> >>v3 --> v4
> >>- comment reword
> >>- simplified documentation in README
> >>- dropped README about standalone
> >>---
> >>  tools/testing/selftests/Makefile              |  1 +
> >>  tools/testing/selftests/arm64/Makefile        | 63 +++++++++++++++++--
> >>  tools/testing/selftests/arm64/README          | 25 ++++++++
> >>  tools/testing/selftests/arm64/tags/Makefile   |  6 ++
> >>  .../arm64/{ => tags}/run_tags_test.sh         |  0
> >>  .../selftests/arm64/{ => tags}/tags_test.c    |  0
> >>  6 files changed, 91 insertions(+), 4 deletions(-)
> >>  create mode 100644 tools/testing/selftests/arm64/README
> >>  create mode 100644 tools/testing/selftests/arm64/tags/Makefile
> >>  rename tools/testing/selftests/arm64/{ => tags}/run_tags_test.sh (100%)
> >>  rename tools/testing/selftests/arm64/{ => tags}/tags_test.c (100%)
> >>
> >>diff --git a/tools/testing/selftests/Makefile b/tools/testing/selftests/Makefile
> >>index 25b43a8c2b15..1722dae9381a 100644
> >>--- a/tools/testing/selftests/Makefile
> >>+++ b/tools/testing/selftests/Makefile
> >>@@ -1,5 +1,6 @@
> >>  # SPDX-License-Identifier: GPL-2.0
> >>  TARGETS = android
> >>+TARGETS += arm64
> >>  TARGETS += bpf
> >>  TARGETS += breakpoints
> >>  TARGETS += capabilities
> >>diff --git a/tools/testing/selftests/arm64/Makefile b/tools/testing/selftests/arm64/Makefile
> >>index a61b2e743e99..cbb2a5a9e3fc 100644
> >>--- a/tools/testing/selftests/arm64/Makefile
> >>+++ b/tools/testing/selftests/arm64/Makefile
> >>@@ -1,11 +1,66 @@
> >>  # SPDX-License-Identifier: GPL-2.0
> >>-# ARCH can be overridden by the user for cross compiling
> >>+# When ARCH not overridden for crosscompiling, lookup machine
> >>  ARCH ?= $(shell uname -m 2>/dev/null || echo not)
> >>  ifneq (,$(filter $(ARCH),aarch64 arm64))
> >>-TEST_GEN_PROGS := tags_test
> >>-TEST_PROGS := run_tags_test.sh
> >>+SUBTARGETS ?= tags
> >>+else
> >>+SUBTARGETS :=
> >>  endif
> >>-include ../lib.mk
> >>+CFLAGS := -Wall -O2 -g
> >>+
> >>+# A proper top_srcdir is needed by KSFT(lib.mk)
> >>+top_srcdir = $(realpath ../../../../)
> >>+
> >>+# Additional include paths needed by kselftest.h and local headers
> >>+CFLAGS += -I$(top_srcdir)/tools/testing/selftests/
> >>+
> >>+# Guessing where the Kernel headers could have been installed
> >>+# depending on ENV config
> >>+ifeq ($(KBUILD_OUTPUT),)
> >>+khdr_dir = $(top_srcdir)/usr/include
> >>+else
> >>+# the KSFT preferred location when KBUILD_OUTPUT is set
> >>+khdr_dir = $(KBUILD_OUTPUT)/kselftest/usr/include
> >>+endif
> >
> >I still tend to think that for now we should just do what all the other
> >tests do.
> >
> >Most tests use
> >
> >	CFLAGS += -I../../../../usr/include/
> >
> >in their Makefiles.
> >
> >For us, the test Makefiles are nested one level deeper, so I guess
> >we would put
> >
> >	CFLAGS += -I../../../../../usr/include/
> >
> >in each.
> >
> >
> >This will break in some cases, but only in the same cases where
> >kselftest is already broken.
> >
> >Ideally we would fix this globally, but can that instead be done
> >independently of this series?
> >
> >Fixing only arm64, by pasting some arbitrary logic from
> >selftests/Makefile doesn't seem like a future-proof approach.
> >
> >
> >Or did I miss something?
> >
> >>+
> >>+CFLAGS += -I$(khdr_dir)
> >>+
> >>+export CFLAGS
> >>+export top_srcdir
> >>+
> >>+all:
> >>+	@for DIR in $(SUBTARGETS); do				\
> >>+		BUILD_TARGET=$(OUTPUT)/$$DIR;			\
> >>+		mkdir -p $$BUILD_TARGET;			\
> >>+		make OUTPUT=$$BUILD_TARGET -C $$DIR $@;		\
> >>+	done
> >>+
> >>+install: all
> >>+	@for DIR in $(SUBTARGETS); do				\
> >>+		BUILD_TARGET=$(OUTPUT)/$$DIR;			\
> >>+		make OUTPUT=$$BUILD_TARGET -C $$DIR $@;		\
> >>+	done
> >>+
> >>+run_tests: all
> >>+	@for DIR in $(SUBTARGETS); do				\
> >>+		BUILD_TARGET=$(OUTPUT)/$$DIR;			\
> >>+		make OUTPUT=$$BUILD_TARGET -C $$DIR $@;		\
> >>+	done
> >>+
> >>+# Avoid any output on non arm64 on emit_tests
> >
> >This comment can be dropped: the whole file does nothing for
> >non-arm64, and it achieves it in the same way as other arch-specific
> >Makefiles, so it's odd to have the comment here specifically (?)
> >
> >
> >With or without the above changes, I'm happy to give
> >
> >Reviewed-by: Dave Martin <Dave.Martin@arm.com>
> >
> >(but Shuah or someone will need to give a view on how this integrates
> >with kselftest overall).
> >
> 
> I am reviewing the series this week. I will provide comments in a
> day or two.
> 
> thanks,
> -- Shuah

Thanks!

From the arm64 side, I'd say we're just down to minor issues at this
point.

Cheers
---Dave

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply

* Re: [PATCH] irqchip/gic-v3: Fix GIC_LINE_NR accessor
From: Marc Zyngier @ 2019-09-18 10:23 UTC (permalink / raw)
  To: Zenghui Yu; +Cc: wanghaibin.wang, tglx, jason, linux-arm-kernel, linux-kernel
In-Reply-To: <1568789850-14080-1-git-send-email-yuzenghui@huawei.com>

On 18/09/2019 07:57, Zenghui Yu wrote:
> As per GIC spec, ITLinesNumber indicates the maximum SPI INTID that
> the GIC implementation supports. And the maximum SPI INTID an
> implementation might support is 1019 (field value 11111).
> 
> max(GICD_TYPER_SPIS(...), 1020) is not what we actually want for
> GIC_LINE_NR. Fix it to min(GICD_TYPER_SPIS(...), 1020).
> 
> Signed-off-by: Zenghui Yu <yuzenghui@huawei.com>
> ---
> 
> Hi Marc,
> 
> I still see "GICv3: 992 SPIs implemented" on the host. I go back to
> https://patchwork.kernel.org/patch/11078623/ and it seems that we
> failed to make the GIC_LINE_NR correct at that time.

Ah, nice catch. Clearly, I didn't have my head screwed on properly when
I wrote this. I'll take this in for the next round of fixes.

Thanks,

	M.
-- 
Jazz is not dead, it just smells funny...

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply

* Re: [RFC PATCH v3 4/6] psci: Add hvc call service for ptp_kvm.
From: Paolo Bonzini @ 2019-09-18 10:23 UTC (permalink / raw)
  To: Jianyong Wu (Arm Technology China), netdev@vger.kernel.org,
	yangbo.lu@nxp.com, john.stultz@linaro.org, tglx@linutronix.de,
	sean.j.christopherson@intel.com, maz@kernel.org,
	richardcochran@gmail.com, Mark Rutland, Will Deacon,
	Suzuki Poulose
  Cc: Justin He (Arm Technology China), kvm@vger.kernel.org,
	Steve Capper, linux-kernel@vger.kernel.org,
	Kaly Xin (Arm Technology China), nd,
	linux-arm-kernel@lists.infradead.org
In-Reply-To: <HE1PR0801MB1676F57B317AE85E3B934B32F48E0@HE1PR0801MB1676.eurprd08.prod.outlook.com>

On 18/09/19 11:57, Jianyong Wu (Arm Technology China) wrote:
> Hi Paolo,
> 
>> On 18/09/19 10:07, Jianyong Wu wrote:
>>> +	case ARM_SMCCC_VENDOR_HYP_KVM_PTP_FUNC_ID:
>>> +		getnstimeofday(ts);
>>
>> This is not Y2038-safe.  Please use ktime_get_real_ts64 instead, and split the
>> 64-bit seconds value between val[0] and val[1].
>>
> As far as I know, y2038-safe will only affect signed 32-bit integer,
> how does it affect 64-bit integer?
> And why split 64-bit number into two blocks is necessary?

val is an u32, not an u64.  (And val[0], where you store the seconds, is
best treated as signed, since val[0] == -1 is returned for
SMCCC_RET_NOT_SUPPORTED).

>> However, it seems to me that the new function is not needed and you can
>> just use ktime_get_snapshot.  You'll get the time in systime_snapshot->real
>> and the cycles value in systime_snapshot->cycles.
> 
> See patch 5/6, I need both counter cycle and clocksource, ktime_get_snapshot seems only offer cycles.

No, patch 5/6 only needs the current clock (ptp_sc.cycles is never
accessed).  So you could just use READ_ONCE(tk->tkr_mono.clock).

However, even then I don't think it is correct to use ptp_sc.cs blindly
in patch 5.  I think there is a misunderstanding on the meaning of
system_counterval.cs as passed to get_device_system_crosststamp.
system_counterval.cs is not the active clocksource; it's the clocksource
on which system_counterval.cycles is based.

Hypothetically, the clocksource could be one for which ptp_sc.cycles is
_not_ a cycle value.  If you set system_counterval.cs to the system
clocksource, get_device_system_crosststamp will return a bogus value.
So system_counterval.cs should be set to something like
&clocksource_counter (from drivers/clocksource/arm_arch_timer.c).
Perhaps the right place to define kvm_arch_ptp_get_clock_fn is in that file?

>>> +		get_current_counterval(&sc);
>>> +		val[0] = ts->tv_sec;
>>> +		val[1] = ts->tv_nsec;
>>> +		val[2] = sc.cycles;
>>> +		val[3] = 0;
>>> +		break;
>>
>> This should return a guest-cycles value.  If the cycles values always the same
>> between the host and the guest on ARM, then okay.  If not, you have to
>> apply whatever offset exists.
>>
> In my opinion, when use ptp_kvm as clock sources to sync time
> between host and guest, user should promise the guest and host has no
> clock offset.

What would be the adverse effect of having a fixed offset between guest
and host?  If there were one, you'd have to check that and fail the
hypercall if there is an offset.  But again, I think it's enough to
subtract vcpu_vtimer(vcpu)->cntvoff or something like that.

You also have to check here that the clocksource is based on the ARM
architectural timer.  Again, maybe you could place the implementation in
drivers/clocksource/arm_arch_timer.c, and make it return -ENODEV if the
active clocksource is not clocksource_counter.  Then KVM can look for
errors and return SMCCC_RET_NOT_SUPPORTED in that case.

Thanks,

Paolo

> So we can be sure that the cycle between guest and
> host should be keep consistent. But I need check it.
> I think host cycle should be returned to guest as we should promise
> we get clock and counter in the same time.


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply

* Re: [PATCH 0/9] added helper macros to remove duplicate code from probe functions of the platform drivers
From: Vinod Koul @ 2019-09-18 10:27 UTC (permalink / raw)
  To: Satendra Singh Thakur
  Cc: lars, maxime.ripard, sean.wang, linux-kernel, afaerber, dmaengine,
	wens, agross, linux-mediatek, satendrasingh.thakur,
	manivannan.sadhasivam, matthias.bgg, dan.j.williams, shawnguo,
	jun.nie, linux-arm-kernel
In-Reply-To: <20190915070003.21260-1-sst2005@gmail.com>

On 15-09-19, 12:30, Satendra Singh Thakur wrote:
> 1. For most of the platform drivers's probe include following steps
> 
> -memory allocation for driver's private structure
> -getting io resources
> -io remapping resources
> -getting irq number
> -registering irq
> -setting driver's private data
> -getting clock
> -preparing and enabling clock

And we have perfect set of APIs for these tasks!

> 2. We have defined a set of macros to combine some or all of
> the above mentioned steps. This will remove redundant/duplicate
> code in drivers' probe functions of platform drivers.

Why, how does it help and you do realize it also introduces bugs

> devm_platform_probe_helper(pdev, priv, clk_name);
> devm_platform_probe_helper_clk(pdev, priv, clk_name);
> devm_platform_probe_helper_irq(pdev, priv, clk_name,
> irq_hndlr, irq_flags, irq_name, irq_devid);
> devm_platform_probe_helper_all(pdev, priv, clk_name,
> irq_hndlr, irq_flags, irq_name, irq_devid);
> devm_platform_probe_helper_all_data(pdev, priv, clk_name,
> irq_hndlr, irq_flags, irq_name, irq_devid);
> 
> 3. Code is made devres compatible (wherever required)
> The functions: clk_get, request_irq, kzalloc, platform_get_resource
> are replaced with their devm_* counterparts.

We already have devres APIs for people to use!
> 
> 4. Few bugs are also fixed.

Which ones..?

> 
> Satendra Singh Thakur (9):
>   probe/dma : added helper macros to remove redundant/duplicate code
>     from probe functions of the dma controller drivers
>   probe/dma/jz4740: removed redundant code from jz4740 dma controller's 
>        probe function
>   probe/dma/zx: removed redundant code from zx dma controller's probe
>     function
>   probe/dma/qcom-bam: removed redundant code from qcom bam dma
>     controller's probe function
>   probe/dma/mtk-hs: removed redundant code from mediatek hs dma
>     controller's probe function
>   probe/dma/sun6i: removed redundant code from sun6i dma controller's
>     probe function
>   probe/dma/sun4i: removed redundant code from sun4i dma controller's
>     probe function
>   probe/dma/axi: removed redundant code from axi dma controller's probe
>     function
>   probe/dma/owl: removed redundant code from owl dma controller's probe
>     function
> 
>  drivers/dma/dma-axi-dmac.c       |  28 ++---
>  drivers/dma/dma-jz4740.c         |  33 +++---
>  drivers/dma/mediatek/mtk-hsdma.c |  38 +++----
>  drivers/dma/owl-dma.c            |  29 ++---
>  drivers/dma/qcom/bam_dma.c       |  71 +++++-------
>  drivers/dma/sun4i-dma.c          |  30 ++----
>  drivers/dma/sun6i-dma.c          |  30 ++----
>  drivers/dma/zx_dma.c             |  35 ++----
>  include/linux/probe-helper.h     | 179 +++++++++++++++++++++++++++++++
>  9 files changed, 280 insertions(+), 193 deletions(-)
>  create mode 100644 include/linux/probe-helper.h
> 
> -- 
> 2.17.1

-- 
~Vinod

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply

* [PATCH] media: rc: Use devm_platform_ioremap_resource() in tango_ir_probe()
From: Markus Elfring @ 2019-09-18 10:37 UTC (permalink / raw)
  To: linux-media, linux-arm-kernel, Allison Randal, Greg Kroah-Hartman,
	Mans Rullgard, Marc Gonzalez, Mauro Carvalho Chehab,
	Thomas Gleixner
  Cc: Bartosz Golaszewski, kernel-janitors, LKML, Himanshu Jha

From: Markus Elfring <elfring@users.sourceforge.net>
Date: Wed, 18 Sep 2019 12:30:18 +0200

Simplify this function implementation by using a known wrapper function.

This issue was detected by using the Coccinelle software.

Signed-off-by: Markus Elfring <elfring@users.sourceforge.net>
---
 drivers/media/rc/tango-ir.c | 14 ++------------
 1 file changed, 2 insertions(+), 12 deletions(-)

diff --git a/drivers/media/rc/tango-ir.c b/drivers/media/rc/tango-ir.c
index 451ec4e9dcfa..b8eb5bc4d9be 100644
--- a/drivers/media/rc/tango-ir.c
+++ b/drivers/media/rc/tango-ir.c
@@ -157,20 +157,10 @@ static int tango_ir_probe(struct platform_device *pdev)
 	struct device *dev = &pdev->dev;
 	struct rc_dev *rc;
 	struct tango_ir *ir;
-	struct resource *rc5_res;
-	struct resource *rc6_res;
 	u64 clkrate, clkdiv;
 	int irq, err;
 	u32 val;

-	rc5_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-	if (!rc5_res)
-		return -EINVAL;
-
-	rc6_res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
-	if (!rc6_res)
-		return -EINVAL;
-
 	irq = platform_get_irq(pdev, 0);
 	if (irq <= 0)
 		return -EINVAL;
@@ -179,11 +169,11 @@ static int tango_ir_probe(struct platform_device *pdev)
 	if (!ir)
 		return -ENOMEM;

-	ir->rc5_base = devm_ioremap_resource(dev, rc5_res);
+	ir->rc5_base = devm_platform_ioremap_resource(pdev, 0);
 	if (IS_ERR(ir->rc5_base))
 		return PTR_ERR(ir->rc5_base);

-	ir->rc6_base = devm_ioremap_resource(dev, rc6_res);
+	ir->rc6_base = devm_platform_ioremap_resource(pdev, 1);
 	if (IS_ERR(ir->rc6_base))
 		return PTR_ERR(ir->rc6_base);

--
2.23.0


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply related

* Re: [PATCH] regulator: vexpress: Use PTR_ERR_OR_ZERO() in vexpress_regulator_probe()
From: Sudeep Holla @ 2019-09-18 10:44 UTC (permalink / raw)
  To: Markus Elfring, Mark Brown
  Cc: Lorenzo Pieralisi, kernel-janitors, Liviu Dudau, Liam Girdwood,
	LKML, Sudeep Holla, linux-arm-kernel
In-Reply-To: <1123a2ab-48f9-f41f-cabb-9b45310cb77e@web.de>

On Sat, Sep 07, 2019 at 01:23:08PM +0200, Markus Elfring wrote:
> From: Markus Elfring <elfring@users.sourceforge.net>
> Date: Sat, 7 Sep 2019 13:07:22 +0200
>
> Simplify this function implementation by using a known function.
>
> Generated by: scripts/coccinelle/api/ptr_ret.cocci
>

Acked-by: Sudeep Holla <sudeep.holla@arm.comi>

Hi Mark,

I assume you can take this via your tree.

--
Regards,
Sudeep

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply

* [PATCH v1 0/9] Basic sound support for Arndale board / wm8994 updates
From: Sylwester Nawrocki @ 2019-09-18 10:46 UTC (permalink / raw)
  To: broonie
  Cc: devicetree, alsa-devel, linux-samsung-soc, ckeepax, b.zolnierkie,
	sbkim73, patches, lgirdwood, krzk, robh+dt, Sylwester Nawrocki,
	linux-arm-kernel, m.szyprowski
In-Reply-To: <CGME20190918104650eucas1p2288b0b7e8081e872c4f181cb5ca8ba0d@eucas1p2.samsung.com>

This patch series adds basic audio support for Exynos5250 SoC based Arndale 
board, the Bluetooth receiver source and HDMI output are not covered yet.

There is also one fix for wm8994 driver related to WM1811 CODEC and wm8994
updates to handle MCLK clocks, similar to patches:
 ae1ea48c5c59 ("ASoC: arizona: Add gating for source clocks of the FLLs")
 7a4413d0dc96 ("ASoC: arizona: Add gating for clock when used for direct MCLK")

Sylwester Nawrocki (9):
  ASoC: wm8994: Do not register inapplicable controls for WM1811
  mfd: wm8994: Add support for MCLKn clock control
  ASoC: wm8994: Add support for setting MCLKn clock rate
  ASoC: wm8994: Add support for MCLKn clock gating
  ASoC: samsung: arndale: Simplify DAI link initialization
  ASoC: dt-bindings: Document "samsung,arndale-wm1811" compatible
  ASoC: samsung: arndale: Add support for WM1811 CODEC
  ASoC: samsung: arndale: Add missing OF node dereferencing
  ARM: dts: arndale: Add audio support (WM1811 CODEC boards)

 .../devicetree/bindings/sound/arndale.txt     |   5 +-
 arch/arm/boot/dts/exynos5250-arndale.dts      |  27 ++-
 drivers/mfd/wm8994-core.c                     |   9 +
 include/linux/mfd/wm8994/core.h               |   9 +
 sound/soc/codecs/wm8994.c                     | 164 +++++++++++++++---
 sound/soc/samsung/arndale_rt5631.c            | 155 +++++++++++++----
 6 files changed, 306 insertions(+), 63 deletions(-)

-- 
2.17.1


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply

* [PATCH v1 1/9] ASoC: wm8994: Do not register inapplicable controls for WM1811
From: Sylwester Nawrocki @ 2019-09-18 10:46 UTC (permalink / raw)
  To: broonie
  Cc: devicetree, alsa-devel, linux-samsung-soc, ckeepax, b.zolnierkie,
	sbkim73, patches, lgirdwood, krzk, robh+dt, Sylwester Nawrocki,
	linux-arm-kernel, m.szyprowski
In-Reply-To: <20190918104634.15216-1-s.nawrocki@samsung.com>

In case of WM1811 device there are currently being registered controls
referring to registers not existing on that device.
It has been noticed when getting values of "AIF1ADC2 Volume", "AIF1DAC2
Volume" controls was failing during ALSA state restoring at boot time:
 "amixer: Mixer hw:0 load error: Device or resource busy"

Reading some registers through I2C was failing with EBUSY error and indeed
those registers were not available according to the datasheet.

To fix this controls not available on WM1811 are moved to a separate array
and registered only for WM8994 and WM8958.

There are some further differences between WM8994 and WM1811, e.g. registers
603h, 604h, 605h, which are not covered in this patch.

Signed-off-by: Sylwester Nawrocki <s.nawrocki@samsung.com>
---
 sound/soc/codecs/wm8994.c | 43 +++++++++++++++++++++++----------------
 1 file changed, 26 insertions(+), 17 deletions(-)

diff --git a/sound/soc/codecs/wm8994.c b/sound/soc/codecs/wm8994.c
index c3d06e8bc54f..d5fb7f5dd551 100644
--- a/sound/soc/codecs/wm8994.c
+++ b/sound/soc/codecs/wm8994.c
@@ -533,13 +533,10 @@ static SOC_ENUM_SINGLE_DECL(dac_osr,
 static SOC_ENUM_SINGLE_DECL(adc_osr,
 			    WM8994_OVERSAMPLING, 1, osr_text);
 
-static const struct snd_kcontrol_new wm8994_snd_controls[] = {
+static const struct snd_kcontrol_new wm8994_common_snd_controls[] = {
 SOC_DOUBLE_R_TLV("AIF1ADC1 Volume", WM8994_AIF1_ADC1_LEFT_VOLUME,
 		 WM8994_AIF1_ADC1_RIGHT_VOLUME,
 		 1, 119, 0, digital_tlv),
-SOC_DOUBLE_R_TLV("AIF1ADC2 Volume", WM8994_AIF1_ADC2_LEFT_VOLUME,
-		 WM8994_AIF1_ADC2_RIGHT_VOLUME,
-		 1, 119, 0, digital_tlv),
 SOC_DOUBLE_R_TLV("AIF2ADC Volume", WM8994_AIF2_ADC_LEFT_VOLUME,
 		 WM8994_AIF2_ADC_RIGHT_VOLUME,
 		 1, 119, 0, digital_tlv),
@@ -556,8 +553,6 @@ SOC_ENUM("AIF2DACR Source", aif2dacr_src),
 
 SOC_DOUBLE_R_TLV("AIF1DAC1 Volume", WM8994_AIF1_DAC1_LEFT_VOLUME,
 		 WM8994_AIF1_DAC1_RIGHT_VOLUME, 1, 96, 0, digital_tlv),
-SOC_DOUBLE_R_TLV("AIF1DAC2 Volume", WM8994_AIF1_DAC2_LEFT_VOLUME,
-		 WM8994_AIF1_DAC2_RIGHT_VOLUME, 1, 96, 0, digital_tlv),
 SOC_DOUBLE_R_TLV("AIF2DAC Volume", WM8994_AIF2_DAC_LEFT_VOLUME,
 		 WM8994_AIF2_DAC_RIGHT_VOLUME, 1, 96, 0, digital_tlv),
 
@@ -565,17 +560,12 @@ SOC_SINGLE_TLV("AIF1 Boost Volume", WM8994_AIF1_CONTROL_2, 10, 3, 0, aif_tlv),
 SOC_SINGLE_TLV("AIF2 Boost Volume", WM8994_AIF2_CONTROL_2, 10, 3, 0, aif_tlv),
 
 SOC_SINGLE("AIF1DAC1 EQ Switch", WM8994_AIF1_DAC1_EQ_GAINS_1, 0, 1, 0),
-SOC_SINGLE("AIF1DAC2 EQ Switch", WM8994_AIF1_DAC2_EQ_GAINS_1, 0, 1, 0),
 SOC_SINGLE("AIF2 EQ Switch", WM8994_AIF2_EQ_GAINS_1, 0, 1, 0),
 
 WM8994_DRC_SWITCH("AIF1DAC1 DRC Switch", WM8994_AIF1_DRC1_1, 2),
 WM8994_DRC_SWITCH("AIF1ADC1L DRC Switch", WM8994_AIF1_DRC1_1, 1),
 WM8994_DRC_SWITCH("AIF1ADC1R DRC Switch", WM8994_AIF1_DRC1_1, 0),
 
-WM8994_DRC_SWITCH("AIF1DAC2 DRC Switch", WM8994_AIF1_DRC2_1, 2),
-WM8994_DRC_SWITCH("AIF1ADC2L DRC Switch", WM8994_AIF1_DRC2_1, 1),
-WM8994_DRC_SWITCH("AIF1ADC2R DRC Switch", WM8994_AIF1_DRC2_1, 0),
-
 WM8994_DRC_SWITCH("AIF2DAC DRC Switch", WM8994_AIF2_DRC_1, 2),
 WM8994_DRC_SWITCH("AIF2ADCL DRC Switch", WM8994_AIF2_DRC_1, 1),
 WM8994_DRC_SWITCH("AIF2ADCR DRC Switch", WM8994_AIF2_DRC_1, 0),
@@ -594,9 +584,6 @@ SOC_SINGLE("Sidetone HPF Switch", WM8994_SIDETONE, 6, 1, 0),
 SOC_ENUM("AIF1ADC1 HPF Mode", aif1adc1_hpf),
 SOC_DOUBLE("AIF1ADC1 HPF Switch", WM8994_AIF1_ADC1_FILTERS, 12, 11, 1, 0),
 
-SOC_ENUM("AIF1ADC2 HPF Mode", aif1adc2_hpf),
-SOC_DOUBLE("AIF1ADC2 HPF Switch", WM8994_AIF1_ADC2_FILTERS, 12, 11, 1, 0),
-
 SOC_ENUM("AIF2ADC HPF Mode", aif2adc_hpf),
 SOC_DOUBLE("AIF2ADC HPF Switch", WM8994_AIF2_ADC_FILTERS, 12, 11, 1, 0),
 
@@ -637,6 +624,24 @@ SOC_SINGLE("AIF2DAC 3D Stereo Switch", WM8994_AIF2_DAC_FILTERS_2,
 	   8, 1, 0),
 };
 
+/* Controls not available on WM1811 */
+static const struct snd_kcontrol_new wm8994_snd_controls[] = {
+SOC_DOUBLE_R_TLV("AIF1ADC2 Volume", WM8994_AIF1_ADC2_LEFT_VOLUME,
+		 WM8994_AIF1_ADC2_RIGHT_VOLUME,
+		 1, 119, 0, digital_tlv),
+SOC_DOUBLE_R_TLV("AIF1DAC2 Volume", WM8994_AIF1_DAC2_LEFT_VOLUME,
+		 WM8994_AIF1_DAC2_RIGHT_VOLUME, 1, 96, 0, digital_tlv),
+
+SOC_SINGLE("AIF1DAC2 EQ Switch", WM8994_AIF1_DAC2_EQ_GAINS_1, 0, 1, 0),
+
+WM8994_DRC_SWITCH("AIF1DAC2 DRC Switch", WM8994_AIF1_DRC2_1, 2),
+WM8994_DRC_SWITCH("AIF1ADC2L DRC Switch", WM8994_AIF1_DRC2_1, 1),
+WM8994_DRC_SWITCH("AIF1ADC2R DRC Switch", WM8994_AIF1_DRC2_1, 0),
+
+SOC_ENUM("AIF1ADC2 HPF Mode", aif1adc2_hpf),
+SOC_DOUBLE("AIF1ADC2 HPF Switch", WM8994_AIF1_ADC2_FILTERS, 12, 11, 1, 0),
+};
+
 static const struct snd_kcontrol_new wm8994_eq_controls[] = {
 SOC_SINGLE_TLV("AIF1DAC1 EQ1 Volume", WM8994_AIF1_DAC1_EQ_GAINS_1, 11, 31, 0,
 	       eq_tlv),
@@ -4258,13 +4263,15 @@ static int wm8994_component_probe(struct snd_soc_component *component)
 	wm8994_handle_pdata(wm8994);
 
 	wm_hubs_add_analogue_controls(component);
-	snd_soc_add_component_controls(component, wm8994_snd_controls,
-			     ARRAY_SIZE(wm8994_snd_controls));
+	snd_soc_add_component_controls(component, wm8994_common_snd_controls,
+				       ARRAY_SIZE(wm8994_common_snd_controls));
 	snd_soc_dapm_new_controls(dapm, wm8994_dapm_widgets,
 				  ARRAY_SIZE(wm8994_dapm_widgets));
 
 	switch (control->type) {
 	case WM8994:
+		snd_soc_add_component_controls(component, wm8994_snd_controls,
+					       ARRAY_SIZE(wm8994_snd_controls));
 		snd_soc_dapm_new_controls(dapm, wm8994_specific_dapm_widgets,
 					  ARRAY_SIZE(wm8994_specific_dapm_widgets));
 		if (control->revision < 4) {
@@ -4284,8 +4291,10 @@ static int wm8994_component_probe(struct snd_soc_component *component)
 		}
 		break;
 	case WM8958:
+		snd_soc_add_component_controls(component, wm8994_snd_controls,
+					       ARRAY_SIZE(wm8994_snd_controls));
 		snd_soc_add_component_controls(component, wm8958_snd_controls,
-				     ARRAY_SIZE(wm8958_snd_controls));
+					       ARRAY_SIZE(wm8958_snd_controls));
 		snd_soc_dapm_new_controls(dapm, wm8958_dapm_widgets,
 					  ARRAY_SIZE(wm8958_dapm_widgets));
 		if (control->revision < 1) {
-- 
2.17.1


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply related

* [PATCH v1 2/9] mfd: wm8994: Add support for MCLKn clock control
From: Sylwester Nawrocki @ 2019-09-18 10:46 UTC (permalink / raw)
  To: broonie
  Cc: devicetree, alsa-devel, linux-samsung-soc, ckeepax, b.zolnierkie,
	sbkim73, patches, lgirdwood, krzk, robh+dt, Sylwester Nawrocki,
	linux-arm-kernel, m.szyprowski
In-Reply-To: <20190918104634.15216-1-s.nawrocki@samsung.com>

The WM1811/WM8994/WM8958 audio CODEC DT bindings specify two optional
clocks: "MCLK1", "MCLK2". Add code for getting those clocks in the MFD
part of the wm8994 driver so they can be further handled in the audio
CODEC part.

Signed-off-by: Sylwester Nawrocki <s.nawrocki@samsung.com>
---
 drivers/mfd/wm8994-core.c       | 9 +++++++++
 include/linux/mfd/wm8994/core.h | 9 +++++++++
 2 files changed, 18 insertions(+)

diff --git a/drivers/mfd/wm8994-core.c b/drivers/mfd/wm8994-core.c
index 1e9fe7d92597..02c19a0bdeb0 100644
--- a/drivers/mfd/wm8994-core.c
+++ b/drivers/mfd/wm8994-core.c
@@ -7,6 +7,7 @@
  * Author: Mark Brown <broonie@opensource.wolfsonmicro.com>
  */
 
+#include <linux/clk.h>
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/slab.h>
@@ -333,6 +334,14 @@ static int wm8994_device_init(struct wm8994 *wm8994, int irq)
 
 	dev_set_drvdata(wm8994->dev, wm8994);
 
+	wm8994->mclk[WM8994_MCLK1].id = "MCLK1";
+	wm8994->mclk[WM8994_MCLK2].id = "MCLK2";
+
+	ret = devm_clk_bulk_get_optional(wm8994->dev, ARRAY_SIZE(wm8994->mclk),
+					 wm8994->mclk);
+	if (ret != 0)
+		return ret;
+
 	/* Add the on-chip regulators first for bootstrapping */
 	ret = mfd_add_devices(wm8994->dev, 0,
 			      wm8994_regulator_devs,
diff --git a/include/linux/mfd/wm8994/core.h b/include/linux/mfd/wm8994/core.h
index e8b093522ffd..320297a1b70c 100644
--- a/include/linux/mfd/wm8994/core.h
+++ b/include/linux/mfd/wm8994/core.h
@@ -10,12 +10,19 @@
 #ifndef __MFD_WM8994_CORE_H__
 #define __MFD_WM8994_CORE_H__
 
+#include <linux/clk.h>
 #include <linux/mutex.h>
 #include <linux/interrupt.h>
 #include <linux/regmap.h>
 
 #include <linux/mfd/wm8994/pdata.h>
 
+enum {
+	WM8994_MCLK1,
+	WM8994_MCLK2,
+	WM8994_NUM_MCLK
+};
+
 enum wm8994_type {
 	WM8994 = 0,
 	WM8958 = 1,
@@ -60,6 +67,8 @@ struct wm8994 {
 	struct device *dev;
 	struct regmap *regmap;
 
+	struct clk_bulk_data mclk[WM8994_NUM_MCLK];
+
 	bool ldo_ena_always_driven;
 
 	int gpio_base;
-- 
2.17.1


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply related

* [PATCH v1 3/9] ASoC: wm8994: Add support for setting MCLKn clock rate
From: Sylwester Nawrocki @ 2019-09-18 10:46 UTC (permalink / raw)
  To: broonie
  Cc: devicetree, alsa-devel, linux-samsung-soc, ckeepax, b.zolnierkie,
	sbkim73, patches, lgirdwood, krzk, robh+dt, Sylwester Nawrocki,
	linux-arm-kernel, m.szyprowski
In-Reply-To: <20190918104634.15216-1-s.nawrocki@samsung.com>

Extend the set_sysclk() handler so we also set frequency of the MCLK1,
MCLK2 clocks through clk API when those clocks are specified in DT for
the device.

Signed-off-by: Sylwester Nawrocki <s.nawrocki@samsung.com>
---
 sound/soc/codecs/wm8994.c | 30 +++++++++++++++++++++++++++++-
 1 file changed, 29 insertions(+), 1 deletion(-)

diff --git a/sound/soc/codecs/wm8994.c b/sound/soc/codecs/wm8994.c
index d5fb7f5dd551..b6b0842ae1fc 100644
--- a/sound/soc/codecs/wm8994.c
+++ b/sound/soc/codecs/wm8994.c
@@ -2372,12 +2372,30 @@ static int wm8994_set_fll(struct snd_soc_dai *dai, int id, int src,
 	return _wm8994_set_fll(dai->component, id, src, freq_in, freq_out);
 }
 
+static int wm8994_set_mclk_rate(struct wm8994_priv *wm8994, unsigned int id,
+				unsigned int *freq)
+{
+	struct wm8994 *control = wm8994->wm8994;
+	int ret;
+
+	if (!control->mclk[id].clk || *freq == wm8994->mclk[id])
+		return 0;
+
+	ret = clk_set_rate(control->mclk[id].clk, *freq);
+	if (ret < 0)
+		return ret;
+
+	*freq = clk_get_rate(control->mclk[id].clk);
+
+	return 0;
+}
+
 static int wm8994_set_dai_sysclk(struct snd_soc_dai *dai,
 		int clk_id, unsigned int freq, int dir)
 {
 	struct snd_soc_component *component = dai->component;
 	struct wm8994_priv *wm8994 = snd_soc_component_get_drvdata(component);
-	int i;
+	int ret, i;
 
 	switch (dai->id) {
 	case 1:
@@ -2392,6 +2410,11 @@ static int wm8994_set_dai_sysclk(struct snd_soc_dai *dai,
 	switch (clk_id) {
 	case WM8994_SYSCLK_MCLK1:
 		wm8994->sysclk[dai->id - 1] = WM8994_SYSCLK_MCLK1;
+
+		ret = wm8994_set_mclk_rate(wm8994, dai->id - 1, &freq);
+		if (ret < 0)
+			return ret;
+
 		wm8994->mclk[0] = freq;
 		dev_dbg(dai->dev, "AIF%d using MCLK1 at %uHz\n",
 			dai->id, freq);
@@ -2400,6 +2423,11 @@ static int wm8994_set_dai_sysclk(struct snd_soc_dai *dai,
 	case WM8994_SYSCLK_MCLK2:
 		/* TODO: Set GPIO AF */
 		wm8994->sysclk[dai->id - 1] = WM8994_SYSCLK_MCLK2;
+
+		ret = wm8994_set_mclk_rate(wm8994, dai->id - 1, &freq);
+		if (ret < 0)
+			return ret;
+
 		wm8994->mclk[1] = freq;
 		dev_dbg(dai->dev, "AIF%d using MCLK2 at %uHz\n",
 			dai->id, freq);
-- 
2.17.1


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply related

* [PATCH v1 4/9] ASoC: wm8994: Add support for MCLKn clock gating
From: Sylwester Nawrocki @ 2019-09-18 10:46 UTC (permalink / raw)
  To: broonie
  Cc: devicetree, alsa-devel, linux-samsung-soc, ckeepax, b.zolnierkie,
	sbkim73, patches, lgirdwood, krzk, robh+dt, Sylwester Nawrocki,
	linux-arm-kernel, m.szyprowski
In-Reply-To: <20190918104634.15216-1-s.nawrocki@samsung.com>

As an intermediate step before covering the clocking subsystem
of the CODEC entirely by the clk API add handling of external CODEC's
master clocks in DAPM events when the AIFn clocks are sourced directly
from MCLKn; when FLLn are used we enable/disable respective MCLKn
before/after FLLn is enabled/disabled.

Signed-off-by: Sylwester Nawrocki <s.nawrocki@samsung.com>
---
 sound/soc/codecs/wm8994.c | 91 +++++++++++++++++++++++++++++++++++++--
 1 file changed, 87 insertions(+), 4 deletions(-)

diff --git a/sound/soc/codecs/wm8994.c b/sound/soc/codecs/wm8994.c
index b6b0842ae1fc..bf02e8908d5a 100644
--- a/sound/soc/codecs/wm8994.c
+++ b/sound/soc/codecs/wm8994.c
@@ -1038,6 +1038,46 @@ static bool wm8994_check_class_w_digital(struct snd_soc_component *component)
 	return true;
 }
 
+static int aif_mclk_set(struct snd_soc_component *component, int aif, bool enable)
+{
+	struct wm8994_priv *wm8994 = snd_soc_component_get_drvdata(component);
+	struct wm8994 *control = wm8994->wm8994;
+	unsigned int offset, val, clk_idx;
+	int ret;
+
+	if (aif)
+		offset = 4;
+	else
+		offset = 0;
+
+	val = snd_soc_component_read32(component, WM8994_AIF1_CLOCKING_1 + offset);
+	val &= WM8994_AIF1CLK_SRC_MASK;
+
+	switch (val) {
+	case 0:
+		clk_idx = WM8994_MCLK1;
+		break;
+	case 1:
+		clk_idx = WM8994_MCLK2;
+		break;
+	default:
+		return 0;
+	}
+
+	if (enable) {
+		ret = clk_prepare_enable(control->mclk[clk_idx].clk);
+		if (ret < 0) {
+			dev_err(component->dev,	"Failed to enable MCLK%d\n",
+				clk_idx);
+			return ret;
+		}
+	} else {
+		clk_disable_unprepare(control->mclk[clk_idx].clk);
+	}
+
+	return 0;
+}
+
 static int aif1clk_ev(struct snd_soc_dapm_widget *w,
 		      struct snd_kcontrol *kcontrol, int event)
 {
@@ -1045,7 +1085,7 @@ static int aif1clk_ev(struct snd_soc_dapm_widget *w,
 	struct wm8994_priv *wm8994 = snd_soc_component_get_drvdata(component);
 	struct wm8994 *control = wm8994->wm8994;
 	int mask = WM8994_AIF1DAC1L_ENA | WM8994_AIF1DAC1R_ENA;
-	int i;
+	int ret, i;
 	int dac;
 	int adc;
 	int val;
@@ -1061,6 +1101,10 @@ static int aif1clk_ev(struct snd_soc_dapm_widget *w,
 
 	switch (event) {
 	case SND_SOC_DAPM_PRE_PMU:
+		ret = aif_mclk_set(component, 0, true);
+		if (ret < 0)
+			return ret;
+
 		/* Don't enable timeslot 2 if not in use */
 		if (wm8994->channels[0] <= 2)
 			mask &= ~(WM8994_AIF1DAC2L_ENA | WM8994_AIF1DAC2R_ENA);
@@ -1133,6 +1177,12 @@ static int aif1clk_ev(struct snd_soc_dapm_widget *w,
 		break;
 	}
 
+	switch (event) {
+	case SND_SOC_DAPM_POST_PMD:
+		aif_mclk_set(component, 0, false);
+		break;
+	}
+
 	return 0;
 }
 
@@ -1140,13 +1190,17 @@ static int aif2clk_ev(struct snd_soc_dapm_widget *w,
 		      struct snd_kcontrol *kcontrol, int event)
 {
 	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
-	int i;
+	int ret, i;
 	int dac;
 	int adc;
 	int val;
 
 	switch (event) {
 	case SND_SOC_DAPM_PRE_PMU:
+		ret = aif_mclk_set(component, 1, true);
+		if (ret < 0)
+			return ret;
+
 		val = snd_soc_component_read32(component, WM8994_AIF2_CONTROL_1);
 		if ((val & WM8994_AIF2ADCL_SRC) &&
 		    (val & WM8994_AIF2ADCR_SRC))
@@ -1218,6 +1272,12 @@ static int aif2clk_ev(struct snd_soc_dapm_widget *w,
 		break;
 	}
 
+	switch (event) {
+	case SND_SOC_DAPM_POST_PMD:
+		aif_mclk_set(component, 1, false);
+		break;
+	}
+
 	return 0;
 }
 
@@ -1623,10 +1683,10 @@ SND_SOC_DAPM_POST("Late Disable PGA", late_disable_ev)
 static const struct snd_soc_dapm_widget wm8994_lateclk_widgets[] = {
 SND_SOC_DAPM_SUPPLY("AIF1CLK", WM8994_AIF1_CLOCKING_1, 0, 0, aif1clk_ev,
 		    SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
-		    SND_SOC_DAPM_PRE_PMD),
+		    SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
 SND_SOC_DAPM_SUPPLY("AIF2CLK", WM8994_AIF2_CLOCKING_1, 0, 0, aif2clk_ev,
 		    SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
-		    SND_SOC_DAPM_PRE_PMD),
+		    SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
 SND_SOC_DAPM_PGA("Direct Voice", SND_SOC_NOPM, 0, 0, NULL, 0),
 SND_SOC_DAPM_MIXER("SPKL", WM8994_POWER_MANAGEMENT_3, 8, 0,
 		   left_speaker_mixer, ARRAY_SIZE(left_speaker_mixer)),
@@ -2141,6 +2201,7 @@ static int _wm8994_set_fll(struct snd_soc_component *component, int id, int src,
 	u16 reg, clk1, aif_reg, aif_src;
 	unsigned long timeout;
 	bool was_enabled;
+	struct clk *mclk;
 
 	switch (id) {
 	case WM8994_FLL1:
@@ -2260,8 +2321,28 @@ static int _wm8994_set_fll(struct snd_soc_component *component, int id, int src,
 	/* Clear any pending completion from a previous failure */
 	try_wait_for_completion(&wm8994->fll_locked[id]);
 
+	switch (src) {
+	case WM8994_FLL_SRC_MCLK1:
+		mclk = control->mclk[0].clk;
+		break;
+	case WM8994_FLL_SRC_MCLK2:
+		mclk = control->mclk[1].clk;
+		break;
+	default:
+		mclk = NULL;
+	}
+
 	/* Enable (with fractional mode if required) */
 	if (freq_out) {
+		if (mclk) {
+			ret = clk_prepare_enable(mclk);
+			if (ret < 0) {
+				dev_err(component->dev,
+					"Failed to enable MCLK for FLL%d\n",
+					id + 1);
+				return ret;
+			}
+		}
 		/* Enable VMID if we need it */
 		if (!was_enabled) {
 			active_reference(component);
@@ -2315,6 +2396,8 @@ static int _wm8994_set_fll(struct snd_soc_component *component, int id, int src,
 
 			active_dereference(component);
 		}
+		if (mclk)
+			clk_disable_unprepare(mclk);
 	}
 
 out:
-- 
2.17.1


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply related

* [PATCH v1 6/9] ASoC: dt-bindings: Document "samsung,arndale-wm1811" compatible
From: Sylwester Nawrocki @ 2019-09-18 10:46 UTC (permalink / raw)
  To: broonie
  Cc: devicetree, alsa-devel, linux-samsung-soc, ckeepax, b.zolnierkie,
	sbkim73, patches, lgirdwood, krzk, robh+dt, Sylwester Nawrocki,
	linux-arm-kernel, m.szyprowski
In-Reply-To: <20190918104634.15216-1-s.nawrocki@samsung.com>

Add compatible string for boards with WM1811 CODEC to the list.

Signed-off-by: Sylwester Nawrocki <s.nawrocki@samsung.com>
---
 Documentation/devicetree/bindings/sound/arndale.txt | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)

diff --git a/Documentation/devicetree/bindings/sound/arndale.txt b/Documentation/devicetree/bindings/sound/arndale.txt
index 0e76946385ae..17530120ccfc 100644
--- a/Documentation/devicetree/bindings/sound/arndale.txt
+++ b/Documentation/devicetree/bindings/sound/arndale.txt
@@ -1,8 +1,9 @@
 Audio Binding for Arndale boards
 
 Required properties:
-- compatible : Can be the following,
-			"samsung,arndale-rt5631"
+- compatible : Can be one of the following:
+		"samsung,arndale-rt5631",
+		"samsung,arndale-wm1811"
 
 - samsung,audio-cpu: The phandle of the Samsung I2S controller
 - samsung,audio-codec: The phandle of the audio codec
-- 
2.17.1


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply related

* [PATCH v1 7/9] ASoC: samsung: arndale: Add support for WM1811 CODEC
From: Sylwester Nawrocki @ 2019-09-18 10:46 UTC (permalink / raw)
  To: broonie
  Cc: devicetree, alsa-devel, linux-samsung-soc, ckeepax, b.zolnierkie,
	sbkim73, patches, lgirdwood, krzk, robh+dt, Sylwester Nawrocki,
	linux-arm-kernel, m.szyprowski
In-Reply-To: <20190918104634.15216-1-s.nawrocki@samsung.com>

The Arndale boards come with different types of the audio daughter
board.  In order to support the WM1811 one we add new definition of
an ASoC card which will be registered when the driver matches on
"samsung,arndale-wm1811" compatible.  There is no runtime detection of
the audio daughter board type at the moment, compatible string of the
audio card needs to be adjusted in DT, e.g. by the bootloader,
depending on actual audio board (CODEC) used.

Signed-off-by: Sylwester Nawrocki <s.nawrocki@samsung.com>
---
 sound/soc/samsung/arndale_rt5631.c | 86 +++++++++++++++++++++++++-----
 1 file changed, 73 insertions(+), 13 deletions(-)

diff --git a/sound/soc/samsung/arndale_rt5631.c b/sound/soc/samsung/arndale_rt5631.c
index c5c8e3b5772f..3744c47742b8 100644
--- a/sound/soc/samsung/arndale_rt5631.c
+++ b/sound/soc/samsung/arndale_rt5631.c
@@ -5,6 +5,7 @@
 //  Author: Claude <claude@insginal.co.kr>
 
 #include <linux/module.h>
+#include <linux/of_device.h>
 #include <linux/platform_device.h>
 #include <linux/clk.h>
 
@@ -13,10 +14,11 @@
 #include <sound/pcm.h>
 #include <sound/pcm_params.h>
 
+#include "../codecs/wm8994.h"
 #include "i2s.h"
 
-static int arndale_hw_params(struct snd_pcm_substream *substream,
-	struct snd_pcm_hw_params *params)
+static int arndale_rt5631_hw_params(struct snd_pcm_substream *substream,
+				    struct snd_pcm_hw_params *params)
 {
 	struct snd_soc_pcm_runtime *rtd = substream->private_data;
 	struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
@@ -46,13 +48,45 @@ static int arndale_hw_params(struct snd_pcm_substream *substream,
 	return 0;
 }
 
-static struct snd_soc_ops arndale_ops = {
-	.hw_params = arndale_hw_params,
+static struct snd_soc_ops arndale_rt5631_ops = {
+	.hw_params = arndale_rt5631_hw_params,
+};
+
+static int arndale_wm1811_hw_params(struct snd_pcm_substream *substream,
+				    struct snd_pcm_hw_params *params)
+{
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct snd_soc_dai *codec_dai = rtd->codec_dai;
+	unsigned int rfs, rclk;
+
+	/* Ensure AIF1CLK is >= 3 MHz for optimal performance */
+	if (params_width(params) == 24)
+		rfs = 384;
+	else if (params_rate(params) == 8000 || params_rate(params) == 11025)
+		rfs = 512;
+	else
+		rfs = 256;
+
+	rclk = params_rate(params) * rfs;
+
+	/*
+	 * We add 1 to the frequency value to ensure proper EPLL setting
+	 * for each audio sampling rate (see epll_24mhz_tbl in drivers/clk/
+	 * samsung/clk-exynos5250.c for list of available EPLL rates).
+	 * The CODEC uses clk API and the value will be rounded hence the MCLK1
+	 * clock's frequency will still be exact multiple of the sample rate.
+	 */
+	return snd_soc_dai_set_sysclk(codec_dai, WM8994_SYSCLK_MCLK1,
+					rclk + 1, SND_SOC_CLOCK_IN);
+}
+
+static struct snd_soc_ops arndale_wm1811_ops = {
+	.hw_params = arndale_wm1811_hw_params,
 };
 
 SND_SOC_DAILINK_DEFS(rt5631_hifi,
 	DAILINK_COMP_ARRAY(COMP_EMPTY()),
-	DAILINK_COMP_ARRAY(COMP_CODEC(NULL, "rt5631-hifi")),
+	DAILINK_COMP_ARRAY(COMP_CODEC(NULL, "rt5631-aif1")),
 	DAILINK_COMP_ARRAY(COMP_EMPTY()));
 
 static struct snd_soc_dai_link arndale_rt5631_dai[] = {
@@ -62,11 +96,28 @@ static struct snd_soc_dai_link arndale_rt5631_dai[] = {
 		.dai_fmt = SND_SOC_DAIFMT_I2S
 			| SND_SOC_DAIFMT_NB_NF
 			| SND_SOC_DAIFMT_CBS_CFS,
-		.ops = &arndale_ops,
+		.ops = &arndale_rt5631_ops,
 		SND_SOC_DAILINK_REG(rt5631_hifi),
 	},
 };
 
+SND_SOC_DAILINK_DEFS(wm1811_hifi,
+	DAILINK_COMP_ARRAY(COMP_EMPTY()),
+	DAILINK_COMP_ARRAY(COMP_CODEC(NULL, "wm8994-aif1")),
+	DAILINK_COMP_ARRAY(COMP_EMPTY()));
+
+static struct snd_soc_dai_link arndale_wm1811_dai[] = {
+	{
+		.name = "WM1811 HiFi",
+		.stream_name = "Primary",
+		.dai_fmt = SND_SOC_DAIFMT_I2S
+			| SND_SOC_DAIFMT_NB_NF
+			| SND_SOC_DAIFMT_CBM_CFM,
+		.ops = &arndale_wm1811_ops,
+		SND_SOC_DAILINK_REG(wm1811_hifi),
+	},
+};
+
 static struct snd_soc_card arndale_rt5631 = {
 	.name = "Arndale RT5631",
 	.owner = THIS_MODULE,
@@ -74,13 +125,21 @@ static struct snd_soc_card arndale_rt5631 = {
 	.num_links = ARRAY_SIZE(arndale_rt5631_dai),
 };
 
+static struct snd_soc_card arndale_wm1811 = {
+	.name = "Arndale WM1811",
+	.owner = THIS_MODULE,
+	.dai_link = arndale_wm1811_dai,
+	.num_links = ARRAY_SIZE(arndale_wm1811_dai),
+};
+
 static int arndale_audio_probe(struct platform_device *pdev)
 {
 	struct device_node *np = pdev->dev.of_node;
-	struct snd_soc_card *card = &arndale_rt5631;
+	struct snd_soc_card *card;
 	struct snd_soc_dai_link *dai_link;
 	int ret;
 
+	card = (struct snd_soc_card *)of_device_get_match_data(&pdev->dev);
 	card->dev = &pdev->dev;
 	dai_link = card->dai_link;
 
@@ -107,18 +166,19 @@ static int arndale_audio_probe(struct platform_device *pdev)
 	return ret;
 }
 
-static const struct of_device_id samsung_arndale_rt5631_of_match[] __maybe_unused = {
-	{ .compatible = "samsung,arndale-rt5631", },
-	{ .compatible = "samsung,arndale-alc5631", },
+static const struct of_device_id arndale_audio_of_match[] __maybe_unused = {
+	{ .compatible = "samsung,arndale-rt5631",  .data = &arndale_rt5631 },
+	{ .compatible = "samsung,arndale-alc5631", .data = &arndale_rt5631 },
+	{ .compatible = "samsung,arndale-wm1811",  .data = &arndale_wm1811 },
 	{},
 };
-MODULE_DEVICE_TABLE(of, samsung_arndale_rt5631_of_match);
+MODULE_DEVICE_TABLE(of, arndale_of_match);
 
 static struct platform_driver arndale_audio_driver = {
 	.driver = {
-		.name   = "arndale-audio",
+		.name = "arndale-audio",
 		.pm = &snd_soc_pm_ops,
-		.of_match_table = of_match_ptr(samsung_arndale_rt5631_of_match),
+		.of_match_table = arndale_audio_of_match,
 	},
 	.probe = arndale_audio_probe,
 };
-- 
2.17.1


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply related

* [PATCH v1 5/9] ASoC: samsung: arndale: Simplify DAI link initialization
From: Sylwester Nawrocki @ 2019-09-18 10:46 UTC (permalink / raw)
  To: broonie
  Cc: devicetree, alsa-devel, linux-samsung-soc, ckeepax, b.zolnierkie,
	sbkim73, patches, lgirdwood, krzk, robh+dt, Sylwester Nawrocki,
	linux-arm-kernel, m.szyprowski
In-Reply-To: <20190918104634.15216-1-s.nawrocki@samsung.com>

There is only one DAI link so we can drop an unnecessary loop statement.
Use card->dai_link in place of direct static arndale_rt5631_dai[] array
dereference as a prerequisite for adding support for other CODECs.
Unnecessary assignment of dai_link->codecs->name to NULL is removed.

Signed-off-by: Sylwester Nawrocki <s.nawrocki@samsung.com>
---
 sound/soc/samsung/arndale_rt5631.c | 42 ++++++++++++------------------
 1 file changed, 17 insertions(+), 25 deletions(-)

diff --git a/sound/soc/samsung/arndale_rt5631.c b/sound/soc/samsung/arndale_rt5631.c
index c213913eb984..c5c8e3b5772f 100644
--- a/sound/soc/samsung/arndale_rt5631.c
+++ b/sound/soc/samsung/arndale_rt5631.c
@@ -76,41 +76,33 @@ static struct snd_soc_card arndale_rt5631 = {
 
 static int arndale_audio_probe(struct platform_device *pdev)
 {
-	int n, ret;
 	struct device_node *np = pdev->dev.of_node;
 	struct snd_soc_card *card = &arndale_rt5631;
+	struct snd_soc_dai_link *dai_link;
+	int ret;
 
 	card->dev = &pdev->dev;
+	dai_link = card->dai_link;
 
-	for (n = 0; np && n < ARRAY_SIZE(arndale_rt5631_dai); n++) {
-		if (!arndale_rt5631_dai[n].cpus->dai_name) {
-			arndale_rt5631_dai[n].cpus->of_node = of_parse_phandle(np,
-					"samsung,audio-cpu", n);
-
-			if (!arndale_rt5631_dai[n].cpus->of_node) {
-				dev_err(&pdev->dev,
-				"Property 'samsung,audio-cpu' missing or invalid\n");
-				return -EINVAL;
-			}
-		}
-		if (!arndale_rt5631_dai[n].platforms->name)
-			arndale_rt5631_dai[n].platforms->of_node =
-					arndale_rt5631_dai[n].cpus->of_node;
-
-		arndale_rt5631_dai[n].codecs->name = NULL;
-		arndale_rt5631_dai[n].codecs->of_node = of_parse_phandle(np,
-					"samsung,audio-codec", n);
-		if (!arndale_rt5631_dai[0].codecs->of_node) {
-			dev_err(&pdev->dev,
-			"Property 'samsung,audio-codec' missing or invalid\n");
+	dai_link->cpus->of_node = of_parse_phandle(np, "samsung,audio-cpu", 0);
+	if (!dai_link->cpus->of_node) {
+		dev_err(&pdev->dev, "Property 'samsung,audio-cpu' missing or invalid\n");
 			return -EINVAL;
-		}
 	}
 
-	ret = devm_snd_soc_register_card(card->dev, card);
+	if (!dai_link->platforms->name)
+		dai_link->platforms->of_node = dai_link->cpus->of_node;
+
+	dai_link->codecs->of_node = of_parse_phandle(np, "samsung,audio-codec", 0);
+	if (!dai_link->codecs->of_node) {
+		dev_err(&pdev->dev,
+			"Property 'samsung,audio-codec' missing or invalid\n");
+		return -EINVAL;
+	}
 
+	ret = devm_snd_soc_register_card(card->dev, card);
 	if (ret)
-		dev_err(&pdev->dev, "snd_soc_register_card() failed:%d\n", ret);
+		dev_err(&pdev->dev, "snd_soc_register_card() failed: %d\n", ret);
 
 	return ret;
 }
-- 
2.17.1


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply related

* [PATCH v1 9/9] ARM: dts: arndale: Add audio support (WM1811 CODEC boards)
From: Sylwester Nawrocki @ 2019-09-18 10:46 UTC (permalink / raw)
  To: broonie
  Cc: devicetree, alsa-devel, linux-samsung-soc, ckeepax, b.zolnierkie,
	sbkim73, patches, lgirdwood, krzk, robh+dt, Sylwester Nawrocki,
	linux-arm-kernel, m.szyprowski
In-Reply-To: <20190918104634.15216-1-s.nawrocki@samsung.com>

Add sound node and the clock configurations for the I2S controller
for audio support on the Exynos5250 SoC Arndale boards with
WM1811 based audio daugther board.

We need to increase drive strength of the I2S bus, otherwise
the audio CODEC doesn't work. Likely the CODEC's master clock
is the main issue here.

Signed-off-by: Sylwester Nawrocki <s.nawrocki@samsung.com>
---
 arch/arm/boot/dts/exynos5250-arndale.dts | 27 +++++++++++++++++++++++-
 1 file changed, 26 insertions(+), 1 deletion(-)

diff --git a/arch/arm/boot/dts/exynos5250-arndale.dts b/arch/arm/boot/dts/exynos5250-arndale.dts
index dc6fa6fe83f1..62aa6720aa88 100644
--- a/arch/arm/boot/dts/exynos5250-arndale.dts
+++ b/arch/arm/boot/dts/exynos5250-arndale.dts
@@ -11,6 +11,7 @@
 #include <dt-bindings/interrupt-controller/irq.h>
 #include <dt-bindings/input/input.h>
 #include <dt-bindings/clock/samsung,s2mps11.h>
+#include <dt-bindings/sound/samsung-i2s.h>
 #include "exynos5250.dtsi"
 
 / {
@@ -135,6 +136,12 @@
 		};
 	};
 
+	sound {
+		compatible = "samsung,arndale-wm1811";
+		samsung,audio-cpu = <&i2s0>;
+		samsung,audio-codec = <&wm1811>;
+	};
+
 	fixed-rate-clocks {
 		xxti {
 			compatible = "samsung,clock-xxti";
@@ -499,12 +506,24 @@
 	};
 };
 
+&clock {
+	assigned-clocks = <&clock CLK_FOUT_EPLL>;
+	assigned-clock-rates = <49152000>;
+};
+
+&clock_audss {
+	assigned-clocks = <&clock_audss EXYNOS_MOUT_AUDSS>;
+	assigned-clock-parents = <&clock CLK_FOUT_EPLL>;
+};
+
 &i2c_3 {
 	status = "okay";
 
-	wm1811a@1a {
+	wm1811: codec@1a {
 		compatible = "wlf,wm1811";
 		reg = <0x1a>;
+		clocks = <&i2s0 CLK_I2S_CDCLK>;
+		clock-names = "MCLK1";
 
 		AVDD2-supply = <&main_dc_reg>;
 		CPVDD-supply = <&main_dc_reg>;
@@ -540,9 +559,15 @@
 };
 
 &i2s0 {
+	assigned-clocks = <&i2s0 CLK_I2S_RCLK_SRC>;
+	assigned-clock-parents = <&clock_audss EXYNOS_I2S_BUS>;
 	status = "okay";
 };
 
+&i2s0_bus {
+	samsung,pin-drv = <EXYNOS4_PIN_DRV_LV2>;
+};
+
 &mixer {
 	status = "okay";
 };
-- 
2.17.1


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply related

* [PATCH v1 8/9] ASoC: samsung: arndale: Add missing OF node dereferencing
From: Sylwester Nawrocki @ 2019-09-18 10:46 UTC (permalink / raw)
  To: broonie
  Cc: devicetree, alsa-devel, linux-samsung-soc, ckeepax, b.zolnierkie,
	sbkim73, patches, lgirdwood, krzk, robh+dt, Sylwester Nawrocki,
	linux-arm-kernel, m.szyprowski
In-Reply-To: <20190918104634.15216-1-s.nawrocki@samsung.com>

Ensure there is no OF node references kept when the driver is removed/unbound.

Signed-off-by: Sylwester Nawrocki <s.nawrocki@samsung.com>
---
 sound/soc/samsung/arndale_rt5631.c | 31 ++++++++++++++++++++++++++++--
 1 file changed, 29 insertions(+), 2 deletions(-)

diff --git a/sound/soc/samsung/arndale_rt5631.c b/sound/soc/samsung/arndale_rt5631.c
index 3744c47742b8..d8da313e898a 100644
--- a/sound/soc/samsung/arndale_rt5631.c
+++ b/sound/soc/samsung/arndale_rt5631.c
@@ -132,6 +132,17 @@ static struct snd_soc_card arndale_wm1811 = {
 	.num_links = ARRAY_SIZE(arndale_wm1811_dai),
 };
 
+static void arndale_put_of_nodes(struct snd_soc_card *card)
+{
+	struct snd_soc_dai_link *dai_link;
+	int i;
+
+	for_each_card_prelinks(card, i, dai_link) {
+		of_node_put(dai_link->cpus->of_node);
+		of_node_put(dai_link->codecs->of_node);
+	}
+}
+
 static int arndale_audio_probe(struct platform_device *pdev)
 {
 	struct device_node *np = pdev->dev.of_node;
@@ -156,16 +167,31 @@ static int arndale_audio_probe(struct platform_device *pdev)
 	if (!dai_link->codecs->of_node) {
 		dev_err(&pdev->dev,
 			"Property 'samsung,audio-codec' missing or invalid\n");
-		return -EINVAL;
+		ret = -EINVAL;
+		goto err_put_of_nodes;
 	}
 
 	ret = devm_snd_soc_register_card(card->dev, card);
-	if (ret)
+	if (ret) {
 		dev_err(&pdev->dev, "snd_soc_register_card() failed: %d\n", ret);
+		goto err_put_of_nodes;
+	}
 
+	return 0;
+
+err_put_of_nodes:
+	arndale_put_of_nodes(card);
 	return ret;
 }
 
+static int arndale_audio_remove(struct platform_device *pdev)
+{
+	struct snd_soc_card *card = platform_get_drvdata(pdev);
+
+	arndale_put_of_nodes(card);
+	return 0;
+}
+
 static const struct of_device_id arndale_audio_of_match[] __maybe_unused = {
 	{ .compatible = "samsung,arndale-rt5631",  .data = &arndale_rt5631 },
 	{ .compatible = "samsung,arndale-alc5631", .data = &arndale_rt5631 },
@@ -181,6 +207,7 @@ static struct platform_driver arndale_audio_driver = {
 		.of_match_table = arndale_audio_of_match,
 	},
 	.probe = arndale_audio_probe,
+	.remove = arndale_audio_remove,
 };
 
 module_platform_driver(arndale_audio_driver);
-- 
2.17.1


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply related

* Re: [PATCH] mfd: mt6360: add pmic mt6360 driver
From: Lee Jones @ 2019-09-18 10:51 UTC (permalink / raw)
  To: Gene Chen
  Cc: gene_chen, linux-kernel, linux-mediatek, matthias.bgg, Wilma.Wu,
	linux-arm-kernel, shufan_lee
In-Reply-To: <1568801744-21380-1-git-send-email-gene.chen.richtek@gmail.com>

On Wed, 18 Sep 2019, Gene Chen wrote:

> From: Gene Chen <gene_chen@richtek.com>
> 
> Add mfd driver for mt6360 pmic chip include
> Battery Charger/USB_PD/Flash LED/RGB LED/LDO/Buck
> 
> Signed-off-by: Gene Chen <gene_chen@richtek.com
> ---

This looks different from the one you sent before, but I don't see a
version bump or any changelog in this space.  Please re-submit with
the differences noted.

>  drivers/mfd/Kconfig                |  12 +
>  drivers/mfd/Makefile               |   1 +
>  drivers/mfd/mt6360-core.c          | 463 +++++++++++++++++++++++++++++++++++++
>  include/linux/mfd/mt6360-private.h | 279 ++++++++++++++++++++++
>  include/linux/mfd/mt6360.h         |  33 +++
>  5 files changed, 788 insertions(+)
>  create mode 100644 drivers/mfd/mt6360-core.c
>  create mode 100644 include/linux/mfd/mt6360-private.h
>  create mode 100644 include/linux/mfd/mt6360.h

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

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply

* Re: [PATCH v1 2/9] mfd: wm8994: Add support for MCLKn clock control
From: Sylwester Nawrocki @ 2019-09-18 10:59 UTC (permalink / raw)
  To: broonie
  Cc: devicetree, alsa-devel, linux-samsung-soc, ckeepax, b.zolnierkie,
	sbkim73, patches, lgirdwood, krzk, robh+dt, lee.jones,
	linux-arm-kernel, m.szyprowski
In-Reply-To: <20190918104634.15216-3-s.nawrocki@samsung.com>

Cc: lee.jones@linaro.org

Excuse me Lee, I forgot to Cc entire series to you, will do it in case
of posting v2.

On 9/18/19 12:46, Sylwester Nawrocki wrote:
> The WM1811/WM8994/WM8958 audio CODEC DT bindings specify two optional
> clocks: "MCLK1", "MCLK2". Add code for getting those clocks in the MFD
> part of the wm8994 driver so they can be further handled in the audio
> CODEC part.
> 
> Signed-off-by: Sylwester Nawrocki <s.nawrocki@samsung.com>
> ---
>  drivers/mfd/wm8994-core.c       | 9 +++++++++
>  include/linux/mfd/wm8994/core.h | 9 +++++++++
>  2 files changed, 18 insertions(+)
> 
> diff --git a/drivers/mfd/wm8994-core.c b/drivers/mfd/wm8994-core.c
> index 1e9fe7d92597..02c19a0bdeb0 100644
> --- a/drivers/mfd/wm8994-core.c
> +++ b/drivers/mfd/wm8994-core.c
> @@ -7,6 +7,7 @@
>   * Author: Mark Brown <broonie@opensource.wolfsonmicro.com>
>   */
>  
> +#include <linux/clk.h>
>  #include <linux/kernel.h>
>  #include <linux/module.h>
>  #include <linux/slab.h>
> @@ -333,6 +334,14 @@ static int wm8994_device_init(struct wm8994 *wm8994, int irq)
>  
>  	dev_set_drvdata(wm8994->dev, wm8994);
>  
> +	wm8994->mclk[WM8994_MCLK1].id = "MCLK1";
> +	wm8994->mclk[WM8994_MCLK2].id = "MCLK2";
> +
> +	ret = devm_clk_bulk_get_optional(wm8994->dev, ARRAY_SIZE(wm8994->mclk),
> +					 wm8994->mclk);
> +	if (ret != 0)
> +		return ret;
> +
>  	/* Add the on-chip regulators first for bootstrapping */
>  	ret = mfd_add_devices(wm8994->dev, 0,
>  			      wm8994_regulator_devs,
> diff --git a/include/linux/mfd/wm8994/core.h b/include/linux/mfd/wm8994/core.h
> index e8b093522ffd..320297a1b70c 100644
> --- a/include/linux/mfd/wm8994/core.h
> +++ b/include/linux/mfd/wm8994/core.h
> @@ -10,12 +10,19 @@
>  #ifndef __MFD_WM8994_CORE_H__
>  #define __MFD_WM8994_CORE_H__
>  
> +#include <linux/clk.h>
>  #include <linux/mutex.h>
>  #include <linux/interrupt.h>
>  #include <linux/regmap.h>
>  
>  #include <linux/mfd/wm8994/pdata.h>
>  
> +enum {
> +	WM8994_MCLK1,
> +	WM8994_MCLK2,
> +	WM8994_NUM_MCLK
> +};
> +
>  enum wm8994_type {
>  	WM8994 = 0,
>  	WM8958 = 1,
> @@ -60,6 +67,8 @@ struct wm8994 {
>  	struct device *dev;
>  	struct regmap *regmap;
>  
> +	struct clk_bulk_data mclk[WM8994_NUM_MCLK];
> +
>  	bool ldo_ena_always_driven;
>  
>  	int gpio_base;
 -- 
Regards,
Sylwester

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply

* Re: [PATCH v6 01/11] kselftest: arm64: extend toplevel skeleton Makefile
From: Cristian Marussi @ 2019-09-18 10:59 UTC (permalink / raw)
  To: shuah, Dave Martin
  Cc: amit.kachhap, andreyknvl, linux-arm-kernel, linux-kselftest
In-Reply-To: <119aaea7-10b5-0fdf-269d-e86df07b4831@kernel.org>

On 17/09/2019 17:18, shuah wrote:
> On 9/17/19 10:05 AM, Dave Martin wrote:
>> On Tue, Sep 10, 2019 at 01:31:01pm +0100, Cristian Marussi wrote:
>>> Modify KSFT arm64 toplevel Makefile to maintain arm64 kselftests organized
>>> by subsystem, keeping them into distinct subdirectories under arm64 custom
>>> KSFT directory: tools/testing/selftests/arm64/
>>>
>>> Add to such toplevel Makefile a mechanism to guess the effective location
>>> of Kernel headers as installed by KSFT framework.
>>>
>>> Fit existing arm64 tags kselftest into this new schema moving them into
>>> their own subdirectory (arm64/tags).
>>>
>>> Signed-off-by: Cristian Marussi <cristian.marussi@arm.com>
>>> ---
>>> Based on:
>>> commit 9ce1263033cd ("selftests, arm64: add a selftest for passing
>>> 		     tagged pointers to kernel")
>>> ---
>>> v5 --> v6
>>> - using realpath to avoid passing down relative paths
>>> - fix commit msg & Copyright
>>> - removed unneded Makefile export
>>> - added SUBTARGETS specification, to allow building specific only some
>>>    arm64 test subsystems
>>> v4 --> v5
>>> - rebased on arm64/for-next/core
>>> - merged this patch with KSFT arm64 tags patch, while moving the latter
>>>    into its own subdir
>>> - moved kernel header includes search mechanism from KSFT arm64
>>>    SIGNAL Makefile
>>> - export proper top_srcdir ENV for lib.mk
>>> v3 --> v4
>>> - comment reword
>>> - simplified documentation in README
>>> - dropped README about standalone
>>> ---
>>>   tools/testing/selftests/Makefile              |  1 +
>>>   tools/testing/selftests/arm64/Makefile        | 63 +++++++++++++++++--
>>>   tools/testing/selftests/arm64/README          | 25 ++++++++
>>>   tools/testing/selftests/arm64/tags/Makefile   |  6 ++
>>>   .../arm64/{ => tags}/run_tags_test.sh         |  0
>>>   .../selftests/arm64/{ => tags}/tags_test.c    |  0
>>>   6 files changed, 91 insertions(+), 4 deletions(-)
>>>   create mode 100644 tools/testing/selftests/arm64/README
>>>   create mode 100644 tools/testing/selftests/arm64/tags/Makefile
>>>   rename tools/testing/selftests/arm64/{ => tags}/run_tags_test.sh (100%)
>>>   rename tools/testing/selftests/arm64/{ => tags}/tags_test.c (100%)
>>>
>>> diff --git a/tools/testing/selftests/Makefile b/tools/testing/selftests/Makefile
>>> index 25b43a8c2b15..1722dae9381a 100644
>>> --- a/tools/testing/selftests/Makefile
>>> +++ b/tools/testing/selftests/Makefile
>>> @@ -1,5 +1,6 @@
>>>   # SPDX-License-Identifier: GPL-2.0
>>>   TARGETS = android
>>> +TARGETS += arm64
>>>   TARGETS += bpf
>>>   TARGETS += breakpoints
>>>   TARGETS += capabilities
>>> diff --git a/tools/testing/selftests/arm64/Makefile b/tools/testing/selftests/arm64/Makefile
>>> index a61b2e743e99..cbb2a5a9e3fc 100644
>>> --- a/tools/testing/selftests/arm64/Makefile
>>> +++ b/tools/testing/selftests/arm64/Makefile
>>> @@ -1,11 +1,66 @@
>>>   # SPDX-License-Identifier: GPL-2.0
>>>   
>>> -# ARCH can be overridden by the user for cross compiling
>>> +# When ARCH not overridden for crosscompiling, lookup machine
>>>   ARCH ?= $(shell uname -m 2>/dev/null || echo not)
>>>   
>>>   ifneq (,$(filter $(ARCH),aarch64 arm64))
>>> -TEST_GEN_PROGS := tags_test
>>> -TEST_PROGS := run_tags_test.sh
>>> +SUBTARGETS ?= tags
>>> +else
>>> +SUBTARGETS :=
>>>   endif
>>>   
>>> -include ../lib.mk
>>> +CFLAGS := -Wall -O2 -g
>>> +
>>> +# A proper top_srcdir is needed by KSFT(lib.mk)
>>> +top_srcdir = $(realpath ../../../../)
>>> +
>>> +# Additional include paths needed by kselftest.h and local headers
>>> +CFLAGS += -I$(top_srcdir)/tools/testing/selftests/
>>> +
>>> +# Guessing where the Kernel headers could have been installed
>>> +# depending on ENV config
>>> +ifeq ($(KBUILD_OUTPUT),)
>>> +khdr_dir = $(top_srcdir)/usr/include
>>> +else
>>> +# the KSFT preferred location when KBUILD_OUTPUT is set
>>> +khdr_dir = $(KBUILD_OUTPUT)/kselftest/usr/include
>>> +endif
>>
>> I still tend to think that for now we should just do what all the other
>> tests do.
>>
>> Most tests use
>>
>> 	CFLAGS += -I../../../../usr/include/
>>
>> in their Makefiles.
>>
>> For us, the test Makefiles are nested one level deeper, so I guess
>> we would put
>>
>> 	CFLAGS += -I../../../../../usr/include/
>>
>> in each.
>>
>>
>> This will break in some cases, but only in the same cases where
>> kselftest is already broken.
>>
>> Ideally we would fix this globally, but can that instead be done
>> independently of this series?
>>
>> Fixing only arm64, by pasting some arbitrary logic from
>> selftests/Makefile doesn't seem like a future-proof approach.
>>
>>
>> Or did I miss something?
>>
>>> +
>>> +CFLAGS += -I$(khdr_dir)
>>> +
>>> +export CFLAGS
>>> +export top_srcdir
>>> +
>>> +all:
>>> +	@for DIR in $(SUBTARGETS); do				\
>>> +		BUILD_TARGET=$(OUTPUT)/$$DIR;			\
>>> +		mkdir -p $$BUILD_TARGET;			\
>>> +		make OUTPUT=$$BUILD_TARGET -C $$DIR $@;		\
>>> +	done
>>> +
>>> +install: all
>>> +	@for DIR in $(SUBTARGETS); do				\
>>> +		BUILD_TARGET=$(OUTPUT)/$$DIR;			\
>>> +		make OUTPUT=$$BUILD_TARGET -C $$DIR $@;		\
>>> +	done
>>> +
>>> +run_tests: all
>>> +	@for DIR in $(SUBTARGETS); do				\
>>> +		BUILD_TARGET=$(OUTPUT)/$$DIR;			\
>>> +		make OUTPUT=$$BUILD_TARGET -C $$DIR $@;		\
>>> +	done
>>> +
>>> +# Avoid any output on non arm64 on emit_tests
>>
>> This comment can be dropped: the whole file does nothing for
>> non-arm64, and it achieves it in the same way as other arch-specific
>> Makefiles, so it's odd to have the comment here specifically (?)
>>
>>
>> With or without the above changes, I'm happy to give
>>
>> Reviewed-by: Dave Martin <Dave.Martin@arm.com>
>>
>> (but Shuah or someone will need to give a view on how this integrates
>> with kselftest overall).
>>
> 
> I am reviewing the series this week. I will provide comments in a
> day or two.
> 

Thanks Shuah.

As a side question... should I rebase next v7 (after your feedback) on latest
kselftest branch (linux-kselftest-5.4-rc1 or whatever)

Cristian


> thanks,
> -- Shuah
> 


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply

* Re: [PATCH] media: rc: Use devm_platform_ioremap_resource() in tango_ir_probe()
From: Måns Rullgård @ 2019-09-18 11:00 UTC (permalink / raw)
  To: Markus Elfring
  Cc: Himanshu Jha, Marc Gonzalez, Greg Kroah-Hartman, kernel-janitors,
	LKML, Bartosz Golaszewski, linux-arm-kernel, Thomas Gleixner,
	Mauro Carvalho Chehab, Allison Randal, linux-media
In-Reply-To: <04df8450-1b15-55ec-91e7-7d72ffbedac7@web.de>

Markus Elfring <Markus.Elfring@web.de> writes:

> From: Markus Elfring <elfring@users.sourceforge.net>
> Date: Wed, 18 Sep 2019 12:30:18 +0200
>
> Simplify this function implementation by using a known wrapper function.
>
> This issue was detected by using the Coccinelle software.
>
> Signed-off-by: Markus Elfring <elfring@users.sourceforge.net>

Acked-by: Mans Rullgard <mans@mansr.com>

> ---
>  drivers/media/rc/tango-ir.c | 14 ++------------
>  1 file changed, 2 insertions(+), 12 deletions(-)
>
> diff --git a/drivers/media/rc/tango-ir.c b/drivers/media/rc/tango-ir.c
> index 451ec4e9dcfa..b8eb5bc4d9be 100644
> --- a/drivers/media/rc/tango-ir.c
> +++ b/drivers/media/rc/tango-ir.c
> @@ -157,20 +157,10 @@ static int tango_ir_probe(struct platform_device *pdev)
>  	struct device *dev = &pdev->dev;
>  	struct rc_dev *rc;
>  	struct tango_ir *ir;
> -	struct resource *rc5_res;
> -	struct resource *rc6_res;
>  	u64 clkrate, clkdiv;
>  	int irq, err;
>  	u32 val;
>
> -	rc5_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> -	if (!rc5_res)
> -		return -EINVAL;
> -
> -	rc6_res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
> -	if (!rc6_res)
> -		return -EINVAL;
> -
>  	irq = platform_get_irq(pdev, 0);
>  	if (irq <= 0)
>  		return -EINVAL;
> @@ -179,11 +169,11 @@ static int tango_ir_probe(struct platform_device *pdev)
>  	if (!ir)
>  		return -ENOMEM;
>
> -	ir->rc5_base = devm_ioremap_resource(dev, rc5_res);
> +	ir->rc5_base = devm_platform_ioremap_resource(pdev, 0);
>  	if (IS_ERR(ir->rc5_base))
>  		return PTR_ERR(ir->rc5_base);
>
> -	ir->rc6_base = devm_ioremap_resource(dev, rc6_res);
> +	ir->rc6_base = devm_platform_ioremap_resource(pdev, 1);
>  	if (IS_ERR(ir->rc6_base))
>  		return PTR_ERR(ir->rc6_base);
>
> --
> 2.23.0
>

-- 
Måns Rullgård

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply

* Re: [PATCHv8 1/7] PCI: mobiveil: Refactor Mobiveil PCIe Host Bridge IP driver
From: Andrew Murray @ 2019-09-18 11:03 UTC (permalink / raw)
  To: Z.q. Hou
  Cc: mark.rutland@arm.com, devicetree@vger.kernel.org,
	lorenzo.pieralisi@arm.com, m.karthikeyan@mobiveil.co.in,
	arnd@arndb.de, linux-pci@vger.kernel.org,
	l.subrahmanya@mobiveil.co.in, will.deacon@arm.com,
	linux-kernel@vger.kernel.org, Leo Li, M.h. Lian,
	robh+dt@kernel.org, Mingkai Hu, Xiaowei Bao,
	catalin.marinas@arm.com, bhelgaas@google.com, shawnguo@kernel.org,
	linux-arm-kernel@lists.infradead.org
In-Reply-To: <20190917113636.GW9720@e119886-lin.cambridge.arm.com>

On Tue, Sep 17, 2019 at 12:36:37PM +0100, Andrew Murray wrote:
> Hi Hou Zhiqiang,
> 
> Apologies if I bring up any feedback that has previously been discussed as
> I've only recently began reviewing controller patches.
> 
> On Tue, Aug 13, 2019 at 11:03:57AM +0000, Z.q. Hou wrote:
> > From: Hou Zhiqiang <Zhiqiang.Hou@nxp.com>
> > 
> > Refactor the Mobiveil PCIe Host Bridge IP driver to make
> > it easier to add support for both RC and EP mode driver.
> > This patch moved the Mobiveil driver to an new directory
> 
> Rephase to "This patch moves the Mobiveil driver to a new directory"
> 
> Also with regards to the commit title: "Refactor Mobiveil PCIe Host
> Bridge" - this is a very generic phrase and could mean anything. It would
> be more helpful to be specific, e.g. "Move definitions to header file" or
> "Split driver into host and platform parts" or similar.
> 
> > 'drivers/pci/controller/mobiveil' and refactor it according
> > to the RC and EP abstraction.
> > 
> > Signed-off-by: Hou Zhiqiang <Zhiqiang.Hou@nxp.com>
> > Reviewed-by: Minghuan Lian <Minghuan.Lian@nxp.com>
> > Reviewed-by: Subrahmanya Lingappa <l.subrahmanya@mobiveil.co.in>
> > ---
> > V8:
> >  - Re-generate the patch on the new code base.
> > 
> >  MAINTAINERS                                   |   2 +-
> >  drivers/pci/controller/Kconfig                |  11 +-
> >  drivers/pci/controller/Makefile               |   2 +-
> >  drivers/pci/controller/mobiveil/Kconfig       |  24 +
> >  drivers/pci/controller/mobiveil/Makefile      |   4 +
> >  .../pcie-mobiveil-host.c}                     | 525 +++---------------
> >  .../controller/mobiveil/pcie-mobiveil-plat.c  |  59 ++
> >  .../pci/controller/mobiveil/pcie-mobiveil.c   | 227 ++++++++
> >  .../pci/controller/mobiveil/pcie-mobiveil.h   | 189 +++++++
> >  9 files changed, 592 insertions(+), 451 deletions(-)
> >  create mode 100644 drivers/pci/controller/mobiveil/Kconfig
> >  create mode 100644 drivers/pci/controller/mobiveil/Makefile
> >  rename drivers/pci/controller/{pcie-mobiveil.c => mobiveil/pcie-mobiveil-host.c} (54%)
> >  create mode 100644 drivers/pci/controller/mobiveil/pcie-mobiveil-plat.c
> >  create mode 100644 drivers/pci/controller/mobiveil/pcie-mobiveil.c
> >  create mode 100644 drivers/pci/controller/mobiveil/pcie-mobiveil.h
> > 
> > diff --git a/MAINTAINERS b/MAINTAINERS
> > index df85ee4dbdc7..0d88e0d3960b 100644
> > --- a/MAINTAINERS
> > +++ b/MAINTAINERS
> > @@ -12367,7 +12367,7 @@ M:	Hou Zhiqiang <Zhiqiang.Hou@nxp.com>
> >  L:	linux-pci@vger.kernel.org
> >  S:	Supported
> >  F:	Documentation/devicetree/bindings/pci/mobiveil-pcie.txt
> > -F:	drivers/pci/controller/pcie-mobiveil.c
> > +F:	drivers/pci/controller/mobiveil/pcie-mobiveil*
> >  
> >  PCI DRIVER FOR MVEBU (Marvell Armada 370 and Armada XP SOC support)
> >  M:	Thomas Petazzoni <thomas.petazzoni@bootlin.com>
> > diff --git a/drivers/pci/controller/Kconfig b/drivers/pci/controller/Kconfig
> > index fe9f9f13ce11..dec8e038cb17 100644
> > --- a/drivers/pci/controller/Kconfig
> > +++ b/drivers/pci/controller/Kconfig
> > @@ -241,16 +241,6 @@ config PCIE_MEDIATEK
> >  	  Say Y here if you want to enable PCIe controller support on
> >  	  MediaTek SoCs.
> >  
> > -config PCIE_MOBIVEIL
> > -	bool "Mobiveil AXI PCIe controller"
> > -	depends on ARCH_ZYNQMP || COMPILE_TEST
> > -	depends on OF
> > -	depends on PCI_MSI_IRQ_DOMAIN
> > -	help
> > -	  Say Y here if you want to enable support for the Mobiveil AXI PCIe
> > -	  Soft IP. It has up to 8 outbound and inbound windows
> > -	  for address translation and it is a PCIe Gen4 IP.
> > -
> >  config PCIE_TANGO_SMP8759
> >  	bool "Tango SMP8759 PCIe controller (DANGEROUS)"
> >  	depends on ARCH_TANGO && PCI_MSI && OF
> > @@ -282,4 +272,5 @@ config VMD
> >  	  module will be called vmd.
> >  
> >  source "drivers/pci/controller/dwc/Kconfig"
> > +source "drivers/pci/controller/mobiveil/Kconfig"
> >  endmenu
> > diff --git a/drivers/pci/controller/Makefile b/drivers/pci/controller/Makefile
> > index d56a507495c5..b79a615041a0 100644
> > --- a/drivers/pci/controller/Makefile
> > +++ b/drivers/pci/controller/Makefile
> > @@ -26,11 +26,11 @@ obj-$(CONFIG_PCIE_ROCKCHIP) += pcie-rockchip.o
> >  obj-$(CONFIG_PCIE_ROCKCHIP_EP) += pcie-rockchip-ep.o
> >  obj-$(CONFIG_PCIE_ROCKCHIP_HOST) += pcie-rockchip-host.o
> >  obj-$(CONFIG_PCIE_MEDIATEK) += pcie-mediatek.o
> > -obj-$(CONFIG_PCIE_MOBIVEIL) += pcie-mobiveil.o
> >  obj-$(CONFIG_PCIE_TANGO_SMP8759) += pcie-tango.o
> >  obj-$(CONFIG_VMD) += vmd.o
> >  # pcie-hisi.o quirks are needed even without CONFIG_PCIE_DW
> >  obj-y				+= dwc/
> > +obj-y				+= mobiveil/
> >  
> >  
> >  # The following drivers are for devices that use the generic ACPI
> > diff --git a/drivers/pci/controller/mobiveil/Kconfig b/drivers/pci/controller/mobiveil/Kconfig
> > new file mode 100644
> > index 000000000000..64343c07bfed
> > --- /dev/null
> > +++ b/drivers/pci/controller/mobiveil/Kconfig
> > @@ -0,0 +1,24 @@
> > +# SPDX-License-Identifier: GPL-2.0
> > +
> > +menu "Mobiveil PCIe Core Support"
> > +	depends on PCI
> > +
> > +config PCIE_MOBIVEIL
> > +	bool
> > +
> > +config PCIE_MOBIVEIL_HOST
> > +        bool
> > +	depends on PCI_MSI_IRQ_DOMAIN
> > +        select PCIE_MOBIVEIL
> 
> This has the same inconsistent indentation as dwc/Kconfig - please you use
> tabs here instead of spaces for the 'depends' line.
> 
> > +
> > +config PCIE_MOBIVEIL_PLAT
> > +	bool "Mobiveil AXI PCIe controller"
> > +	depends on ARCH_ZYNQMP || COMPILE_TEST
> > +	depends on OF
> > +	select PCIE_MOBIVEIL_HOST
> > +	help
> > +	  Say Y here if you want to enable support for the Mobiveil AXI PCIe
> > +	  Soft IP. It has up to 8 outbound and inbound windows
> > +	  for address translation and it is a PCIe Gen4 IP.
> 
> Does this description describe both host and EP?

Apologies, I misread your cover letter and expected an EP driver. I can see
that this series does not add an EP driver, so please ignore the above
comment.

> 
> There appears to be two existing in-tree approaches to sharing code between EP
> and host:
> 
>  The 'dwc' approach (the one you've taken) - this puts has its own directory,
>  vendor.c, vendor-ep.c, vendor-host.c and vendor-plat.c files.
> 
>  The 'cadence','rockchip' approach - this uses the same directory and has a
>  vendor.c, vendor-ep.c and vendor-host.c
> 
> The 'dwc' approach is well suited for its own directory because there are
> many DWC drivers and probably many more to come. Why have you chosen this
> approach?

I'm still interested in why this approach - is there an expectation of future
Mobiveil drivers?

Thanks,

Andrew Murray

> 
> > +
> > +endmenu
> > diff --git a/drivers/pci/controller/mobiveil/Makefile b/drivers/pci/controller/mobiveil/Makefile
> > new file mode 100644
> > index 000000000000..9fb6d1c6504d
> > --- /dev/null
> > +++ b/drivers/pci/controller/mobiveil/Makefile
> > @@ -0,0 +1,4 @@
> > +# SPDX-License-Identifier: GPL-2.0
> > +obj-$(CONFIG_PCIE_MOBIVEIL) += pcie-mobiveil.o
> > +obj-$(CONFIG_PCIE_MOBIVEIL_HOST) += pcie-mobiveil-host.o
> > +obj-$(CONFIG_PCIE_MOBIVEIL_PLAT) += pcie-mobiveil-plat.o
> > diff --git a/drivers/pci/controller/pcie-mobiveil.c b/drivers/pci/controller/mobiveil/pcie-mobiveil-host.c
> > similarity index 54%
> > rename from drivers/pci/controller/pcie-mobiveil.c
> > rename to drivers/pci/controller/mobiveil/pcie-mobiveil-host.c
> > index a45a6447b01d..995487c4f760 100644
> > --- a/drivers/pci/controller/pcie-mobiveil.c
> > +++ b/drivers/pci/controller/mobiveil/pcie-mobiveil-host.c
> > @@ -3,10 +3,12 @@
> >   * PCIe host controller driver for Mobiveil PCIe Host controller
> >   *
> >   * Copyright (c) 2018 Mobiveil Inc.
> > + * Copyright 2019 NXP
> > + *
> >   * Author: Subrahmanya Lingappa <l.subrahmanya@mobiveil.co.in>
> > + * Refactor: Zhiqiang Hou <Zhiqiang.Hou@nxp.com>
> 
> I'm not sure the value of adding a 'Refactor:' tag here. It's not
> a tag I've seen anywhere else in the kernel. I'd rather people rely
> on git log to understand the revision history. Though I wouldn't have
> any objection to you adding yourself alongside Subrahmanya as a
> co-author.
> 
> >   */
> >  
> > -#include <linux/delay.h>
> >  #include <linux/init.h>
> >  #include <linux/interrupt.h>
> >  #include <linux/irq.h>
> > @@ -23,274 +25,21 @@
> >  #include <linux/platform_device.h>
> >  #include <linux/slab.h>
> >  
> > -#include "../pci.h"
> > -
> > -/* register offsets and bit positions */
> > -
> > -/*
> > - * translation tables are grouped into windows, each window registers are
> > - * grouped into blocks of 4 or 16 registers each
> > - */
> > -#define PAB_REG_BLOCK_SIZE		16
> > -#define PAB_EXT_REG_BLOCK_SIZE		4
> > -
> > -#define PAB_REG_ADDR(offset, win)	\
> > -	(offset + (win * PAB_REG_BLOCK_SIZE))
> > -#define PAB_EXT_REG_ADDR(offset, win)	\
> > -	(offset + (win * PAB_EXT_REG_BLOCK_SIZE))
> > -
> > -#define LTSSM_STATUS			0x0404
> > -#define  LTSSM_STATUS_L0_MASK		0x3f
> > -#define  LTSSM_STATUS_L0		0x2d
> > -
> > -#define PAB_CTRL			0x0808
> > -#define  AMBA_PIO_ENABLE_SHIFT		0
> > -#define  PEX_PIO_ENABLE_SHIFT		1
> > -#define  PAGE_SEL_SHIFT			13
> > -#define  PAGE_SEL_MASK			0x3f
> > -#define  PAGE_LO_MASK			0x3ff
> > -#define  PAGE_SEL_OFFSET_SHIFT		10
> > -
> > -#define PAB_AXI_PIO_CTRL		0x0840
> > -#define  APIO_EN_MASK			0xf
> > -
> > -#define PAB_PEX_PIO_CTRL		0x08c0
> > -#define  PIO_ENABLE_SHIFT		0
> > -
> > -#define PAB_INTP_AMBA_MISC_ENB		0x0b0c
> > -#define PAB_INTP_AMBA_MISC_STAT		0x0b1c
> > -#define  PAB_INTP_INTX_MASK		0x01e0
> > -#define  PAB_INTP_MSI_MASK		0x8
> > -
> > -#define PAB_AXI_AMAP_CTRL(win)		PAB_REG_ADDR(0x0ba0, win)
> > -#define  WIN_ENABLE_SHIFT		0
> > -#define  WIN_TYPE_SHIFT			1
> > -#define  WIN_TYPE_MASK			0x3
> > -#define  WIN_SIZE_MASK			0xfffffc00
> > -
> > -#define PAB_EXT_AXI_AMAP_SIZE(win)	PAB_EXT_REG_ADDR(0xbaf0, win)
> > -
> > -#define PAB_EXT_AXI_AMAP_AXI_WIN(win)	PAB_EXT_REG_ADDR(0x80a0, win)
> > -#define PAB_AXI_AMAP_AXI_WIN(win)	PAB_REG_ADDR(0x0ba4, win)
> > -#define  AXI_WINDOW_ALIGN_MASK		3
> > -
> > -#define PAB_AXI_AMAP_PEX_WIN_L(win)	PAB_REG_ADDR(0x0ba8, win)
> > -#define  PAB_BUS_SHIFT			24
> > -#define  PAB_DEVICE_SHIFT		19
> > -#define  PAB_FUNCTION_SHIFT		16
> > -
> > -#define PAB_AXI_AMAP_PEX_WIN_H(win)	PAB_REG_ADDR(0x0bac, win)
> > -#define PAB_INTP_AXI_PIO_CLASS		0x474
> > -
> > -#define PAB_PEX_AMAP_CTRL(win)		PAB_REG_ADDR(0x4ba0, win)
> > -#define  AMAP_CTRL_EN_SHIFT		0
> > -#define  AMAP_CTRL_TYPE_SHIFT		1
> > -#define  AMAP_CTRL_TYPE_MASK		3
> > -
> > -#define PAB_EXT_PEX_AMAP_SIZEN(win)	PAB_EXT_REG_ADDR(0xbef0, win)
> > -#define PAB_EXT_PEX_AMAP_AXI_WIN(win)	PAB_EXT_REG_ADDR(0xb4a0, win)
> > -#define PAB_PEX_AMAP_AXI_WIN(win)	PAB_REG_ADDR(0x4ba4, win)
> > -#define PAB_PEX_AMAP_PEX_WIN_L(win)	PAB_REG_ADDR(0x4ba8, win)
> > -#define PAB_PEX_AMAP_PEX_WIN_H(win)	PAB_REG_ADDR(0x4bac, win)
> > -
> > -/* starting offset of INTX bits in status register */
> > -#define PAB_INTX_START			5
> > -
> > -/* supported number of MSI interrupts */
> > -#define PCI_NUM_MSI			16
> > -
> > -/* MSI registers */
> > -#define MSI_BASE_LO_OFFSET		0x04
> > -#define MSI_BASE_HI_OFFSET		0x08
> > -#define MSI_SIZE_OFFSET			0x0c
> > -#define MSI_ENABLE_OFFSET		0x14
> > -#define MSI_STATUS_OFFSET		0x18
> > -#define MSI_DATA_OFFSET			0x20
> > -#define MSI_ADDR_L_OFFSET		0x24
> > -#define MSI_ADDR_H_OFFSET		0x28
> > -
> > -/* outbound and inbound window definitions */
> > -#define WIN_NUM_0			0
> > -#define WIN_NUM_1			1
> > -#define CFG_WINDOW_TYPE			0
> > -#define IO_WINDOW_TYPE			1
> > -#define MEM_WINDOW_TYPE			2
> > -#define IB_WIN_SIZE			((u64)256 * 1024 * 1024 * 1024)
> > -#define MAX_PIO_WINDOWS			8
> > -
> > -/* Parameters for the waiting for link up routine */
> > -#define LINK_WAIT_MAX_RETRIES		10
> > -#define LINK_WAIT_MIN			90000
> > -#define LINK_WAIT_MAX			100000
> > -
> > -#define PAGED_ADDR_BNDRY		0xc00
> > -#define OFFSET_TO_PAGE_ADDR(off)	\
> > -	((off & PAGE_LO_MASK) | PAGED_ADDR_BNDRY)
> > -#define OFFSET_TO_PAGE_IDX(off)		\
> > -	((off >> PAGE_SEL_OFFSET_SHIFT) & PAGE_SEL_MASK)
> > -
> > -struct mobiveil_msi {			/* MSI information */
> > -	struct mutex lock;		/* protect bitmap variable */
> > -	struct irq_domain *msi_domain;
> > -	struct irq_domain *dev_domain;
> > -	phys_addr_t msi_pages_phys;
> > -	int num_of_vectors;
> > -	DECLARE_BITMAP(msi_irq_in_use, PCI_NUM_MSI);
> > -};
> > -
> > -struct mobiveil_pcie {
> > -	struct platform_device *pdev;
> > -	struct list_head resources;
> > -	void __iomem *config_axi_slave_base;	/* endpoint config base */
> > -	void __iomem *csr_axi_slave_base;	/* root port config base */
> > -	void __iomem *apb_csr_base;	/* MSI register base */
> > -	phys_addr_t pcie_reg_base;	/* Physical PCIe Controller Base */
> > -	struct irq_domain *intx_domain;
> > -	raw_spinlock_t intx_mask_lock;
> > -	int irq;
> > -	int apio_wins;
> > -	int ppio_wins;
> > -	int ob_wins_configured;		/* configured outbound windows */
> > -	int ib_wins_configured;		/* configured inbound windows */
> > -	struct resource *ob_io_res;
> > -	char root_bus_nr;
> > -	struct mobiveil_msi msi;
> > -};
> > -
> > -/*
> > - * mobiveil_pcie_sel_page - routine to access paged register
> > - *
> > - * Registers whose address greater than PAGED_ADDR_BNDRY (0xc00) are paged,
> > - * for this scheme to work extracted higher 6 bits of the offset will be
> > - * written to pg_sel field of PAB_CTRL register and rest of the lower 10
> > - * bits enabled with PAGED_ADDR_BNDRY are used as offset of the register.
> > - */
> > -static void mobiveil_pcie_sel_page(struct mobiveil_pcie *pcie, u8 pg_idx)
> > -{
> > -	u32 val;
> > -
> > -	val = readl(pcie->csr_axi_slave_base + PAB_CTRL);
> > -	val &= ~(PAGE_SEL_MASK << PAGE_SEL_SHIFT);
> > -	val |= (pg_idx & PAGE_SEL_MASK) << PAGE_SEL_SHIFT;
> > -
> > -	writel(val, pcie->csr_axi_slave_base + PAB_CTRL);
> > -}
> > -
> > -static void *mobiveil_pcie_comp_addr(struct mobiveil_pcie *pcie, u32 off)
> > -{
> > -	if (off < PAGED_ADDR_BNDRY) {
> > -		/* For directly accessed registers, clear the pg_sel field */
> > -		mobiveil_pcie_sel_page(pcie, 0);
> > -		return pcie->csr_axi_slave_base + off;
> > -	}
> > -
> > -	mobiveil_pcie_sel_page(pcie, OFFSET_TO_PAGE_IDX(off));
> > -	return pcie->csr_axi_slave_base + OFFSET_TO_PAGE_ADDR(off);
> > -}
> > -
> > -static int mobiveil_pcie_read(void __iomem *addr, int size, u32 *val)
> > -{
> > -	if ((uintptr_t)addr & (size - 1)) {
> > -		*val = 0;
> > -		return PCIBIOS_BAD_REGISTER_NUMBER;
> > -	}
> > -
> > -	switch (size) {
> > -	case 4:
> > -		*val = readl(addr);
> > -		break;
> > -	case 2:
> > -		*val = readw(addr);
> > -		break;
> > -	case 1:
> > -		*val = readb(addr);
> > -		break;
> > -	default:
> > -		*val = 0;
> > -		return PCIBIOS_BAD_REGISTER_NUMBER;
> > -	}
> > -
> > -	return PCIBIOS_SUCCESSFUL;
> > -}
> > -
> > -static int mobiveil_pcie_write(void __iomem *addr, int size, u32 val)
> > -{
> > -	if ((uintptr_t)addr & (size - 1))
> > -		return PCIBIOS_BAD_REGISTER_NUMBER;
> > -
> > -	switch (size) {
> > -	case 4:
> > -		writel(val, addr);
> > -		break;
> > -	case 2:
> > -		writew(val, addr);
> > -		break;
> > -	case 1:
> > -		writeb(val, addr);
> > -		break;
> > -	default:
> > -		return PCIBIOS_BAD_REGISTER_NUMBER;
> > -	}
> > -
> > -	return PCIBIOS_SUCCESSFUL;
> > -}
> > -
> > -static u32 csr_read(struct mobiveil_pcie *pcie, u32 off, size_t size)
> > -{
> > -	void *addr;
> > -	u32 val;
> > -	int ret;
> > -
> > -	addr = mobiveil_pcie_comp_addr(pcie, off);
> > -
> > -	ret = mobiveil_pcie_read(addr, size, &val);
> > -	if (ret)
> > -		dev_err(&pcie->pdev->dev, "read CSR address failed\n");
> > -
> > -	return val;
> > -}
> > -
> > -static void csr_write(struct mobiveil_pcie *pcie, u32 val, u32 off, size_t size)
> > -{
> > -	void *addr;
> > -	int ret;
> > -
> > -	addr = mobiveil_pcie_comp_addr(pcie, off);
> > -
> > -	ret = mobiveil_pcie_write(addr, size, val);
> > -	if (ret)
> > -		dev_err(&pcie->pdev->dev, "write CSR address failed\n");
> > -}
> > -
> > -static u32 csr_readl(struct mobiveil_pcie *pcie, u32 off)
> > -{
> > -	return csr_read(pcie, off, 0x4);
> > -}
> > -
> > -static void csr_writel(struct mobiveil_pcie *pcie, u32 val, u32 off)
> > -{
> > -	csr_write(pcie, val, off, 0x4);
> > -}
> > -
> > -static bool mobiveil_pcie_link_up(struct mobiveil_pcie *pcie)
> > -{
> > -	return (csr_readl(pcie, LTSSM_STATUS) &
> > -		LTSSM_STATUS_L0_MASK) == LTSSM_STATUS_L0;
> > -}
> > +#include "pcie-mobiveil.h"
> >  
> >  static bool mobiveil_pcie_valid_device(struct pci_bus *bus, unsigned int devfn)
> >  {
> >  	struct mobiveil_pcie *pcie = bus->sysdata;
> >  
> >  	/* Only one device down on each root port */
> > -	if ((bus->number == pcie->root_bus_nr) && (devfn > 0))
> > +	if ((bus->number == pcie->rp.root_bus_nr) && (devfn > 0))
> >  		return false;
> >  
> >  	/*
> >  	 * Do not read more than one device on the bus directly
> >  	 * attached to RC
> >  	 */
> > -	if ((bus->primary == pcie->root_bus_nr) && (PCI_SLOT(devfn) > 0))
> > +	if ((bus->primary == pcie->rp.root_bus_nr) && (PCI_SLOT(devfn) > 0))
> >  		return false;
> >  
> >  	return true;
> > @@ -310,7 +59,7 @@ static void __iomem *mobiveil_pcie_map_bus(struct pci_bus *bus,
> >  		return NULL;
> >  
> >  	/* RC config access */
> > -	if (bus->number == pcie->root_bus_nr)
> > +	if (bus->number == pcie->rp.root_bus_nr)
> >  		return pcie->csr_axi_slave_base + where;
> >  
> >  	/*
> > @@ -325,7 +74,7 @@ static void __iomem *mobiveil_pcie_map_bus(struct pci_bus *bus,
> >  
> >  	csr_writel(pcie, value, PAB_AXI_AMAP_PEX_WIN_L(WIN_NUM_0));
> >  
> > -	return pcie->config_axi_slave_base + where;
> > +	return pcie->rp.config_axi_slave_base + where;
> >  }
> >  
> >  static struct pci_ops mobiveil_pcie_ops = {
> > @@ -339,7 +88,7 @@ static void mobiveil_pcie_isr(struct irq_desc *desc)
> >  	struct irq_chip *chip = irq_desc_get_chip(desc);
> >  	struct mobiveil_pcie *pcie = irq_desc_get_handler_data(desc);
> >  	struct device *dev = &pcie->pdev->dev;
> > -	struct mobiveil_msi *msi = &pcie->msi;
> > +	struct mobiveil_msi *msi = &pcie->rp.msi;
> >  	u32 msi_data, msi_addr_lo, msi_addr_hi;
> >  	u32 intr_status, msi_status;
> >  	unsigned long shifted_status;
> > @@ -364,7 +113,7 @@ static void mobiveil_pcie_isr(struct irq_desc *desc)
> >  		shifted_status >>= PAB_INTX_START;
> >  		do {
> >  			for_each_set_bit(bit, &shifted_status, PCI_NUM_INTX) {
> > -				virq = irq_find_mapping(pcie->intx_domain,
> > +				virq = irq_find_mapping(pcie->rp.intx_domain,
> >  							bit + 1);
> >  				if (virq)
> >  					generic_handle_irq(virq);
> > @@ -427,10 +176,10 @@ static int mobiveil_pcie_parse_dt(struct mobiveil_pcie *pcie)
> >  	/* map config resource */
> >  	res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
> >  					   "config_axi_slave");
> > -	pcie->config_axi_slave_base = devm_pci_remap_cfg_resource(dev, res);
> > -	if (IS_ERR(pcie->config_axi_slave_base))
> > -		return PTR_ERR(pcie->config_axi_slave_base);
> > -	pcie->ob_io_res = res;
> > +	pcie->rp.config_axi_slave_base = devm_pci_remap_cfg_resource(dev, res);
> > +	if (IS_ERR(pcie->rp.config_axi_slave_base))
> > +		return PTR_ERR(pcie->rp.config_axi_slave_base);
> > +	pcie->rp.ob_io_res = res;
> >  
> 
> The splitting up of this file into multiple file looks broadly consistent with
> 'dwc' - however it is tricky to review as in addition to moving code, we're also
> changing it. For example you introduce the concept of a root_port along with
> (mobiveil_rp_ops and mobiveil_pab_ops) - this changes the code that you are
> moving. There are also differences with interrupt handling.
> 
> It would be helpful to split this up.
> 
> Thanks,
> 
> Andrew Murray 
> 
> 
> >  	/* map csr resource */
> >  	res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
> > @@ -440,12 +189,6 @@ static int mobiveil_pcie_parse_dt(struct mobiveil_pcie *pcie)
> >  		return PTR_ERR(pcie->csr_axi_slave_base);
> >  	pcie->pcie_reg_base = res->start;
> >  
> > -	/* map MSI config resource */
> > -	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "apb_csr");
> > -	pcie->apb_csr_base = devm_pci_remap_cfg_resource(dev, res);
> > -	if (IS_ERR(pcie->apb_csr_base))
> > -		return PTR_ERR(pcie->apb_csr_base);
> > -
> >  	/* read the number of windows requested */
> >  	if (of_property_read_u32(node, "apio-wins", &pcie->apio_wins))
> >  		pcie->apio_wins = MAX_PIO_WINDOWS;
> > @@ -453,116 +196,15 @@ static int mobiveil_pcie_parse_dt(struct mobiveil_pcie *pcie)
> >  	if (of_property_read_u32(node, "ppio-wins", &pcie->ppio_wins))
> >  		pcie->ppio_wins = MAX_PIO_WINDOWS;
> >  
> > -	pcie->irq = platform_get_irq(pdev, 0);
> > -	if (pcie->irq <= 0) {
> > -		dev_err(dev, "failed to map IRQ: %d\n", pcie->irq);
> > -		return -ENODEV;
> > -	}
> > -
> >  	return 0;
> >  }
> >  
> > -static void program_ib_windows(struct mobiveil_pcie *pcie, int win_num,
> > -			       u64 cpu_addr, u64 pci_addr, u32 type, u64 size)
> > -{
> > -	u32 value;
> > -	u64 size64 = ~(size - 1);
> > -
> > -	if (win_num >= pcie->ppio_wins) {
> > -		dev_err(&pcie->pdev->dev,
> > -			"ERROR: max inbound windows reached !\n");
> > -		return;
> > -	}
> > -
> > -	value = csr_readl(pcie, PAB_PEX_AMAP_CTRL(win_num));
> > -	value &= ~(AMAP_CTRL_TYPE_MASK << AMAP_CTRL_TYPE_SHIFT | WIN_SIZE_MASK);
> > -	value |= type << AMAP_CTRL_TYPE_SHIFT | 1 << AMAP_CTRL_EN_SHIFT |
> > -		 (lower_32_bits(size64) & WIN_SIZE_MASK);
> > -	csr_writel(pcie, value, PAB_PEX_AMAP_CTRL(win_num));
> > -
> > -	csr_writel(pcie, upper_32_bits(size64),
> > -		   PAB_EXT_PEX_AMAP_SIZEN(win_num));
> > -
> > -	csr_writel(pcie, lower_32_bits(cpu_addr),
> > -		   PAB_PEX_AMAP_AXI_WIN(win_num));
> > -	csr_writel(pcie, upper_32_bits(cpu_addr),
> > -		   PAB_EXT_PEX_AMAP_AXI_WIN(win_num));
> > -
> > -	csr_writel(pcie, lower_32_bits(pci_addr),
> > -		   PAB_PEX_AMAP_PEX_WIN_L(win_num));
> > -	csr_writel(pcie, upper_32_bits(pci_addr),
> > -		   PAB_PEX_AMAP_PEX_WIN_H(win_num));
> > -
> > -	pcie->ib_wins_configured++;
> > -}
> > -
> > -/*
> > - * routine to program the outbound windows
> > - */
> > -static void program_ob_windows(struct mobiveil_pcie *pcie, int win_num,
> > -			       u64 cpu_addr, u64 pci_addr, u32 type, u64 size)
> > -{
> > -	u32 value;
> > -	u64 size64 = ~(size - 1);
> > -
> > -	if (win_num >= pcie->apio_wins) {
> > -		dev_err(&pcie->pdev->dev,
> > -			"ERROR: max outbound windows reached !\n");
> > -		return;
> > -	}
> > -
> > -	/*
> > -	 * program Enable Bit to 1, Type Bit to (00) base 2, AXI Window Size Bit
> > -	 * to 4 KB in PAB_AXI_AMAP_CTRL register
> > -	 */
> > -	value = csr_readl(pcie, PAB_AXI_AMAP_CTRL(win_num));
> > -	value &= ~(WIN_TYPE_MASK << WIN_TYPE_SHIFT | WIN_SIZE_MASK);
> > -	value |= 1 << WIN_ENABLE_SHIFT | type << WIN_TYPE_SHIFT |
> > -		 (lower_32_bits(size64) & WIN_SIZE_MASK);
> > -	csr_writel(pcie, value, PAB_AXI_AMAP_CTRL(win_num));
> > -
> > -	csr_writel(pcie, upper_32_bits(size64), PAB_EXT_AXI_AMAP_SIZE(win_num));
> > -
> > -	/*
> > -	 * program AXI window base with appropriate value in
> > -	 * PAB_AXI_AMAP_AXI_WIN0 register
> > -	 */
> > -	csr_writel(pcie, lower_32_bits(cpu_addr) & (~AXI_WINDOW_ALIGN_MASK),
> > -		   PAB_AXI_AMAP_AXI_WIN(win_num));
> > -	csr_writel(pcie, upper_32_bits(cpu_addr),
> > -		   PAB_EXT_AXI_AMAP_AXI_WIN(win_num));
> > -
> > -	csr_writel(pcie, lower_32_bits(pci_addr),
> > -		   PAB_AXI_AMAP_PEX_WIN_L(win_num));
> > -	csr_writel(pcie, upper_32_bits(pci_addr),
> > -		   PAB_AXI_AMAP_PEX_WIN_H(win_num));
> > -
> > -	pcie->ob_wins_configured++;
> > -}
> > -
> > -static int mobiveil_bringup_link(struct mobiveil_pcie *pcie)
> > -{
> > -	int retries;
> > -
> > -	/* check if the link is up or not */
> > -	for (retries = 0; retries < LINK_WAIT_MAX_RETRIES; retries++) {
> > -		if (mobiveil_pcie_link_up(pcie))
> > -			return 0;
> > -
> > -		usleep_range(LINK_WAIT_MIN, LINK_WAIT_MAX);
> > -	}
> > -
> > -	dev_err(&pcie->pdev->dev, "link never came up\n");
> > -
> > -	return -ETIMEDOUT;
> > -}
> > -
> >  static void mobiveil_pcie_enable_msi(struct mobiveil_pcie *pcie)
> >  {
> >  	phys_addr_t msg_addr = pcie->pcie_reg_base;
> > -	struct mobiveil_msi *msi = &pcie->msi;
> > +	struct mobiveil_msi *msi = &pcie->rp.msi;
> >  
> > -	pcie->msi.num_of_vectors = PCI_NUM_MSI;
> > +	msi->num_of_vectors = PCI_NUM_MSI;
> >  	msi->msi_pages_phys = (phys_addr_t)msg_addr;
> >  
> >  	writel_relaxed(lower_32_bits(msg_addr),
> > @@ -600,9 +242,6 @@ static int mobiveil_host_init(struct mobiveil_pcie *pcie)
> >  	pab_ctrl |= (1 << AMBA_PIO_ENABLE_SHIFT) | (1 << PEX_PIO_ENABLE_SHIFT);
> >  	csr_writel(pcie, pab_ctrl, PAB_CTRL);
> >  
> > -	csr_writel(pcie, (PAB_INTP_INTX_MASK | PAB_INTP_MSI_MASK),
> > -		   PAB_INTP_AMBA_MISC_ENB);
> > -
> >  	/*
> >  	 * program PIO Enable Bit to 1 and Config Window Enable Bit to 1 in
> >  	 * PAB_AXI_PIO_CTRL Register
> > @@ -624,20 +263,24 @@ static int mobiveil_host_init(struct mobiveil_pcie *pcie)
> >  	 */
> >  
> >  	/* config outbound translation window */
> > -	program_ob_windows(pcie, WIN_NUM_0, pcie->ob_io_res->start, 0,
> > -			   CFG_WINDOW_TYPE, resource_size(pcie->ob_io_res));
> > +	program_ob_windows(pcie, WIN_NUM_0, pcie->rp.ob_io_res->start, 0,
> > +			   CFG_WINDOW_TYPE, resource_size(pcie->rp.ob_io_res));
> >  
> >  	/* memory inbound translation window */
> >  	program_ib_windows(pcie, WIN_NUM_0, 0, 0, MEM_WINDOW_TYPE, IB_WIN_SIZE);
> >  
> >  	/* Get the I/O and memory ranges from DT */
> >  	resource_list_for_each_entry(win, &pcie->resources) {
> > -		if (resource_type(win->res) == IORESOURCE_MEM)
> > +		if (resource_type(win->res) == IORESOURCE_MEM) {
> >  			type = MEM_WINDOW_TYPE;
> > -		else if (resource_type(win->res) == IORESOURCE_IO)
> > +		} else if (resource_type(win->res) == IORESOURCE_IO) {
> >  			type = IO_WINDOW_TYPE;
> > -		else
> > +		} else if (resource_type(win->res) == IORESOURCE_BUS) {
> > +			pcie->rp.root_bus_nr = win->res->start;
> >  			continue;
> > +		} else {
> > +			continue;
> > +		}
> >  
> >  		/* configure outbound translation window */
> >  		program_ob_windows(pcie, pcie->ob_wins_configured,
> > @@ -652,9 +295,6 @@ static int mobiveil_host_init(struct mobiveil_pcie *pcie)
> >  	value |= (PCI_CLASS_BRIDGE_PCI << 16);
> >  	csr_writel(pcie, value, PAB_INTP_AXI_PIO_CLASS);
> >  
> > -	/* setup MSI hardware registers */
> > -	mobiveil_pcie_enable_msi(pcie);
> > -
> >  	return 0;
> >  }
> >  
> > @@ -667,11 +307,11 @@ static void mobiveil_mask_intx_irq(struct irq_data *data)
> >  
> >  	pcie = irq_desc_get_chip_data(desc);
> >  	mask = 1 << ((data->hwirq + PAB_INTX_START) - 1);
> > -	raw_spin_lock_irqsave(&pcie->intx_mask_lock, flags);
> > +	raw_spin_lock_irqsave(&pcie->rp.intx_mask_lock, flags);
> >  	shifted_val = csr_readl(pcie, PAB_INTP_AMBA_MISC_ENB);
> >  	shifted_val &= ~mask;
> >  	csr_writel(pcie, shifted_val, PAB_INTP_AMBA_MISC_ENB);
> > -	raw_spin_unlock_irqrestore(&pcie->intx_mask_lock, flags);
> > +	raw_spin_unlock_irqrestore(&pcie->rp.intx_mask_lock, flags);
> >  }
> >  
> >  static void mobiveil_unmask_intx_irq(struct irq_data *data)
> > @@ -683,11 +323,11 @@ static void mobiveil_unmask_intx_irq(struct irq_data *data)
> >  
> >  	pcie = irq_desc_get_chip_data(desc);
> >  	mask = 1 << ((data->hwirq + PAB_INTX_START) - 1);
> > -	raw_spin_lock_irqsave(&pcie->intx_mask_lock, flags);
> > +	raw_spin_lock_irqsave(&pcie->rp.intx_mask_lock, flags);
> >  	shifted_val = csr_readl(pcie, PAB_INTP_AMBA_MISC_ENB);
> >  	shifted_val |= mask;
> >  	csr_writel(pcie, shifted_val, PAB_INTP_AMBA_MISC_ENB);
> > -	raw_spin_unlock_irqrestore(&pcie->intx_mask_lock, flags);
> > +	raw_spin_unlock_irqrestore(&pcie->rp.intx_mask_lock, flags);
> >  }
> >  
> >  static struct irq_chip intx_irq_chip = {
> > @@ -755,7 +395,7 @@ static int mobiveil_irq_msi_domain_alloc(struct irq_domain *domain,
> >  					 unsigned int nr_irqs, void *args)
> >  {
> >  	struct mobiveil_pcie *pcie = domain->host_data;
> > -	struct mobiveil_msi *msi = &pcie->msi;
> > +	struct mobiveil_msi *msi = &pcie->rp.msi;
> >  	unsigned long bit;
> >  
> >  	WARN_ON(nr_irqs != 1);
> > @@ -782,7 +422,7 @@ static void mobiveil_irq_msi_domain_free(struct irq_domain *domain,
> >  {
> >  	struct irq_data *d = irq_domain_get_irq_data(domain, virq);
> >  	struct mobiveil_pcie *pcie = irq_data_get_irq_chip_data(d);
> > -	struct mobiveil_msi *msi = &pcie->msi;
> > +	struct mobiveil_msi *msi = &pcie->rp.msi;
> >  
> >  	mutex_lock(&msi->lock);
> >  
> > @@ -803,9 +443,9 @@ static int mobiveil_allocate_msi_domains(struct mobiveil_pcie *pcie)
> >  {
> >  	struct device *dev = &pcie->pdev->dev;
> >  	struct fwnode_handle *fwnode = of_node_to_fwnode(dev->of_node);
> > -	struct mobiveil_msi *msi = &pcie->msi;
> > +	struct mobiveil_msi *msi = &pcie->rp.msi;
> >  
> > -	mutex_init(&pcie->msi.lock);
> > +	mutex_init(&msi->lock);
> >  	msi->dev_domain = irq_domain_add_linear(NULL, msi->num_of_vectors,
> >  						&msi_domain_ops, pcie);
> >  	if (!msi->dev_domain) {
> > @@ -832,15 +472,15 @@ static int mobiveil_pcie_init_irq_domain(struct mobiveil_pcie *pcie)
> >  	int ret;
> >  
> >  	/* setup INTx */
> > -	pcie->intx_domain = irq_domain_add_linear(node, PCI_NUM_INTX,
> > -						  &intx_domain_ops, pcie);
> > +	pcie->rp.intx_domain = irq_domain_add_linear(node, PCI_NUM_INTX,
> > +						     &intx_domain_ops, pcie);
> >  
> > -	if (!pcie->intx_domain) {
> > +	if (!pcie->rp.intx_domain) {
> >  		dev_err(dev, "Failed to get a INTx IRQ domain\n");
> >  		return -ENOMEM;
> >  	}
> >  
> > -	raw_spin_lock_init(&pcie->intx_mask_lock);
> > +	raw_spin_lock_init(&pcie->rp.intx_mask_lock);
> >  
> >  	/* setup MSI */
> >  	ret = mobiveil_allocate_msi_domains(pcie);
> > @@ -850,24 +490,58 @@ static int mobiveil_pcie_init_irq_domain(struct mobiveil_pcie *pcie)
> >  	return 0;
> >  }
> >  
> > -static int mobiveil_pcie_probe(struct platform_device *pdev)
> > +static int mobiveil_pcie_interrupt_init(struct mobiveil_pcie *pcie)
> > +{
> > +	struct device *dev = &pcie->pdev->dev;
> > +	struct resource *res;
> > +	int ret;
> > +
> > +	if (pcie->rp.ops->interrupt_init)
> > +		return pcie->rp.ops->interrupt_init(pcie);
> > +
> > +	/* map MSI config resource */
> > +	res = platform_get_resource_byname(pcie->pdev, IORESOURCE_MEM,
> > +					   "apb_csr");
> > +	pcie->apb_csr_base = devm_pci_remap_cfg_resource(dev, res);
> > +	if (IS_ERR(pcie->apb_csr_base))
> > +		return PTR_ERR(pcie->apb_csr_base);
> > +
> > +	/* setup MSI hardware registers */
> > +	mobiveil_pcie_enable_msi(pcie);
> > +
> > +	pcie->rp.irq = platform_get_irq(pcie->pdev, 0);
> > +	if (pcie->rp.irq <= 0) {
> > +		dev_err(dev, "failed to map IRQ: %d\n", pcie->rp.irq);
> > +		return -ENODEV;
> > +	}
> > +
> > +	/* initialize the IRQ domains */
> > +	ret = mobiveil_pcie_init_irq_domain(pcie);
> > +	if (ret) {
> > +		dev_err(dev, "Failed creating IRQ Domain\n");
> > +		return ret;
> > +	}
> > +
> > +	irq_set_chained_handler_and_data(pcie->rp.irq,
> > +					 mobiveil_pcie_isr, pcie);
> > +
> > +	/* Enable interrupts */
> > +	csr_writel(pcie, (PAB_INTP_INTX_MASK | PAB_INTP_MSI_MASK),
> > +		   PAB_INTP_AMBA_MISC_ENB);
> > +
> > +	return 0;
> > +}
> > +
> > +int mobiveil_pcie_host_probe(struct mobiveil_pcie *pcie)
> >  {
> > -	struct mobiveil_pcie *pcie;
> >  	struct pci_bus *bus;
> >  	struct pci_bus *child;
> > -	struct pci_host_bridge *bridge;
> > -	struct device *dev = &pdev->dev;
> > +	struct pci_host_bridge *bridge = pcie->bridge;
> > +	struct device *dev = &pcie->pdev->dev;
> >  	resource_size_t iobase;
> >  	int ret;
> >  
> > -	/* allocate the PCIe port */
> > -	bridge = devm_pci_alloc_host_bridge(dev, sizeof(*pcie));
> > -	if (!bridge)
> > -		return -ENOMEM;
> > -
> > -	pcie = pci_host_bridge_priv(bridge);
> > -
> > -	pcie->pdev = pdev;
> > +	INIT_LIST_HEAD(&pcie->resources);
> >  
> >  	ret = mobiveil_pcie_parse_dt(pcie);
> >  	if (ret) {
> > @@ -875,8 +549,6 @@ static int mobiveil_pcie_probe(struct platform_device *pdev)
> >  		return ret;
> >  	}
> >  
> > -	INIT_LIST_HEAD(&pcie->resources);
> > -
> >  	/* parse the host bridge base addresses from the device tree file */
> >  	ret = devm_of_pci_get_host_bridge_resources(dev, 0, 0xff,
> >  						    &pcie->resources, &iobase);
> > @@ -895,15 +567,12 @@ static int mobiveil_pcie_probe(struct platform_device *pdev)
> >  		goto error;
> >  	}
> >  
> > -	/* initialize the IRQ domains */
> > -	ret = mobiveil_pcie_init_irq_domain(pcie);
> > +	ret = mobiveil_pcie_interrupt_init(pcie);
> >  	if (ret) {
> > -		dev_err(dev, "Failed creating IRQ Domain\n");
> > +		dev_err(dev, "Interrupt init failed\n");
> >  		goto error;
> >  	}
> >  
> > -	irq_set_chained_handler_and_data(pcie->irq, mobiveil_pcie_isr, pcie);
> > -
> >  	ret = devm_request_pci_bus_resources(dev, &pcie->resources);
> >  	if (ret)
> >  		goto error;
> > @@ -912,7 +581,7 @@ static int mobiveil_pcie_probe(struct platform_device *pdev)
> >  	list_splice_init(&pcie->resources, &bridge->windows);
> >  	bridge->dev.parent = dev;
> >  	bridge->sysdata = pcie;
> > -	bridge->busnr = pcie->root_bus_nr;
> > +	bridge->busnr = pcie->rp.root_bus_nr;
> >  	bridge->ops = &mobiveil_pcie_ops;
> >  	bridge->map_irq = of_irq_parse_and_map_pci;
> >  	bridge->swizzle_irq = pci_common_swizzle;
> > @@ -940,25 +609,3 @@ static int mobiveil_pcie_probe(struct platform_device *pdev)
> >  	pci_free_resource_list(&pcie->resources);
> >  	return ret;
> >  }
> > -
> > -static const struct of_device_id mobiveil_pcie_of_match[] = {
> > -	{.compatible = "mbvl,gpex40-pcie",},
> > -	{},
> > -};
> > -
> > -MODULE_DEVICE_TABLE(of, mobiveil_pcie_of_match);
> > -
> > -static struct platform_driver mobiveil_pcie_driver = {
> > -	.probe = mobiveil_pcie_probe,
> > -	.driver = {
> > -		.name = "mobiveil-pcie",
> > -		.of_match_table = mobiveil_pcie_of_match,
> > -		.suppress_bind_attrs = true,
> > -	},
> > -};
> > -
> > -builtin_platform_driver(mobiveil_pcie_driver);
> > -
> > -MODULE_LICENSE("GPL v2");
> > -MODULE_DESCRIPTION("Mobiveil PCIe host controller driver");
> > -MODULE_AUTHOR("Subrahmanya Lingappa <l.subrahmanya@mobiveil.co.in>");
> > diff --git a/drivers/pci/controller/mobiveil/pcie-mobiveil-plat.c b/drivers/pci/controller/mobiveil/pcie-mobiveil-plat.c
> > new file mode 100644
> > index 000000000000..9c62fc58530c
> > --- /dev/null
> > +++ b/drivers/pci/controller/mobiveil/pcie-mobiveil-plat.c
> > @@ -0,0 +1,59 @@
> > +// SPDX-License-Identifier: GPL-2.0
> > +/*
> > + * PCIe host controller driver for Mobiveil PCIe Host controller
> > + *
> > + * Copyright (c) 2018 Mobiveil Inc.
> > + * Copyright 2019 NXP
> > + *
> > + * Author: Subrahmanya Lingappa <l.subrahmanya@mobiveil.co.in>
> > + * Refactor: Zhiqiang Hou <Zhiqiang.Hou@nxp.com>
> > + */
> > +
> > +#include <linux/init.h>
> > +#include <linux/kernel.h>
> > +#include <linux/module.h>
> > +#include <linux/of_pci.h>
> > +#include <linux/pci.h>
> > +#include <linux/platform_device.h>
> > +#include <linux/slab.h>
> > +
> > +#include "pcie-mobiveil.h"
> > +
> > +static int mobiveil_pcie_probe(struct platform_device *pdev)
> > +{
> > +	struct mobiveil_pcie *pcie;
> > +	struct pci_host_bridge *bridge;
> > +	struct device *dev = &pdev->dev;
> > +
> > +	bridge = devm_pci_alloc_host_bridge(dev, sizeof(*pcie));
> > +	if (!bridge)
> > +		return -ENOMEM;
> > +
> > +	pcie = pci_host_bridge_priv(bridge);
> > +
> > +	pcie->pdev = pdev;
> > +
> > +	return mobiveil_pcie_host_probe(pcie);
> > +}
> > +
> > +static const struct of_device_id mobiveil_pcie_of_match[] = {
> > +	{.compatible = "mbvl,gpex40-pcie",},
> > +	{},
> > +};
> > +
> > +MODULE_DEVICE_TABLE(of, mobiveil_pcie_of_match);
> > +
> > +static struct platform_driver mobiveil_pcie_driver = {
> > +	.probe = mobiveil_pcie_probe,
> > +	.driver = {
> > +		.name = "mobiveil-pcie",
> > +		.of_match_table = mobiveil_pcie_of_match,
> > +		.suppress_bind_attrs = true,
> > +	},
> > +};
> > +
> > +builtin_platform_driver(mobiveil_pcie_driver);
> > +
> > +MODULE_LICENSE("GPL v2");
> > +MODULE_DESCRIPTION("Mobiveil PCIe host controller driver");
> > +MODULE_AUTHOR("Subrahmanya Lingappa <l.subrahmanya@mobiveil.co.in>");
> > diff --git a/drivers/pci/controller/mobiveil/pcie-mobiveil.c b/drivers/pci/controller/mobiveil/pcie-mobiveil.c
> > new file mode 100644
> > index 000000000000..94b23be1a06f
> > --- /dev/null
> > +++ b/drivers/pci/controller/mobiveil/pcie-mobiveil.c
> > @@ -0,0 +1,227 @@
> > +// SPDX-License-Identifier: GPL-2.0
> > +/*
> > + * PCIe host controller driver for Mobiveil PCIe Host controller
> > + *
> > + * Copyright (c) 2018 Mobiveil Inc.
> > + * Copyright 2019 NXP
> > + *
> > + * Author: Subrahmanya Lingappa <l.subrahmanya@mobiveil.co.in>
> > + * Refactor: Zhiqiang Hou <Zhiqiang.Hou@nxp.com>
> > + */
> > +
> > +#include <linux/delay.h>
> > +#include <linux/init.h>
> > +#include <linux/kernel.h>
> > +#include <linux/pci.h>
> > +#include <linux/platform_device.h>
> > +
> > +#include "pcie-mobiveil.h"
> > +
> > +/*
> > + * mobiveil_pcie_sel_page - routine to access paged register
> > + *
> > + * Registers whose address greater than PAGED_ADDR_BNDRY (0xc00) are paged,
> > + * for this scheme to work extracted higher 6 bits of the offset will be
> > + * written to pg_sel field of PAB_CTRL register and rest of the lower 10
> > + * bits enabled with PAGED_ADDR_BNDRY are used as offset of the register.
> > + */
> > +static void mobiveil_pcie_sel_page(struct mobiveil_pcie *pcie, u8 pg_idx)
> > +{
> > +	u32 val;
> > +
> > +	val = readl(pcie->csr_axi_slave_base + PAB_CTRL);
> > +	val &= ~(PAGE_SEL_MASK << PAGE_SEL_SHIFT);
> > +	val |= (pg_idx & PAGE_SEL_MASK) << PAGE_SEL_SHIFT;
> > +
> > +	writel(val, pcie->csr_axi_slave_base + PAB_CTRL);
> > +}
> > +
> > +static void *mobiveil_pcie_comp_addr(struct mobiveil_pcie *pcie, u32 off)
> > +{
> > +	if (off < PAGED_ADDR_BNDRY) {
> > +		/* For directly accessed registers, clear the pg_sel field */
> > +		mobiveil_pcie_sel_page(pcie, 0);
> > +		return pcie->csr_axi_slave_base + off;
> > +	}
> > +
> > +	mobiveil_pcie_sel_page(pcie, OFFSET_TO_PAGE_IDX(off));
> > +	return pcie->csr_axi_slave_base + OFFSET_TO_PAGE_ADDR(off);
> > +}
> > +
> > +static int mobiveil_pcie_read(void __iomem *addr, int size, u32 *val)
> > +{
> > +	if ((uintptr_t)addr & (size - 1)) {
> > +		*val = 0;
> > +		return PCIBIOS_BAD_REGISTER_NUMBER;
> > +	}
> > +
> > +	switch (size) {
> > +	case 4:
> > +		*val = readl(addr);
> > +		break;
> > +	case 2:
> > +		*val = readw(addr);
> > +		break;
> > +	case 1:
> > +		*val = readb(addr);
> > +		break;
> > +	default:
> > +		*val = 0;
> > +		return PCIBIOS_BAD_REGISTER_NUMBER;
> > +	}
> > +
> > +	return PCIBIOS_SUCCESSFUL;
> > +}
> > +
> > +static int mobiveil_pcie_write(void __iomem *addr, int size, u32 val)
> > +{
> > +	if ((uintptr_t)addr & (size - 1))
> > +		return PCIBIOS_BAD_REGISTER_NUMBER;
> > +
> > +	switch (size) {
> > +	case 4:
> > +		writel(val, addr);
> > +		break;
> > +	case 2:
> > +		writew(val, addr);
> > +		break;
> > +	case 1:
> > +		writeb(val, addr);
> > +		break;
> > +	default:
> > +		return PCIBIOS_BAD_REGISTER_NUMBER;
> > +	}
> > +
> > +	return PCIBIOS_SUCCESSFUL;
> > +}
> > +
> > +u32 csr_read(struct mobiveil_pcie *pcie, u32 off, size_t size)
> > +{
> > +	void *addr;
> > +	u32 val;
> > +	int ret;
> > +
> > +	addr = mobiveil_pcie_comp_addr(pcie, off);
> > +
> > +	ret = mobiveil_pcie_read(addr, size, &val);
> > +	if (ret)
> > +		dev_err(&pcie->pdev->dev, "read CSR address failed\n");
> > +
> > +	return val;
> > +}
> > +
> > +void csr_write(struct mobiveil_pcie *pcie, u32 val, u32 off, size_t size)
> > +{
> > +	void *addr;
> > +	int ret;
> > +
> > +	addr = mobiveil_pcie_comp_addr(pcie, off);
> > +
> > +	ret = mobiveil_pcie_write(addr, size, val);
> > +	if (ret)
> > +		dev_err(&pcie->pdev->dev, "write CSR address failed\n");
> > +}
> > +
> > +bool mobiveil_pcie_link_up(struct mobiveil_pcie *pcie)
> > +{
> > +	if (pcie->ops->link_up)
> > +		return pcie->ops->link_up(pcie);
> > +
> > +	return (csr_readl(pcie, LTSSM_STATUS) &
> > +		LTSSM_STATUS_L0_MASK) == LTSSM_STATUS_L0;
> > +}
> > +
> > +void program_ib_windows(struct mobiveil_pcie *pcie, int win_num, u64 cpu_addr,
> > +			u64 pci_addr, u32 type, u64 size)
> > +{
> > +	u32 value;
> > +	u64 size64 = ~(size - 1);
> > +
> > +	if (win_num >= pcie->ppio_wins) {
> > +		dev_err(&pcie->pdev->dev,
> > +			"ERROR: max inbound windows reached !\n");
> > +		return;
> > +	}
> > +
> > +	value = csr_readl(pcie, PAB_PEX_AMAP_CTRL(win_num));
> > +	value &= ~(AMAP_CTRL_TYPE_MASK << AMAP_CTRL_TYPE_SHIFT | WIN_SIZE_MASK);
> > +	value |= type << AMAP_CTRL_TYPE_SHIFT | 1 << AMAP_CTRL_EN_SHIFT |
> > +		 (lower_32_bits(size64) & WIN_SIZE_MASK);
> > +	csr_writel(pcie, value, PAB_PEX_AMAP_CTRL(win_num));
> > +
> > +	csr_writel(pcie, upper_32_bits(size64),
> > +		   PAB_EXT_PEX_AMAP_SIZEN(win_num));
> > +
> > +	csr_writel(pcie, lower_32_bits(cpu_addr),
> > +		   PAB_PEX_AMAP_AXI_WIN(win_num));
> > +	csr_writel(pcie, upper_32_bits(cpu_addr),
> > +		   PAB_EXT_PEX_AMAP_AXI_WIN(win_num));
> > +
> > +	csr_writel(pcie, lower_32_bits(pci_addr),
> > +		   PAB_PEX_AMAP_PEX_WIN_L(win_num));
> > +	csr_writel(pcie, upper_32_bits(pci_addr),
> > +		   PAB_PEX_AMAP_PEX_WIN_H(win_num));
> > +
> > +	pcie->ib_wins_configured++;
> > +}
> > +
> > +/*
> > + * routine to program the outbound windows
> > + */
> > +void program_ob_windows(struct mobiveil_pcie *pcie, int win_num, u64 cpu_addr,
> > +			u64 pci_addr, u32 type, u64 size)
> > +{
> > +	u32 value;
> > +	u64 size64 = ~(size - 1);
> > +
> > +	if (win_num >= pcie->apio_wins) {
> > +		dev_err(&pcie->pdev->dev,
> > +			"ERROR: max outbound windows reached !\n");
> > +		return;
> > +	}
> > +
> > +	/*
> > +	 * program Enable Bit to 1, Type Bit to (00) base 2, AXI Window Size Bit
> > +	 * to 4 KB in PAB_AXI_AMAP_CTRL register
> > +	 */
> > +	value = csr_readl(pcie, PAB_AXI_AMAP_CTRL(win_num));
> > +	value &= ~(WIN_TYPE_MASK << WIN_TYPE_SHIFT | WIN_SIZE_MASK);
> > +	value |= 1 << WIN_ENABLE_SHIFT | type << WIN_TYPE_SHIFT |
> > +		 (lower_32_bits(size64) & WIN_SIZE_MASK);
> > +	csr_writel(pcie, value, PAB_AXI_AMAP_CTRL(win_num));
> > +
> > +	csr_writel(pcie, upper_32_bits(size64), PAB_EXT_AXI_AMAP_SIZE(win_num));
> > +
> > +	/*
> > +	 * program AXI window base with appropriate value in
> > +	 * PAB_AXI_AMAP_AXI_WIN0 register
> > +	 */
> > +	csr_writel(pcie, lower_32_bits(cpu_addr) & (~AXI_WINDOW_ALIGN_MASK),
> > +		   PAB_AXI_AMAP_AXI_WIN(win_num));
> > +	csr_writel(pcie, upper_32_bits(cpu_addr),
> > +		   PAB_EXT_AXI_AMAP_AXI_WIN(win_num));
> > +
> > +	csr_writel(pcie, lower_32_bits(pci_addr),
> > +		   PAB_AXI_AMAP_PEX_WIN_L(win_num));
> > +	csr_writel(pcie, upper_32_bits(pci_addr),
> > +		   PAB_AXI_AMAP_PEX_WIN_H(win_num));
> > +
> > +	pcie->ob_wins_configured++;
> > +}
> > +
> > +int mobiveil_bringup_link(struct mobiveil_pcie *pcie)
> > +{
> > +	int retries;
> > +
> > +	/* check if the link is up or not */
> > +	for (retries = 0; retries < LINK_WAIT_MAX_RETRIES; retries++) {
> > +		if (mobiveil_pcie_link_up(pcie))
> > +			return 0;
> > +
> > +		usleep_range(LINK_WAIT_MIN, LINK_WAIT_MAX);
> > +	}
> > +
> > +	dev_err(&pcie->pdev->dev, "link never came up\n");
> > +
> > +	return -ETIMEDOUT;
> > +}
> > diff --git a/drivers/pci/controller/mobiveil/pcie-mobiveil.h b/drivers/pci/controller/mobiveil/pcie-mobiveil.h
> > new file mode 100644
> > index 000000000000..4825e30030cd
> > --- /dev/null
> > +++ b/drivers/pci/controller/mobiveil/pcie-mobiveil.h
> > @@ -0,0 +1,189 @@
> > +/* SPDX-License-Identifier: GPL-2.0 */
> > +/*
> > + * PCIe host controller driver for Mobiveil PCIe Host controller
> > + *
> > + * Copyright (c) 2018 Mobiveil Inc.
> > + * Copyright 2019 NXP
> > + *
> > + * Author: Subrahmanya Lingappa <l.subrahmanya@mobiveil.co.in>
> > + * Refactor: Zhiqiang Hou <Zhiqiang.Hou@nxp.com>
> > + */
> > +
> > +#ifndef _PCIE_MOBIVEIL_H
> > +#define _PCIE_MOBIVEIL_H
> > +
> > +#include <linux/pci.h>
> > +#include <linux/irq.h>
> > +#include <linux/msi.h>
> > +#include "../../pci.h"
> > +
> > +/* register offsets and bit positions */
> > +
> > +/*
> > + * translation tables are grouped into windows, each window registers are
> > + * grouped into blocks of 4 or 16 registers each
> > + */
> > +#define PAB_REG_BLOCK_SIZE		16
> > +#define PAB_EXT_REG_BLOCK_SIZE		4
> > +
> > +#define PAB_REG_ADDR(offset, win)	\
> > +	(offset + (win * PAB_REG_BLOCK_SIZE))
> > +#define PAB_EXT_REG_ADDR(offset, win)	\
> > +	(offset + (win * PAB_EXT_REG_BLOCK_SIZE))
> > +
> > +#define LTSSM_STATUS			0x0404
> > +#define  LTSSM_STATUS_L0_MASK		0x3f
> > +#define  LTSSM_STATUS_L0		0x2d
> > +
> > +#define PAB_CTRL			0x0808
> > +#define  AMBA_PIO_ENABLE_SHIFT		0
> > +#define  PEX_PIO_ENABLE_SHIFT		1
> > +#define  PAGE_SEL_SHIFT			13
> > +#define  PAGE_SEL_MASK			0x3f
> > +#define  PAGE_LO_MASK			0x3ff
> > +#define  PAGE_SEL_OFFSET_SHIFT		10
> > +
> > +#define PAB_AXI_PIO_CTRL		0x0840
> > +#define  APIO_EN_MASK			0xf
> > +
> > +#define PAB_PEX_PIO_CTRL		0x08c0
> > +#define  PIO_ENABLE_SHIFT		0
> > +
> > +#define PAB_INTP_AMBA_MISC_ENB		0x0b0c
> > +#define PAB_INTP_AMBA_MISC_STAT		0x0b1c
> > +#define  PAB_INTP_INTX_MASK		0x01e0
> > +#define  PAB_INTP_MSI_MASK		0x8
> > +
> > +#define PAB_AXI_AMAP_CTRL(win)		PAB_REG_ADDR(0x0ba0, win)
> > +#define  WIN_ENABLE_SHIFT		0
> > +#define  WIN_TYPE_SHIFT			1
> > +#define  WIN_TYPE_MASK			0x3
> > +#define  WIN_SIZE_MASK			0xfffffc00
> > +
> > +#define PAB_EXT_AXI_AMAP_SIZE(win)	PAB_EXT_REG_ADDR(0xbaf0, win)
> > +
> > +#define PAB_EXT_AXI_AMAP_AXI_WIN(win)	PAB_EXT_REG_ADDR(0x80a0, win)
> > +#define PAB_AXI_AMAP_AXI_WIN(win)	PAB_REG_ADDR(0x0ba4, win)
> > +#define  AXI_WINDOW_ALIGN_MASK		3
> > +
> > +#define PAB_AXI_AMAP_PEX_WIN_L(win)	PAB_REG_ADDR(0x0ba8, win)
> > +#define  PAB_BUS_SHIFT			24
> > +#define  PAB_DEVICE_SHIFT		19
> > +#define  PAB_FUNCTION_SHIFT		16
> > +
> > +#define PAB_AXI_AMAP_PEX_WIN_H(win)	PAB_REG_ADDR(0x0bac, win)
> > +#define PAB_INTP_AXI_PIO_CLASS		0x474
> > +
> > +#define PAB_PEX_AMAP_CTRL(win)		PAB_REG_ADDR(0x4ba0, win)
> > +#define  AMAP_CTRL_EN_SHIFT		0
> > +#define  AMAP_CTRL_TYPE_SHIFT		1
> > +#define  AMAP_CTRL_TYPE_MASK		3
> > +
> > +#define PAB_EXT_PEX_AMAP_SIZEN(win)	PAB_EXT_REG_ADDR(0xbef0, win)
> > +#define PAB_EXT_PEX_AMAP_AXI_WIN(win)	PAB_EXT_REG_ADDR(0xb4a0, win)
> > +#define PAB_PEX_AMAP_AXI_WIN(win)	PAB_REG_ADDR(0x4ba4, win)
> > +#define PAB_PEX_AMAP_PEX_WIN_L(win)	PAB_REG_ADDR(0x4ba8, win)
> > +#define PAB_PEX_AMAP_PEX_WIN_H(win)	PAB_REG_ADDR(0x4bac, win)
> > +
> > +/* starting offset of INTX bits in status register */
> > +#define PAB_INTX_START			5
> > +
> > +/* supported number of MSI interrupts */
> > +#define PCI_NUM_MSI			16
> > +
> > +/* MSI registers */
> > +#define MSI_BASE_LO_OFFSET		0x04
> > +#define MSI_BASE_HI_OFFSET		0x08
> > +#define MSI_SIZE_OFFSET			0x0c
> > +#define MSI_ENABLE_OFFSET		0x14
> > +#define MSI_STATUS_OFFSET		0x18
> > +#define MSI_DATA_OFFSET			0x20
> > +#define MSI_ADDR_L_OFFSET		0x24
> > +#define MSI_ADDR_H_OFFSET		0x28
> > +
> > +/* outbound and inbound window definitions */
> > +#define WIN_NUM_0			0
> > +#define WIN_NUM_1			1
> > +#define CFG_WINDOW_TYPE			0
> > +#define IO_WINDOW_TYPE			1
> > +#define MEM_WINDOW_TYPE			2
> > +#define IB_WIN_SIZE			((u64)256 * 1024 * 1024 * 1024)
> > +#define MAX_PIO_WINDOWS			8
> > +
> > +/* Parameters for the waiting for link up routine */
> > +#define LINK_WAIT_MAX_RETRIES		10
> > +#define LINK_WAIT_MIN			90000
> > +#define LINK_WAIT_MAX			100000
> > +
> > +#define PAGED_ADDR_BNDRY		0xc00
> > +#define OFFSET_TO_PAGE_ADDR(off)	\
> > +	((off & PAGE_LO_MASK) | PAGED_ADDR_BNDRY)
> > +#define OFFSET_TO_PAGE_IDX(off)		\
> > +	((off >> PAGE_SEL_OFFSET_SHIFT) & PAGE_SEL_MASK)
> > +
> > +struct mobiveil_pcie;
> > +
> > +struct mobiveil_msi {			/* MSI information */
> > +	struct mutex lock;		/* protect bitmap variable */
> > +	struct irq_domain *msi_domain;
> > +	struct irq_domain *dev_domain;
> > +	phys_addr_t msi_pages_phys;
> > +	int num_of_vectors;
> > +	DECLARE_BITMAP(msi_irq_in_use, PCI_NUM_MSI);
> > +};
> > +
> > +struct mobiveil_rp_ops {
> > +	int (*interrupt_init)(struct mobiveil_pcie *pcie);
> > +};
> > +
> > +struct root_port {
> > +	u8 root_bus_nr;
> > +	void __iomem *config_axi_slave_base;	/* endpoint config base */
> > +	struct resource *ob_io_res;
> > +	struct mobiveil_rp_ops *ops;
> > +	int irq;
> > +	raw_spinlock_t intx_mask_lock;
> > +	struct irq_domain *intx_domain;
> > +	struct mobiveil_msi msi;
> > +};
> > +
> > +struct mobiveil_pab_ops {
> > +	int (*link_up)(struct mobiveil_pcie *pcie);
> > +};
> > +
> > +struct mobiveil_pcie {
> > +	struct platform_device *pdev;
> > +	struct list_head resources;
> > +	void __iomem *csr_axi_slave_base;	/* PAB registers base */
> > +	phys_addr_t pcie_reg_base;	/* Physical PCIe Controller Base */
> > +	void __iomem *apb_csr_base;	/* MSI register base */
> > +	u32 apio_wins;
> > +	u32 ppio_wins;
> > +	u32 ob_wins_configured;		/* configured outbound windows */
> > +	u32 ib_wins_configured;		/* configured inbound windows */
> > +	const struct mobiveil_pab_ops *ops;
> > +	struct root_port rp;
> > +	struct pci_host_bridge *bridge;
> > +};
> > +
> > +int mobiveil_pcie_host_probe(struct mobiveil_pcie *pcie);
> > +bool mobiveil_pcie_link_up(struct mobiveil_pcie *pcie);
> > +int mobiveil_bringup_link(struct mobiveil_pcie *pcie);
> > +void program_ob_windows(struct mobiveil_pcie *pcie, int win_num, u64 cpu_addr,
> > +			u64 pci_addr, u32 type, u64 size);
> > +void program_ib_windows(struct mobiveil_pcie *pcie, int win_num, u64 cpu_addr,
> > +			u64 pci_addr, u32 type, u64 size);
> > +u32 csr_read(struct mobiveil_pcie *pcie, u32 off, size_t size);
> > +void csr_write(struct mobiveil_pcie *pcie, u32 val, u32 off, size_t size);
> > +
> > +static inline u32 csr_readl(struct mobiveil_pcie *pcie, u32 off)
> > +{
> > +	return csr_read(pcie, off, 0x4);
> > +}
> > +
> > +static inline void csr_writel(struct mobiveil_pcie *pcie, u32 val, u32 off)
> > +{
> > +	csr_write(pcie, val, off, 0x4);
> > +}
> > +
> > +#endif /* _PCIE_MOBIVEIL_H */
> > -- 
> > 2.17.1
> > 

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply

* [RESEND PATCH v2] coresight: etm4x: Add support for ThunderX2
From: Tanmay Vilas Kumar Jagdale @ 2019-09-18 11:04 UTC (permalink / raw)
  To: mathieu.poirier@linaro.org
  Cc: Ganapatrao Kulkarni, Tomasz Nowicki, suzuki.poulose@arm.com,
	Jayachandran Chandrasekharan Nair, Tanmay Vilas Kumar Jagdale,
	linux-arm-kernel@lists.infradead.org

From: Tanmay Vilas Kumar Jagdale <tanmay@marvell.com>

Add ETMv4 periperhal ID for Marvell's ThunderX2 chip.
This chip contains ETMv4.1 version.

Signed-off-by: Tanmay Vilas Kumar Jagdale <tanmay@marvell.com>
---
- Updated with full name "Tanmay Vilas Kumar Jagdale" instead of
  "Tanmay Jagdale".

[0] https://patchwork.kernel.org/patch/11138743/

 drivers/hwtracing/coresight/coresight-etm4x.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/drivers/hwtracing/coresight/coresight-etm4x.c b/drivers/hwtracing/coresight/coresight-etm4x.c
index a128b5063f46..47839b4a8bc0 100644
--- a/drivers/hwtracing/coresight/coresight-etm4x.c
+++ b/drivers/hwtracing/coresight/coresight-etm4x.c
@@ -1211,6 +1211,7 @@ static const struct amba_id etm4_ids[] = {
 	CS_AMBA_UCI_ID(0x000f0211, uci_id_etm4),/* Qualcomm Kryo */
 	CS_AMBA_ID(0x000bb802),			/* Qualcomm Kryo 385 Cortex-A55 */
 	CS_AMBA_ID(0x000bb803),			/* Qualcomm Kryo 385 Cortex-A75 */
+	CS_AMBA_UCI_ID(0x000cc0af, uci_id_etm4),/* Marvell ThunderX2 */
 	{},
 };
 
-- 
2.17.1


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply related

* [PATCH v3] pinctrl: at91-pio4: implement .get_multiple and .set_multiple
From: Alexandre Belloni @ 2019-09-18 11:36 UTC (permalink / raw)
  To: Linus Walleij
  Cc: Alexandre Belloni, linux-kernel, linux-gpio, Ludovic Desroches,
	Claudiu.Beznea, linux-arm-kernel

Implement .get_multiple and .set_multiple to allow reading or setting
multiple pins simultaneously. Pins in the same bank will all be switched at
the same time, improving synchronization and performances.

Keep the driver future proof by allowing its use on 64bits platforms if
they ever appear with this IP and we end up with a mismatch between
ATMEL_PIO_NPINS_PER_BANK and BITS_PER_LONG.

Signed-off-by: Alexandre Belloni <alexandre.belloni@bootlin.com>
Acked-by: Ludovic Desroches <ludovic.desroches@microchip.com>
---

Changes in v3:
 - Add ack from ludovic
 - add comment and amend commit message to explain the ifdefd

 drivers/pinctrl/pinctrl-at91-pio4.c | 62 +++++++++++++++++++++++++++++
 1 file changed, 62 insertions(+)

diff --git a/drivers/pinctrl/pinctrl-at91-pio4.c b/drivers/pinctrl/pinctrl-at91-pio4.c
index d6de4d360cd4..e380202eb86a 100644
--- a/drivers/pinctrl/pinctrl-at91-pio4.c
+++ b/drivers/pinctrl/pinctrl-at91-pio4.c
@@ -328,6 +328,33 @@ static int atmel_gpio_get(struct gpio_chip *chip, unsigned offset)
 	return !!(reg & BIT(pin->line));
 }
 
+static int atmel_gpio_get_multiple(struct gpio_chip *chip, unsigned long *mask,
+				   unsigned long *bits)
+{
+	struct atmel_pioctrl *atmel_pioctrl = gpiochip_get_data(chip);
+	unsigned int bank;
+
+	bitmap_zero(bits, atmel_pioctrl->npins);
+
+	for (bank = 0; bank < atmel_pioctrl->nbanks; bank++) {
+		unsigned int word = bank;
+		unsigned int offset = 0;
+		unsigned int reg;
+
+#if ATMEL_PIO_NPINS_PER_BANK != BITS_PER_LONG
+		word = BIT_WORD(bank * ATMEL_PIO_NPINS_PER_BANK);
+		offset = bank * ATMEL_PIO_NPINS_PER_BANK % BITS_PER_LONG;
+#endif
+		if (!mask[word])
+			continue;
+
+		reg = atmel_gpio_read(atmel_pioctrl, bank, ATMEL_PIO_PDSR);
+		bits[word] |= mask[word] & (reg << offset);
+	}
+
+	return 0;
+}
+
 static int atmel_gpio_direction_output(struct gpio_chip *chip, unsigned offset,
 				       int value)
 {
@@ -358,11 +385,46 @@ static void atmel_gpio_set(struct gpio_chip *chip, unsigned offset, int val)
 			 BIT(pin->line));
 }
 
+static void atmel_gpio_set_multiple(struct gpio_chip *chip, unsigned long *mask,
+				    unsigned long *bits)
+{
+	struct atmel_pioctrl *atmel_pioctrl = gpiochip_get_data(chip);
+	unsigned int bank;
+
+	for (bank = 0; bank < atmel_pioctrl->nbanks; bank++) {
+		unsigned int bitmask;
+		unsigned int word = bank;
+
+/*
+ * On a 64-bit platform, BITS_PER_LONG is 64 so it is necessary to iterate over
+ * two 32bit words to handle the whole  bitmask
+ */
+#if ATMEL_PIO_NPINS_PER_BANK != BITS_PER_LONG
+		word = BIT_WORD(bank * ATMEL_PIO_NPINS_PER_BANK);
+#endif
+		if (!mask[word])
+			continue;
+
+		bitmask = mask[word] & bits[word];
+		atmel_gpio_write(atmel_pioctrl, bank, ATMEL_PIO_SODR, bitmask);
+
+		bitmask = mask[word] & ~bits[word];
+		atmel_gpio_write(atmel_pioctrl, bank, ATMEL_PIO_CODR, bitmask);
+
+#if ATMEL_PIO_NPINS_PER_BANK != BITS_PER_LONG
+		mask[word] >>= ATMEL_PIO_NPINS_PER_BANK;
+		bits[word] >>= ATMEL_PIO_NPINS_PER_BANK;
+#endif
+	}
+}
+
 static struct gpio_chip atmel_gpio_chip = {
 	.direction_input        = atmel_gpio_direction_input,
 	.get                    = atmel_gpio_get,
+	.get_multiple           = atmel_gpio_get_multiple,
 	.direction_output       = atmel_gpio_direction_output,
 	.set                    = atmel_gpio_set,
+	.set_multiple           = atmel_gpio_set_multiple,
 	.to_irq                 = atmel_gpio_to_irq,
 	.base                   = 0,
 };
-- 
2.21.0


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply related


This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox