LKML Archive on lore.kernel.org
help / color / mirror / Atom feed
* [PATCH 0/6] Add initial support for Broadcom Cygnus SoC 
       [not found] <Jonathan Richardson <jonathar@broadcom.com>
@ 2014-09-16 19:58 ` Jonathan Richardson
  2014-09-16 19:58   ` [PATCH 1/6] ARM: cygnus: Initial " Jonathan Richardson
                     ` (6 more replies)
  2014-09-23 21:17 ` [PATCH v2 " Jonathan Richardson
                   ` (12 subsequent siblings)
  13 siblings, 7 replies; 92+ messages in thread
From: Jonathan Richardson @ 2014-09-16 19:58 UTC (permalink / raw)
  To: Christian Daudt, Matt Porter, Russell King, Mike Turquette,
	Rob Herring, Pawel Moll, Mark Rutland, Ian Campbell, Kumar Gala,
	JD Zheng
  Cc: linux-arm-kernel, bcm-kernel-feedback-list, linux-kernel,
	devicetree, Scott Branden, Ray Jui, Jonathan Richardson

Hi,

This patchset contains initial support for Broadcom's Cygnus SoC based on our
iProc architecture. Initial support is minimal and includes just the mach
platform code, clock driver, and a basic device tree configuration. Peripheral
drivers will be submitted soon, as will device tree configurations for other
Cygnus board variants.

Jonathan Richardson (5):
  ARM: cygnus: Initial support for Broadcom Cygnus SoC
  clk: Clock driver support for Broadcom Cygnus SoC
  dt-bindings: Document Broadcom Cygnus SoC and clock driver
  ARM: dts: Enable Broadcom Cygnus SoC
  ARM: cygnus defconfig : Initial defconfig for Broadcom Cygnus SoC
  MAINTAINERS: Entry for Cygnus/iproc arm architecture and clock
    drivers

 Documentation/devicetree/bindings/arm/cygnus.txt   |   12 +
 .../devicetree/bindings/clock/clk-cygnus.txt       |  121 ++
 .../devicetree/bindings/clock/clk-iproc.txt        |   48 +
 MAINTAINERS                                        |   21 +
 arch/arm/boot/dts/Makefile                         |    1 +
 arch/arm/boot/dts/bcm-cygnus.dtsi                  |  344 ++++++
 arch/arm/boot/dts/bcm911360_entphn.dts             |   17 +
 arch/arm/configs/bcm_cygnus_defconfig              |  223 ++++
 arch/arm/mach-bcm/Kconfig                          |   34 +
 arch/arm/mach-bcm/Makefile                         |    3 +
 arch/arm/mach-bcm/board_bcm_cygnus.c               |  166 +++
 drivers/clk/Makefile                               |    1 +
 drivers/clk/bcm/Makefile                           |    2 +
 drivers/clk/bcm/clk-cygnus.c                       | 1179 ++++++++++++++++++++
 drivers/clk/bcm/clk-iproc.c                        |  446 ++++++++
 15 files changed, 2618 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/arm/cygnus.txt
 create mode 100644 Documentation/devicetree/bindings/clock/clk-cygnus.txt
 create mode 100644 Documentation/devicetree/bindings/clock/clk-iproc.txt
 create mode 100644 arch/arm/boot/dts/bcm-cygnus.dtsi
 create mode 100644 arch/arm/boot/dts/bcm911360_entphn.dts
 create mode 100644 arch/arm/configs/bcm_cygnus_defconfig
 create mode 100644 arch/arm/mach-bcm/board_bcm_cygnus.c
 create mode 100644 drivers/clk/bcm/clk-cygnus.c
 create mode 100644 drivers/clk/bcm/clk-iproc.c

-- 
1.7.9.5


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

* [PATCH 1/6] ARM: cygnus: Initial support for Broadcom Cygnus SoC
  2014-09-16 19:58 ` [PATCH 0/6] Add initial support for Broadcom Cygnus SoC Jonathan Richardson
@ 2014-09-16 19:58   ` Jonathan Richardson
  2014-09-17  0:00     ` Mark Rutland
  2014-09-16 19:58   ` [PATCH 2/6] clk: Clock driver " Jonathan Richardson
                     ` (5 subsequent siblings)
  6 siblings, 1 reply; 92+ messages in thread
From: Jonathan Richardson @ 2014-09-16 19:58 UTC (permalink / raw)
  To: Christian Daudt, Matt Porter, Russell King, Mike Turquette,
	Rob Herring, Pawel Moll, Mark Rutland, Ian Campbell, Kumar Gala,
	JD Zheng
  Cc: linux-arm-kernel, bcm-kernel-feedback-list, linux-kernel,
	devicetree, Scott Branden, Ray Jui, Jonathan Richardson

Adds initial support for the Cygnus SoC based on Broadcom’s iProc series.

Reviewed-by: Ray Jui <rjui@broadcom.com>
Reviewed-by: Desmond Liu <desmondl@broadcom.com>
Reviewed-by: JD (Jiandong) Zheng <jdzheng@broadcom.com>
Tested-by: Jonathan Richardson <jonathar@broadcom.com>
Signed-off-by: Jonathan Richardson <jonathar@broadcom.com>
---
 arch/arm/mach-bcm/Kconfig            |   34 +++++++
 arch/arm/mach-bcm/Makefile           |    3 +
 arch/arm/mach-bcm/board_bcm_cygnus.c |  166 ++++++++++++++++++++++++++++++++++
 3 files changed, 203 insertions(+)
 create mode 100644 arch/arm/mach-bcm/board_bcm_cygnus.c

diff --git a/arch/arm/mach-bcm/Kconfig b/arch/arm/mach-bcm/Kconfig
index fc93800..58e0f20 100644
--- a/arch/arm/mach-bcm/Kconfig
+++ b/arch/arm/mach-bcm/Kconfig
@@ -5,6 +5,40 @@ menuconfig ARCH_BCM
 
 if ARCH_BCM
 
+config ARCH_BCM_IPROC
+	bool "Broadcom ARMv7 iProc boards" if ARCH_MULTI_V7
+	select ARM_GIC
+	select CACHE_L2X0
+	select HAVE_ARM_SCU if SMP
+	select HAVE_ARM_TWD if LOCAL_TIMERS
+	select HAVE_CLK
+	select CLKSRC_OF
+	select CLKSRC_MMIO
+	select LOCAL_TIMERS if SMP
+	select GENERIC_CLOCKEVENTS_BUILD
+	select GENERIC_CLOCKEVENTS
+	select ARM_GLOBAL_TIMER
+	select ARCH_REQUIRE_GPIOLIB
+	select ARM_AMBA
+	select PINCTRL
+	select DEBUG_UART_8250
+	help
+	  This enables support for systems based on Broadcom IPROC architected SoCs.
+	  The IPROC complex contains one or more ARM CPUs along with common
+	  core periperals. Application specific SoCs are created by adding a
+	  uArchitecture containing peripherals outside of the IPROC complex.
+	  Currently supported SoCs are Cygnus.
+
+menu "iProc SoC based Machine types"
+	depends on ARCH_BCM_IPROC
+
+	config ARCH_BCM_CYGNUS
+		bool "Support Broadcom Cygnus board"
+		select USB_ARCH_HAS_EHCI if USB_SUPPORT
+		help
+		  Support for Broadcom Cygnus SoC.
+endmenu
+
 config ARCH_BCM_MOBILE
 	bool "Broadcom Mobile SoC Support" if ARCH_MULTI_V7
 	select ARCH_REQUIRE_GPIOLIB
diff --git a/arch/arm/mach-bcm/Makefile b/arch/arm/mach-bcm/Makefile
index b19a396..dd14a10 100644
--- a/arch/arm/mach-bcm/Makefile
+++ b/arch/arm/mach-bcm/Makefile
@@ -10,6 +10,9 @@
 # of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 # GNU General Public License for more details.
 
+# Cygnus
+obj-$(CONFIG_ARCH_BCM_CYGNUS) +=  board_bcm_cygnus.o
+
 # BCM281XX
 obj-$(CONFIG_ARCH_BCM_281XX)	+= board_bcm281xx.o
 
diff --git a/arch/arm/mach-bcm/board_bcm_cygnus.c b/arch/arm/mach-bcm/board_bcm_cygnus.c
new file mode 100644
index 0000000..d67555a
--- /dev/null
+++ b/arch/arm/mach-bcm/board_bcm_cygnus.c
@@ -0,0 +1,166 @@
+/*
+ * Copyright 2014 Broadcom Corporation.  All rights reserved.
+ *
+ * Unless you and Broadcom execute a separate written software license
+ * agreement governing use of this software, this software is licensed to you
+ * under the terms of the GNU General Public License version 2, available at
+ * http://www.broadcom.com/licenses/GPLv2.php (the "GPL").
+ */
+
+#include <linux/of_address.h>
+#include <linux/of_platform.h>
+#include <linux/clocksource.h>
+#include <linux/clk-provider.h>
+#include <linux/delay.h>
+#include <asm/mach/arch.h>
+#include <asm/mach/map.h>
+#include <asm/proc-fns.h>
+#include <asm/hardware/cache-l2x0.h>
+
+#define CRMU_MAIL_BOX1      0x03024028
+#define CRMU_SOFT_RESET_CMD 0xFFFFFFFF
+
+/* CRU_RESET register */
+static void * __iomem crmu_mail_box1_reg;
+
+#ifdef CONFIG_NEON
+
+#define CRU_BASE                  0x1800e000
+#define CRU_SIZE                  0x34
+#define CRU_CONTROL_OFFSET        0x0
+#define CRU_PWRDWN_EN_OFFSET      0x4
+#define CRU_PWRDWN_STATUS_OFFSET  0x8
+#define CRU_NEON0_HW_RESET  6
+#define CRU_CLAMP_ON_NEON0  20
+#define CRU_PWRONIN_NEON0   21
+#define CRU_PWRONOUT_NEON0  21
+#define CRU_PWROKIN_NEON0   22
+#define CRU_PWROKOUT_NEON0  22
+#define CRU_STATUS_DELAY_NS 500
+#define CRU_MAX_RETRY_COUNT 10
+#define CRU_RETRY_INTVL_US  1
+
+/* Power up the NEON/VFPv3 block. */
+static void bcm_cygnus_powerup_neon(void)
+{
+	void * __iomem cru_base = ioremap_nocache(CRU_BASE, CRU_SIZE);
+	u32 reg, i;
+
+	BUG_ON(!cru_base);
+
+	/* De-assert the neon hardware block reset */
+	reg = readl(cru_base + CRU_CONTROL_OFFSET);
+	reg &= ~(1 << CRU_NEON0_HW_RESET);
+	writel(reg, cru_base + CRU_CONTROL_OFFSET);
+
+	/* Assert the power ON register bit */
+	reg = readl(cru_base + CRU_PWRDWN_EN_OFFSET);
+	reg |= (1 << CRU_PWRONIN_NEON0);
+	writel(reg, cru_base + CRU_PWRDWN_EN_OFFSET);
+
+	/*
+	 * Wait up to 10 usec in 1 usec increments for the
+	 * status register to acknowledge the power ON assert
+	 */
+	for (i = 0; i < CRU_MAX_RETRY_COUNT; i++) {
+		reg = readl(cru_base + CRU_PWRDWN_STATUS_OFFSET);
+		if (reg & CRU_PWRONOUT_NEON0)
+			break;
+
+		udelay(CRU_RETRY_INTVL_US);
+	}
+
+	if (i == CRU_MAX_RETRY_COUNT)
+		panic("NEON power ON register not acknowledged\n");
+
+	/* Wait 0.5 usec = 500 nsec */
+	ndelay(CRU_STATUS_DELAY_NS);
+
+	/* Assert the power OK register bit */
+	reg = readl(cru_base + CRU_PWRDWN_EN_OFFSET);
+	reg |= (1 << CRU_PWROKIN_NEON0);
+	writel(reg, cru_base + CRU_PWRDWN_EN_OFFSET);
+
+	/*
+	 * Wait up to 10 usec in 1 usec increments for the
+	 * status register to acknowledge the power OK assert
+	 */
+	for (i = 0; i < CRU_MAX_RETRY_COUNT; i++) {
+		reg = readl(cru_base + CRU_PWRDWN_STATUS_OFFSET);
+		if (reg & CRU_PWROKOUT_NEON0)
+			break;
+
+		udelay(CRU_RETRY_INTVL_US);
+	}
+
+	if (i == CRU_MAX_RETRY_COUNT)
+		panic("NEON power OK register not acknowledged\n");
+
+	/* Wait 0.5 usec = 500 nsec */
+	ndelay(CRU_STATUS_DELAY_NS);
+
+	/* Set the logic clamp for the neon block */
+	reg = readl(cru_base + CRU_PWRDWN_EN_OFFSET);
+	reg &= ~(1 << CRU_CLAMP_ON_NEON0);
+	writel(reg, cru_base + CRU_PWRDWN_EN_OFFSET);
+
+	/* Wait 0.5 usec = 500 nsec */
+	ndelay(CRU_STATUS_DELAY_NS);
+
+	/* Reset the neon hardware block */
+	reg = readl(cru_base + CRU_CONTROL_OFFSET);
+	reg |= (1 << CRU_NEON0_HW_RESET);
+	writel(reg, cru_base + CRU_CONTROL_OFFSET);
+
+	iounmap(cru_base);
+}
+#endif /* CONFIG_NEON */
+
+static void __init bcm_cygnus_timer_init(void)
+{
+	/* Initialize all clocks declared in device tree */
+	of_clk_init(NULL);
+
+	clocksource_of_init();
+}
+
+static void __init bcm_cygnus_init(void)
+{
+	of_platform_populate(NULL, of_default_bus_match_table, NULL, NULL);
+
+	l2x0_of_init(0, ~0UL);
+
+	crmu_mail_box1_reg = ioremap_nocache(CRMU_MAIL_BOX1, SZ_4);
+	BUG_ON(!crmu_mail_box1_reg);
+
+#ifdef CONFIG_NEON
+	bcm_cygnus_powerup_neon();
+#endif
+}
+
+/*
+ * Reset the system
+ */
+void bcm_cygnus_restart(enum reboot_mode mode, const char *cmd)
+{
+	/* Send reset command to M0 via Mailbox. */
+	writel(CRMU_SOFT_RESET_CMD, crmu_mail_box1_reg);
+	iounmap(crmu_mail_box1_reg);
+
+	/* Wait for M0 to reset the chip. */
+	while (1)
+		cpu_do_idle();
+}
+
+static const char const *bcm_cygnus_dt_compat[] = {
+	"brcm,cygnus",
+	NULL,
+};
+
+DT_MACHINE_START(BCM_CYGNUS_DT, "Broadcom Cygnus SoC")
+	.init_machine = bcm_cygnus_init,
+	.map_io = debug_ll_io_init,
+	.init_time = bcm_cygnus_timer_init,
+	.dt_compat = bcm_cygnus_dt_compat,
+	.restart   = bcm_cygnus_restart
+MACHINE_END
-- 
1.7.9.5


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

* [PATCH 2/6] clk: Clock driver support for Broadcom Cygnus SoC
  2014-09-16 19:58 ` [PATCH 0/6] Add initial support for Broadcom Cygnus SoC Jonathan Richardson
  2014-09-16 19:58   ` [PATCH 1/6] ARM: cygnus: Initial " Jonathan Richardson
@ 2014-09-16 19:58   ` Jonathan Richardson
  2014-09-17  0:47     ` Mark Rutland
  2014-09-16 19:58   ` [PATCH 3/6] dt-bindings: Document Broadcom Cygnus SoC and clock driver Jonathan Richardson
                     ` (4 subsequent siblings)
  6 siblings, 1 reply; 92+ messages in thread
From: Jonathan Richardson @ 2014-09-16 19:58 UTC (permalink / raw)
  To: Christian Daudt, Matt Porter, Russell King, Mike Turquette,
	Rob Herring, Pawel Moll, Mark Rutland, Ian Campbell, Kumar Gala,
	JD Zheng
  Cc: linux-arm-kernel, bcm-kernel-feedback-list, linux-kernel,
	devicetree, Scott Branden, Ray Jui, Jonathan Richardson

The iProc clock driver controls PLL's common across iProc chips. The
cygnus driver controls cygnus specific features and variations.

Reviewed-by: Ray Jui <rjui@broadcom.com>
Tested-by: Jonathan Richardson <jonathar@broadcom.com>
Reviewed-by: JD (Jiandong) Zheng <jdzheng@broadcom.com>
Signed-off-by: Jonathan Richardson <jonathar@broadcom.com>
---
 drivers/clk/Makefile         |    1 +
 drivers/clk/bcm/Makefile     |    2 +
 drivers/clk/bcm/clk-cygnus.c | 1179 ++++++++++++++++++++++++++++++++++++++++++
 drivers/clk/bcm/clk-iproc.c  |  446 ++++++++++++++++
 4 files changed, 1628 insertions(+)
 create mode 100644 drivers/clk/bcm/clk-cygnus.c
 create mode 100644 drivers/clk/bcm/clk-iproc.c

diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile
index f537a0b..8ac0a31 100644
--- a/drivers/clk/Makefile
+++ b/drivers/clk/Makefile
@@ -37,6 +37,7 @@ obj-$(CONFIG_ARCH_VT8500)		+= clk-vt8500.o
 obj-$(CONFIG_COMMON_CLK_WM831X)		+= clk-wm831x.o
 obj-$(CONFIG_COMMON_CLK_XGENE)		+= clk-xgene.o
 obj-$(CONFIG_COMMON_CLK_AT91)		+= at91/
+obj-$(CONFIG_ARCH_BCM_IPROC)	+= bcm/
 obj-$(CONFIG_ARCH_BCM_MOBILE)		+= bcm/
 obj-$(CONFIG_ARCH_BERLIN)		+= berlin/
 obj-$(CONFIG_ARCH_HI3xxx)		+= hisilicon/
diff --git a/drivers/clk/bcm/Makefile b/drivers/clk/bcm/Makefile
index 6297d05..f803919 100644
--- a/drivers/clk/bcm/Makefile
+++ b/drivers/clk/bcm/Makefile
@@ -2,3 +2,5 @@ obj-$(CONFIG_CLK_BCM_KONA)	+= clk-kona.o
 obj-$(CONFIG_CLK_BCM_KONA)	+= clk-kona-setup.o
 obj-$(CONFIG_CLK_BCM_KONA)	+= clk-bcm281xx.o
 obj-$(CONFIG_CLK_BCM_KONA)	+= clk-bcm21664.o
+obj-$(CONFIG_ARCH_BCM_IPROC)	+= clk-iproc.o
+obj-$(CONFIG_ARCH_BCM_CYGNUS)	+= clk-cygnus.o
diff --git a/drivers/clk/bcm/clk-cygnus.c b/drivers/clk/bcm/clk-cygnus.c
new file mode 100644
index 0000000..bbeb152
--- /dev/null
+++ b/drivers/clk/bcm/clk-cygnus.c
@@ -0,0 +1,1179 @@
+/*
+ * Copyright 2014 Broadcom Corporation.  All rights reserved.
+ *
+ * Unless you and Broadcom execute a separate written software license
+ * agreement governing use of this software, this software is licensed to you
+ * under the terms of the GNU General Public License version 2, available at
+ * http://www.broadcom.com/licenses/GPLv2.php (the "GPL").
+ */
+#include <linux/kernel.h>
+#include <linux/err.h>
+#include <linux/clk-provider.h>
+#include <linux/io.h>
+#include <linux/of.h>
+#include <linux/clkdev.h>
+#include <linux/of_address.h>
+
+/*
+ * The CRU contains two similar PLLs: LCPLL and GENPLL,
+ * both with several output channels divided from the PLL
+ * output.
+ */
+
+#define CRU_LCPLL_CONTROL1_OFFSET  0x04
+#define CRU_LCPLL_STATUS_OFFSET    0x18
+
+#define LCPLL0_PDIV_SHIFT       26
+#define LCPLL0_PDIV_MASK        0xf
+#define LCPLL0_NDIV_SHIFT       16
+#define LCPLL0_NDIV_MASK        0x3ff
+#define LCPLL_ENABLEB_CH_SHIFT  7
+#define LCPLL_ENABLEB_CH_MASK   0x3f
+#define LCPLL_MDIV_MASK         0xff
+#define LCPLL_STATUS_LOCK_SHIFT 12
+
+#define LCPLL0_CONTROL0_OFFSET  0x00
+#define LCPLL0_CONTROL1_OFFSET  0x04
+#define LCPLL0_CONTROL2_OFFSET  0x08
+#define LCPLL0_CONTROL3_OFFSET  0x0c
+
+#define GENPLL_CONTROL0_OFFSET 0x00
+#define GENPLL_CONTROL1_OFFSET 0x04
+#define GENPLL_CONTROL2_OFFSET 0x08
+#define GENPLL_CONTROL3_OFFSET 0x0c
+#define GENPLL_CONTROL4_OFFSET 0x10
+#define GENPLL_CONTROL5_OFFSET 0x14
+#define GENPLL_CONTROL6_OFFSET 0x18
+#define GENPLL_CONTROL7_OFFSET 0x1c
+#define GENPLL_CONTROL8_OFFSET 0x20
+#define GENPLL_CONTROL9_OFFSET 0x24
+#define GENPLL_STATUS_OFFSET   0x28
+
+#define GENPLL_ENABLEB_CH_SHIFT    0x6
+#define GENPLL_ENABLEB_CH_MASK     0x3f
+
+#define GENPLL_STATUS_LOCK_SHIFT           12
+#define GENPLL_STATUS_LOCK_MASK            1
+#define GENPLL_CONTROL4_NDIV_INT_SHIFT     20
+#define GENPLL_CONTROL4_NDIV_INT_MASK      0x3FF
+#define GENPLL_CONTROL4_NDIV_FRAC_SHIFT    0
+#define GENPLL_CONTROL4_NDIV_FRAC_MASK     0xFFFFF
+#define GENPLL_CONTROL5_PDIV_SHIFT         0
+#define GENPLL_CONTROL5_PDIV_MASK          0xF
+#define GENPLL_MDIV_MASK                   0xff
+
+#define MIPI_DSI_GENPLL_ENABLEB_CH_SHIFT   12
+#define NDIV_FRAC_DIVISOR                  0x100000
+
+#define ASIU_MIPI_GENPLL_PWRON_SHIFT      20
+#define ASIU_MIPI_GENPLL_PWRON_PLL_SHIFT  19
+#define ASIU_MIPI_GENPLL_PWRON_BG_SHIFT   18
+#define ASIU_MIPI_GENPLL_PWRON_LDO_SHIFT  17
+#define ASIU_MIPI_GENPLL_ISO_IN_SHIFT     16
+#define ASIU_AUDIO_GENPLL_PWRON_PLL_SHIFT 11
+#define ASIU_AUDIO_GENPLL_PWRON_BG_SHIFT  10
+#define ASIU_AUDIO_GENPLL_PWRON_LDO_SHIFT 9
+#define ASIU_AUDIO_GENPLL_ISO_IN          8
+
+#define CLK_RATE_NO_DIV                   -1
+
+/*
+ * The clock framework may call recalc even if a clock is is unused, and
+ * therefore before being prepared/enabled. State checking is done for the
+ * MIPI PLL to prevent reading from a MIPI DSI register before the PLL is
+ * powered up because it will cause corruption (imprecise external aborts)
+ * sometimer later on.
+ */
+enum clock_state {
+	CLK_ENABLED,
+	CLK_PREPARED,
+	CLK_DISABLED
+};
+
+struct cygnus_clk {
+	struct clk_hw   hw;
+	void __iomem    *regs_base;
+	void __iomem    *pll_ctrl_reg;
+	void __iomem    *clock_gate_ctrl_reg;
+	int             chan;
+	int             internal_div;
+	unsigned long   rate;
+	enum clock_state state;
+};
+
+#define to_cygnus_clk(p) container_of(p, struct cygnus_clk, hw)
+
+/* Identifies LCPLL clock channels. */
+enum cygnus_lcpll_clk_chan {
+	LCPLL_CH0_PCIE_PHY_REF_CLK      = 0,
+	LCPLL_CH1_DDR_CLK               = 1,
+	LCPLL_CH2_SDIO_CLK              = 2,
+	LCPLL_CH3_USB_PHY_REF_CLK       = 3,
+	LCPLL_CH4_ASIU_SMART_CARD_CLK   = 4,
+	LCPLL_CH5                       = 5
+};
+
+/* Identifies GENPLL clock channels. */
+enum cygnus_genpll_clk_chan {
+	GENPLL_CH0_AXI21_CLK      = 0,
+	GENPLL_CH1_25MHZ_CLK      = 1,
+	GENPLL_CH2_SYS_CLK        = 2,
+	GENPLL_CH3_ETHERNET_CLK   = 3,
+	GENPLL_CH4_ASIU_AUDIO_CLK = 4,
+	GENPLL_CH5_ASIU_CAN_CLK   = 5
+};
+
+/*
+ * Channels for Oscillator dervived clocks are values used to determine
+ * which clock to enable/disable from the top clock gating control.
+ */
+enum cygnus_osc_derived_clk_chan {
+	OSC_DERIVED_CH0_KEYPAD_CLK = 0,
+	OSC_DERIVED_CH1_ADC_CLK    = 1,
+	OSC_DERIVED_CH2_PWM_CLK    = 2,
+};
+
+enum cygnus_mipi_pll_clk_chan {
+	MIPI_PLL_CH0_MIPI_PHY_CLK    = 0,
+	MIPI_PLL_CH1_LCD_CLK         = 1,
+	MIPI_PLL_CH2_3D_GRAPHICS_CLK = 2,
+};
+
+/* Order of registers defined in DT. */
+enum cygnus_clk_dt_regs {
+	CYGNUS_CLK_BASE_REG = 0,
+	CYGNUS_CLK_GATE_CTRL_REG,
+	CYGNUS_PLL_CTRL_REG
+};
+
+enum cygnus_top_clk_gating_ctrl_offsets {
+	GFX_CLK_GATE_EN = 0,
+	AUD_CLK_GATE_EN,
+	CAM_CLK_GATE_EN,
+	MIPI_DSI_CLK_GATE_EN,
+	LCD_CLK_GATE_EN,
+	D1W_CLK_GATE_EN,
+	CAN_CLK_GATE_EN,
+	KEYPAD_CLK_GATE_EN,
+	SMARTCARD_CLK_GATE_EN,
+	ADC_CLK_GATE_EN,
+	CRYPTO_CLK_GATE_EN
+};
+
+/*
+ * Enable clocks controlled through the top clock gating control.
+ *
+ * @param state true = enable clock, false = disable clock
+ */
+static void cygnus_clkgate_enable(void __iomem *clkgate_reg,
+	enum cygnus_top_clk_gating_ctrl_offsets offset, bool state)
+{
+	u32 val = readl(clkgate_reg);
+
+	/* Enable or disable the clock. */
+	if (state)
+		val |= 1 << offset;
+	else
+		val &= ~(1 << offset);
+
+	writel(val, clkgate_reg);
+}
+
+/*
+ * Powers on/off the MIPI GENPLL using CRMU_PLL_AON_CTRL register.
+ *
+ * @param state true to power on PLL, false to power off
+ */
+static void cygnus_mipi_genpll_poweron(void __iomem *pll_ctrl_reg,
+	bool state)
+{
+	u32 val;
+	u32 pll_ldo_on = ((1 << ASIU_MIPI_GENPLL_PWRON_SHIFT) |
+		(1 << ASIU_MIPI_GENPLL_PWRON_PLL_SHIFT) |
+		(1 << ASIU_MIPI_GENPLL_PWRON_BG_SHIFT)  |
+		(1 << ASIU_MIPI_GENPLL_PWRON_LDO_SHIFT));
+
+	val = readl(pll_ctrl_reg);
+
+	/*
+	 * Set PLL on/off. Set input isolation mode to 1 when disabled, 0 when
+	 * enabled.
+	 */
+	if (state) {
+		val |= pll_ldo_on;
+		val &= ~(1 << ASIU_MIPI_GENPLL_ISO_IN_SHIFT);
+	} else {
+		val &= ~pll_ldo_on;
+		val |= 1 << ASIU_MIPI_GENPLL_ISO_IN_SHIFT;
+	}
+
+	writel(val, pll_ctrl_reg);
+}
+
+/*
+ * Powers on/off the audio PLL using CRMU_PLL_AON_CTRL register.
+ *
+ * @param state true to power on PLL, false to power off
+ */
+static void cygnus_audio_genpll_poweron(void __iomem *pll_ctrl_reg,
+	bool state)
+{
+	u32 val;
+	u32 pll_ldo_on = ((1 << ASIU_AUDIO_GENPLL_PWRON_PLL_SHIFT) |
+		(1 << ASIU_AUDIO_GENPLL_PWRON_BG_SHIFT) |
+		(1 << ASIU_AUDIO_GENPLL_PWRON_LDO_SHIFT));
+
+	val = readl(pll_ctrl_reg);
+
+	/*
+	 * Set PLL on/off. Set input isolation mode to 1 when disabled, 0 when
+	 * enabled.
+	 */
+	if (state) {
+		val |= pll_ldo_on;
+		val &= ~(1 << ASIU_AUDIO_GENPLL_ISO_IN);
+	} else {
+		val &= ~pll_ldo_on;
+		val |= 1 << ASIU_AUDIO_GENPLL_ISO_IN;
+	}
+
+	writel(val, pll_ctrl_reg);
+}
+
+/*
+ * Get PLL running status and calculate output frequency
+ */
+static unsigned long cygnus_lcpll_status(struct cygnus_clk *clk,
+	unsigned long parent_rate)
+{
+	u32 reg;
+	unsigned pdiv, ndiv;
+
+	/* read status register */
+	reg = readl(clk->regs_base + CRU_LCPLL_STATUS_OFFSET);
+
+	/* Must be locked for proper PLL operation. */
+	if ((reg & (1 << LCPLL_STATUS_LOCK_SHIFT)) == 0) {
+		clk->rate = 0;
+		return -EIO;
+	}
+
+	/*
+	 * Calculate PLL frequency based on LCPLL divider values:
+	 *	 pdiv = LCPLL pre-divider ratio
+	 *   ndiv = LCPLL feedback divider
+	 *
+	 * The frequency is calculated by:
+	 *   ndiv * (parent clock rate / pdiv)
+	 */
+
+	reg = readl(clk->regs_base + CRU_LCPLL_CONTROL1_OFFSET);
+
+	/* feedback divider integer and fraction parts */
+	pdiv = (reg >> LCPLL0_PDIV_SHIFT) & LCPLL0_PDIV_MASK;
+	ndiv = (reg >> LCPLL0_NDIV_SHIFT) & LCPLL0_NDIV_MASK;
+
+	if (pdiv == 0)
+		return -EIO;
+
+	clk->rate = ndiv * (parent_rate / pdiv);
+
+	return clk->rate;
+}
+
+static unsigned long cygnus_lcpll_clk_recalc_rate(struct clk_hw *hwclk,
+	unsigned long parent_rate)
+{
+	struct cygnus_clk *bcm_clk = to_cygnus_clk(hwclk);
+
+	return cygnus_lcpll_status(bcm_clk, parent_rate);
+}
+
+static const struct clk_ops cygnus_lcpll_ops = {
+	.recalc_rate = cygnus_lcpll_clk_recalc_rate,
+};
+
+static int cygnus_lcpll_chan_status(struct cygnus_clk *clk,
+	unsigned long parent_rate)
+{
+	void * __iomem base;
+	u32 reg;
+	unsigned enable;
+	unsigned mdiv;
+	int offset = 0;
+	int shift = 0;
+
+	/* Register address is only stored in PLL structure */
+	base = clk->regs_base;
+	BUG_ON(base == NULL);
+
+	/* enable bit is in enableb_ch[] inversed */
+	enable = ((readl(base + LCPLL0_CONTROL0_OFFSET) >>
+		LCPLL_ENABLEB_CH_SHIFT) & LCPLL_ENABLEB_CH_MASK) ^
+		LCPLL_ENABLEB_CH_MASK;
+
+	if ((enable & (1 << clk->chan)) == 0) {
+		clk->rate = 0;
+		return -EIO;
+	}
+
+	/* MDIV for the 6 channels is spread over two registers. */
+	switch (clk->chan) {
+	case LCPLL_CH0_PCIE_PHY_REF_CLK:
+		offset = LCPLL0_CONTROL2_OFFSET; shift = 0;
+		break;
+
+	case LCPLL_CH1_DDR_CLK:
+		offset = LCPLL0_CONTROL2_OFFSET; shift = 10;
+		break;
+
+	case LCPLL_CH2_SDIO_CLK:
+		offset = LCPLL0_CONTROL2_OFFSET; shift = 20;
+		break;
+
+	case LCPLL_CH3_USB_PHY_REF_CLK:
+		offset = LCPLL0_CONTROL3_OFFSET; shift = 0;
+		break;
+
+	case LCPLL_CH4_ASIU_SMART_CARD_CLK:
+		offset = LCPLL0_CONTROL3_OFFSET; shift = 10;
+		break;
+
+	case LCPLL_CH5:
+		offset = LCPLL0_CONTROL3_OFFSET; shift = 20;
+		break;
+
+	default:
+		return -EINVAL;
+	}
+
+	/* Read MDIV for requested channel. */
+	reg = readl(base + offset);
+	mdiv = (reg >> shift) & LCPLL_MDIV_MASK;
+
+	/* when divisor is 0, it behaves as max+1 */
+	if (mdiv == 0)
+		mdiv = 256;
+
+	clk->rate = parent_rate / mdiv;
+
+	pr_debug("LCPLL[%d] mdiv=%u Prate=%lu rate=%lu\n",
+		clk->chan, mdiv, parent_rate, clk->rate);
+
+	return clk->rate;
+}
+
+static unsigned long cygnus_lcpll_chan_recalc_rate(struct clk_hw *hwclk,
+	unsigned long parent_rate)
+{
+	struct cygnus_clk *bcm_clk = to_cygnus_clk(hwclk);
+
+	return cygnus_lcpll_chan_status(bcm_clk, parent_rate);
+}
+
+static const struct clk_ops cygnus_lcpll_chan_ops = {
+	.recalc_rate = cygnus_lcpll_chan_recalc_rate,
+};
+
+/*
+ * Get PLL running status and calculate output frequency
+ */
+static unsigned long cygnus_genpll_status(struct cygnus_clk *clk,
+	unsigned long parent_rate)
+{
+	u32 reg;
+	unsigned pdiv;
+	unsigned ndiv_int;
+	unsigned ndiv_frac;
+
+	/* Read PLL status register. It must be locked. */
+	reg = readl(clk->regs_base + GENPLL_STATUS_OFFSET);
+	if ((reg & (1 << GENPLL_STATUS_LOCK_SHIFT)) == 0) {
+		clk->rate = 0;
+		return -EIO;
+	}
+
+	/* Calculate PLL frequency */
+
+	/* Get PLL feedback divider values. */
+	reg = readl(clk->regs_base + GENPLL_CONTROL4_OFFSET);
+
+	/* feedback divider integer and fraction parts */
+	ndiv_int = reg >> GENPLL_CONTROL4_NDIV_INT_SHIFT;
+	ndiv_frac = reg & GENPLL_CONTROL4_NDIV_INT_MASK;
+	ndiv_int += ndiv_frac / NDIV_FRAC_DIVISOR;
+
+	/* Get pdiv - first 4 bits. */
+	reg = readl(clk->regs_base + GENPLL_CONTROL5_OFFSET);
+	pdiv = reg & GENPLL_CONTROL5_PDIV_MASK;
+	if (pdiv == 0)
+		return -EIO;
+
+	clk->rate = (parent_rate / pdiv) * ndiv_int;
+
+	return clk->rate;
+}
+
+static unsigned long cygnus_genpll_recalc_rate(struct clk_hw *hwclk,
+	unsigned long parent_rate)
+{
+	struct cygnus_clk *bcm_clk = to_cygnus_clk(hwclk);
+
+	return cygnus_genpll_status(bcm_clk, parent_rate);
+}
+
+static const struct clk_ops cygnus_genpll_ops = {
+	.recalc_rate = cygnus_genpll_recalc_rate,
+};
+
+/*
+ * Calculates clock rate of the GENPLL channel requested. The clock rate is
+ * calculated as: the configured clock rate
+ *     Parent clock rate / mdiv
+ */
+static unsigned long cygnus_genpll_chan_get_rate(struct cygnus_clk *clk,
+	unsigned long parent_rate, int enableb_ch_shift)
+{
+	u32 reg;
+	unsigned enable;
+	unsigned mdiv;
+	unsigned offset = 0;
+	unsigned shift = 0;
+
+	/*
+	 * Read ENABLEB_CH to determine which channels are enabled. The enable
+	 * bits are inversed: 0 = channel enabled, 1 = channel disabled.
+	 */
+	reg = readl(clk->regs_base + GENPLL_CONTROL1_OFFSET);
+	enable = ((reg >> enableb_ch_shift) &
+		GENPLL_ENABLEB_CH_MASK) ^ GENPLL_ENABLEB_CH_MASK;
+
+	/* If channel is disabled the rate is 0. */
+	if ((enable & (1 << clk->chan)) == 0) {
+		clk->rate = 0;
+		return -EIO;
+	}
+
+	/* MDIV for the 6 channels is spread over two registers. */
+	switch (clk->chan) {
+	case 0:
+		offset = GENPLL_CONTROL8_OFFSET; shift = 0;
+		break;
+
+	case 1:
+		offset = GENPLL_CONTROL8_OFFSET; shift = 10;
+		break;
+
+	case 2:
+		offset = GENPLL_CONTROL8_OFFSET; shift = 20;
+		break;
+
+	case 3:
+		offset = GENPLL_CONTROL9_OFFSET; shift = 0;
+		break;
+
+	case 4:
+		offset = GENPLL_CONTROL9_OFFSET; shift = 10;
+		break;
+
+	case 5:
+		offset = GENPLL_CONTROL9_OFFSET; shift = 20;
+		break;
+
+	default:
+		return -EINVAL;
+	}
+
+	/* Read MDIV (post divider ratio) for requested channel. */
+	reg = readl(clk->regs_base + offset);
+	mdiv = (reg >> shift) & GENPLL_MDIV_MASK;
+
+	/* When divisor is 0, it behaves as max+1. */
+	if (mdiv == 0)
+		mdiv = 256;
+
+	clk->rate = parent_rate / mdiv;
+
+	pr_debug("GENPLL[%d] mdiv=%u parent rate=%lu rate=%lu\n",
+		clk->chan, mdiv, parent_rate, clk->rate);
+
+	return clk->rate;
+}
+
+/*
+ * Powers on the audio PLL for the audio channel from the PLL. No other
+ * GENPLL channels require powering on.
+ */
+static int cygnus_genpll_chan_prepare(struct clk_hw *hwclk)
+{
+	struct cygnus_clk *clk = to_cygnus_clk(hwclk);
+	struct clk *parent_clk = clk_get_parent(hwclk->clk);
+	struct cygnus_clk *cyg_parent_clk =
+		to_cygnus_clk(__clk_get_hw(parent_clk));
+
+	if (WARN_ON(!cyg_parent_clk->pll_ctrl_reg))
+		return -EIO;
+
+	if (clk->chan == GENPLL_CH4_ASIU_AUDIO_CLK) {
+		pr_debug("GENPLL[%d]: Powering on audio PLL/LDO\n", clk->chan);
+		cygnus_audio_genpll_poweron(cyg_parent_clk->pll_ctrl_reg, true);
+	}
+
+	return 0;
+}
+
+/*
+ * Powers off the audio PLL for the audio channel from the PLL. No other
+ * GENPLL channels require powering off.
+ */
+static void cygnus_genpll_chan_unprepare(struct clk_hw *hwclk)
+{
+	struct cygnus_clk *clk = to_cygnus_clk(hwclk);
+	struct clk *parent_clk = clk_get_parent(hwclk->clk);
+	struct cygnus_clk *cyg_parent_clk =
+		to_cygnus_clk(__clk_get_hw(parent_clk));
+
+	if (WARN_ON(!cyg_parent_clk->pll_ctrl_reg))
+		return;
+
+	if (clk->chan == GENPLL_CH4_ASIU_AUDIO_CLK) {
+		pr_debug("GENPLL[%d]: Powering down audio PLL and LDO\n",
+			clk->chan);
+		cygnus_audio_genpll_poweron(cyg_parent_clk->pll_ctrl_reg,
+			false);
+	}
+}
+
+static unsigned long cygnus_genpll_chan_recalc_rate(struct clk_hw *hwclk,
+	unsigned long parent_rate)
+{
+	struct cygnus_clk *bcm_clk = to_cygnus_clk(hwclk);
+
+	return cygnus_genpll_chan_get_rate(bcm_clk, parent_rate,
+		GENPLL_ENABLEB_CH_SHIFT);
+}
+
+/*
+ * Enables GENPLL channels. The only PLL channel that is controlled through
+ * the top clock gating control is the audio clock which requires enabling.
+ *
+ * Individual channels aren't enabled/disabled on the PLL because they are
+ * enabled by default and drivers don't always refer to them, meaning the
+ * clock framework would disable them. This can be added later when power
+ * saving is a concern.
+ */
+static int cygnus_genpll_chan_enable(struct clk_hw *hwclk)
+{
+	struct cygnus_clk *clk = to_cygnus_clk(hwclk);
+	struct clk *parent_clk = clk_get_parent(hwclk->clk);
+	struct cygnus_clk *cyg_parent_clk =
+		to_cygnus_clk(__clk_get_hw(parent_clk));
+	int parent_rate;
+
+	if (WARN_ON(!cyg_parent_clk->clock_gate_ctrl_reg))
+		return -EIO;
+
+	pr_debug("Enable GENPLL chan %d\n", clk->chan);
+
+	if (clk->chan == GENPLL_CH4_ASIU_AUDIO_CLK) {
+		cygnus_clkgate_enable(cyg_parent_clk->clock_gate_ctrl_reg,
+			AUD_CLK_GATE_EN, true);
+
+		/* Ensure parent's clock rate is calculated. */
+		parent_rate = clk_get_rate(parent_clk);
+		if (WARN_ON(!parent_rate))
+			return -EIO;
+	}
+
+	return 0;
+}
+
+static void cygnus_genpll_chan_disable(struct clk_hw *hwclk)
+{
+	struct cygnus_clk *clk = to_cygnus_clk(hwclk);
+	struct clk *parent_clk = clk_get_parent(hwclk->clk);
+	struct cygnus_clk *cyg_parent_clk =
+		to_cygnus_clk(__clk_get_hw(parent_clk));
+
+	if (WARN_ON(!cyg_parent_clk->clock_gate_ctrl_reg))
+		return;
+
+	pr_debug("GENPLL: disable chan %d\n", clk->chan);
+
+	/* Enable audio clock. */
+	if (clk->chan == GENPLL_CH4_ASIU_AUDIO_CLK)
+		cygnus_clkgate_enable(cyg_parent_clk->clock_gate_ctrl_reg,
+			AUD_CLK_GATE_EN, false);
+}
+
+static const struct clk_ops cygnus_genpll_chan_ops = {
+	.prepare = cygnus_genpll_chan_prepare,
+	.unprepare = cygnus_genpll_chan_unprepare,
+	.enable = cygnus_genpll_chan_enable,
+	.disable = cygnus_genpll_chan_disable,
+	.recalc_rate = cygnus_genpll_chan_recalc_rate,
+};
+
+static __init struct clk *cygnus_clock_init(struct device_node *node,
+	const struct clk_ops *ops)
+{
+	u32 channel = 0;
+	struct clk *clk;
+	struct cygnus_clk *cygnus_clk;
+	const char *clk_name = node->name;
+	const char *parent_name;
+	struct clk_init_data init;
+	int rc;
+
+	pr_debug("Clock name %s\n", node->name);
+
+	of_property_read_u32(node, "channel", &channel);
+	cygnus_clk = kzalloc(sizeof(*cygnus_clk), GFP_KERNEL);
+	if (WARN_ON(!cygnus_clk))
+		return NULL;
+
+	cygnus_clk->state = CLK_DISABLED;
+
+	/* Read base address from device tree and map to virtual address. */
+	cygnus_clk->regs_base = of_iomap(node, CYGNUS_CLK_BASE_REG);
+	if (WARN_ON(!cygnus_clk->regs_base))
+		goto err_alloc;
+
+	/* Read optional base addresses for PLL control and clock gating. */
+	cygnus_clk->clock_gate_ctrl_reg = of_iomap(node,
+		CYGNUS_CLK_GATE_CTRL_REG);
+	cygnus_clk->pll_ctrl_reg = of_iomap(node, CYGNUS_PLL_CTRL_REG);
+
+	of_property_read_u32(node, "channel", &channel);
+	cygnus_clk->chan = channel;
+	of_property_read_string(node, "clock-output-names", &clk_name);
+
+	/*
+	 * Internal divider is optional and used for PLL derived clocks with
+	 * hardcoded dividers.
+	 */
+	cygnus_clk->internal_div = CLK_RATE_NO_DIV;
+	of_property_read_u32(node, "div", &cygnus_clk->internal_div);
+
+	init.name = clk_name;
+	init.ops = ops;
+	init.flags = CLK_GET_RATE_NOCACHE;
+	parent_name = of_clk_get_parent_name(node, 0);
+	init.parent_names = &parent_name;
+	init.num_parents = 1;
+
+	cygnus_clk->hw.init = &init;
+
+	clk = clk_register(NULL, &cygnus_clk->hw);
+	if (WARN_ON(IS_ERR(clk)))
+		goto err_unmap;
+
+	rc = of_clk_add_provider(node, of_clk_src_simple_get, clk);
+	if (WARN_ON(IS_ERR_VALUE(rc)))
+		goto err_unregister;
+
+	rc = clk_register_clkdev(clk, clk_name, NULL);
+	if (WARN_ON(IS_ERR_VALUE(rc)))
+		goto err_provider;
+
+	return clk;
+
+err_provider:
+	of_clk_del_provider(node);
+
+err_unregister:
+	clk_unregister(clk);
+
+err_unmap:
+	iounmap(cygnus_clk->regs_base);
+	iounmap(cygnus_clk->clock_gate_ctrl_reg);
+	iounmap(cygnus_clk->pll_ctrl_reg);
+
+err_alloc:
+	kfree(cygnus_clk);
+
+	return NULL;
+}
+
+static void __init cygnus_lcpll_init(struct device_node *node)
+{
+	cygnus_clock_init(node, &cygnus_lcpll_ops);
+}
+CLK_OF_DECLARE(cygnus_lcpll, "brcm,cygnus-lcpll-clk", cygnus_lcpll_init);
+
+static void __init cygnus_genpll_init(struct device_node *node)
+{
+	cygnus_clock_init(node, &cygnus_genpll_ops);
+}
+CLK_OF_DECLARE(cygnus_genpll, "brcm,cygnus-genpll-clk", cygnus_genpll_init);
+
+static void __init cygnus_lcpll_ch_init(struct device_node *node)
+{
+	cygnus_clock_init(node, &cygnus_lcpll_chan_ops);
+}
+CLK_OF_DECLARE(cygnus_lcpll_ch, "brcm,cygnus-lcpll-ch", cygnus_lcpll_ch_init);
+
+static void __init cygnus_genpll_ch_init(struct device_node *node)
+{
+	cygnus_clock_init(node, &cygnus_genpll_chan_ops);
+}
+CLK_OF_DECLARE(cygnus_genpll_ch, "brcm,cygnus-genpll-ch",
+	cygnus_genpll_ch_init);
+
+/*
+ * Some clocks on Cygnus are derived from the oscillator directly without
+ * going through either the GENPLL or LCPLL. These clocks have specific
+ * registers for their dividers. The clocks included are: keypad, ADC, PWM.
+ */
+
+#define ASIU_CLK_DIV_ENABLE_SHIFT  31
+#define ASIU_CLK_DIV_ENABLE_MASK   0x1
+#define ASIU_CLK_DIV_HIGH_SHIFT    16
+#define ASIU_CLK_DIV_HIGH_MASK     0x3ff
+#define ASIU_CLK_DIV_LOW_SHIFT     0
+#define ASIU_CLK_DIV_LOW_MASK      0x3ff
+
+/*
+ * Calculate clock frequency for clocks derived from oscillator.
+ *
+ * @return The clock rate in Hz
+ */
+static int cygnus_osc_derived_clk_get_rate(struct cygnus_clk *clk,
+	unsigned long parent_rate)
+{
+	int reg_val;
+	int enabled;
+	int clk_div_high;
+	int clk_div_low;
+	unsigned long rate = 0;
+
+	reg_val = readl(clk->regs_base);
+
+	/* Ensure clock is enabled. */
+	enabled = (reg_val >> ASIU_CLK_DIV_ENABLE_SHIFT) &
+		ASIU_CLK_DIV_ENABLE_MASK;
+	if (!enabled)
+		return rate;
+
+	clk_div_high = (reg_val >> ASIU_CLK_DIV_HIGH_SHIFT) &
+		ASIU_CLK_DIV_HIGH_MASK;
+	clk_div_high += 1;
+
+	clk_div_low = (reg_val >> ASIU_CLK_DIV_LOW_SHIFT) &
+		ASIU_CLK_DIV_LOW_MASK;
+	clk_div_low += 1;
+
+	/*
+	 * Rate calculated as:
+	 *   (oscillator rate) / ((clk high + 1) + (clk_low + 1))
+	 */
+	rate = parent_rate / (clk_div_high + clk_div_low);
+
+	pr_debug("Osc derived clk: Prate=%lu div_high=%d div_low=%d rate=%lu\n",
+		parent_rate, clk_div_high, clk_div_low, rate);
+
+	return rate;
+}
+
+static unsigned long cygnus_osc_derived_clk_recalc_rate(struct clk_hw *hwclk,
+	unsigned long parent_rate)
+{
+	struct cygnus_clk *bcm_clk = to_cygnus_clk(hwclk);
+
+	return cygnus_osc_derived_clk_get_rate(bcm_clk, parent_rate);
+}
+
+/*
+ * Enables the top clock gating control for clocks that require it.
+ */
+static int cygnus_osc_derived_clk_enable(struct clk_hw *hwclk)
+{
+	struct cygnus_clk *clk = to_cygnus_clk(hwclk);
+	struct clk *parent_clk = clk_get_parent(hwclk->clk);
+	int parent_rate;
+	u32 val;
+
+	if (WARN_ON(!clk->clock_gate_ctrl_reg))
+		return 0;
+
+	pr_debug("OSC derived clk enable chan %d\n", clk->chan);
+
+	/* Enable top clock gating control if necessary. */
+	if (clk->chan == OSC_DERIVED_CH0_KEYPAD_CLK)
+		cygnus_clkgate_enable(clk->clock_gate_ctrl_reg,
+			KEYPAD_CLK_GATE_EN, true);
+	else if (clk->chan == OSC_DERIVED_CH1_ADC_CLK)
+		cygnus_clkgate_enable(clk->clock_gate_ctrl_reg,
+			ADC_CLK_GATE_EN, true);
+
+	/* Set and enable divider if specified. */
+	if (clk->internal_div != CLK_RATE_NO_DIV) {
+		val = (1 << ASIU_CLK_DIV_ENABLE_SHIFT) |
+			((clk->internal_div & ASIU_CLK_DIV_HIGH_MASK) <<
+			ASIU_CLK_DIV_HIGH_SHIFT) |
+			((clk->internal_div & ASIU_CLK_DIV_LOW_MASK) <<
+			ASIU_CLK_DIV_LOW_SHIFT);
+		writel(val, clk->regs_base);
+	}
+
+	/* Ensure parent's clock rate is calculated. */
+	parent_rate = clk_get_rate(parent_clk);
+	if (WARN_ON(!parent_rate))
+		return -EIO;
+
+	return 0;
+}
+
+/*
+ * Disables top clock gating control for clocks that were enabled.
+ */
+static void cygnus_osc_derived_clk_disable(struct clk_hw *hwclk)
+{
+	struct cygnus_clk *clk = to_cygnus_clk(hwclk);
+
+	if (WARN_ON(!clk->clock_gate_ctrl_reg))
+		return;
+
+	pr_debug("OSC derived clk disable chan %d\n", clk->chan);
+
+	/* Disable top clock gating control if necessary. */
+	if (clk->chan == OSC_DERIVED_CH0_KEYPAD_CLK)
+		cygnus_clkgate_enable(clk->clock_gate_ctrl_reg,
+			KEYPAD_CLK_GATE_EN, false);
+	else if (clk->chan == OSC_DERIVED_CH1_ADC_CLK)
+		cygnus_clkgate_enable(clk->clock_gate_ctrl_reg,
+			ADC_CLK_GATE_EN, false);
+}
+
+static const struct clk_ops cygnus_osc_derived_clk_ops = {
+	.enable = cygnus_osc_derived_clk_enable,
+	.disable = cygnus_osc_derived_clk_disable,
+	.recalc_rate = cygnus_osc_derived_clk_recalc_rate,
+};
+
+static void __init cygnus_osc_derived_init(struct device_node *node)
+{
+	cygnus_clock_init(node, &cygnus_osc_derived_clk_ops);
+}
+
+CLK_OF_DECLARE(cygnus_osc_derived, "brcm,cygnus-osc-derived",
+	cygnus_osc_derived_init);
+
+/*
+ * Some clocks are derived from a PLL. The dividers are internal and can't
+ * be read from a register. If the parent clock rate changes then the derived
+ * clock rates scale accordingly.
+ */
+
+ /*
+  * Calculate clock frequency for clocks derived from oscillator.
+  * Rate calculated as:  parent rate / internal divider
+  * The internal divider must be specified in DT.
+  *
+  * @return The clock rate in Hz.
+  */
+static unsigned long cygnus_pll_derived_clk_get_rate(struct cygnus_clk *clk,
+	unsigned long parent_rate)
+{
+	unsigned long rate = parent_rate / clk->internal_div;
+
+	pr_debug("PLL derived clk: Prate=%lu rate=%lu\n", parent_rate, rate);
+
+	return rate;
+}
+
+static unsigned long cygnus_pll_derived_clk_recalc_rate(struct clk_hw *hwclk,
+	unsigned long parent_rate)
+{
+	struct cygnus_clk *bcm_clk = to_cygnus_clk(hwclk);
+
+	return cygnus_pll_derived_clk_get_rate(bcm_clk, parent_rate);
+}
+
+static const struct clk_ops cygnus_pll_derived_clk_ops = {
+	.recalc_rate = cygnus_pll_derived_clk_recalc_rate,
+};
+
+static void __init cygnus_pll_derived_init(struct device_node *node)
+{
+	cygnus_clock_init(node, &cygnus_pll_derived_clk_ops);
+}
+
+CLK_OF_DECLARE(cygnus_pll_derived, "brcm,cygnus-pll-derived",
+	cygnus_pll_derived_init);
+
+/*
+ * MIPI DSI GENPLL
+ */
+
+/*
+ * Get PLL running status and calculate output frequency.
+ */
+static unsigned long cygnus_mipipll_get_rate(struct cygnus_clk *clk,
+	unsigned long parent_rate)
+{
+	u32 reg;
+	u32 rate;
+	u32 pdiv;
+	u32 ndiv_int;
+	u32 ndiv_frac;
+	int pll_locked;
+
+	/* Read lock field from PLL status register. It must be unlocked. */
+	reg = readl(clk->regs_base + GENPLL_STATUS_OFFSET);
+
+	pll_locked = (reg >> GENPLL_STATUS_LOCK_SHIFT) &
+		GENPLL_STATUS_LOCK_MASK;
+	if (pll_locked) {
+		clk->rate = 0;
+		return -EIO;
+	}
+	/*
+	 * Calculate PLL frequency:
+	 *   PLL freq = ((crystal clock / pdiv) * ndiv ) / mdiv
+	 */
+
+	/* Get PLL feedback divider values. */
+	reg = readl(clk->regs_base + GENPLL_CONTROL4_OFFSET);
+
+	/* Feedback divider integer and fractional parts. */
+	ndiv_int = (reg >> GENPLL_CONTROL4_NDIV_INT_SHIFT) &
+		GENPLL_CONTROL4_NDIV_INT_MASK;
+	ndiv_frac = (reg >> GENPLL_CONTROL4_NDIV_FRAC_SHIFT) &
+		GENPLL_CONTROL4_NDIV_FRAC_MASK;
+	ndiv_int += ndiv_frac / NDIV_FRAC_DIVISOR;
+
+	/* Get pdiv. */
+	reg = readl(clk->regs_base + GENPLL_CONTROL5_OFFSET);
+	pdiv = (reg >> GENPLL_CONTROL5_PDIV_SHIFT) &
+		GENPLL_CONTROL5_PDIV_MASK;
+
+	/* If pdiv is 0, divide by 0.5 - doubler. */
+	if (pdiv == 0)
+		rate = parent_rate * 2;
+	else
+		rate = parent_rate / pdiv;
+
+	clk->rate = rate * ndiv_int;
+
+	pr_debug("[MIPI PLL] parent rate=%lu, ndiv int=%d, pdiv=%d, rate=%lu\n",
+	    parent_rate, ndiv_int, pdiv, clk->rate);
+
+	return clk->rate;
+}
+
+/*
+ * Powers on the necessary PLL's and LDO for MIPI GEN PLL.
+ */
+static int cygnus_mipipll_prepare(struct clk_hw *hwclk)
+{
+	struct cygnus_clk *clk = to_cygnus_clk(hwclk);
+
+	if (WARN_ON(!clk->pll_ctrl_reg))
+		return -EIO;
+
+	pr_debug("Powering up MIPI PLL and LDO\n");
+
+	/* Power on the PLL. */
+	cygnus_mipi_genpll_poweron(clk->pll_ctrl_reg, true);
+
+	clk->state = CLK_PREPARED;
+
+	return 0;
+}
+
+/*
+ * Powers off the PLL's and LDO for MIPI GEN PLL.
+ */
+static void cygnus_mipipll_unprepare(struct clk_hw *hwclk)
+{
+	struct cygnus_clk *clk = to_cygnus_clk(hwclk);
+
+	if (WARN_ON(!clk->pll_ctrl_reg))
+		return;
+
+	pr_debug("Powering down MIPI PLL and LDO\n");
+
+	/* Power off the PLL. */
+	cygnus_mipi_genpll_poweron(clk->pll_ctrl_reg, false);
+
+	clk->state = CLK_DISABLED;
+}
+
+static unsigned long cygnus_mipipll_recalc_rate(struct clk_hw *hwclk,
+	unsigned long parent_rate)
+{
+	struct cygnus_clk *bcm_clk = to_cygnus_clk(hwclk);
+
+	if (bcm_clk->state != CLK_ENABLED)
+		return 0;
+
+	return cygnus_mipipll_get_rate(bcm_clk, parent_rate);
+}
+
+/*
+ * Enables the MIPI DSI clock gate through the top clock gating control.
+ */
+static int cygnus_mipipll_enable(struct clk_hw *hwclk)
+{
+	struct cygnus_clk *clk = to_cygnus_clk(hwclk);
+
+	if (WARN_ON(!clk->clock_gate_ctrl_reg))
+		return -EIO;
+
+	pr_debug("Enable MIPI PLL\n");
+
+	/* Enable MIPI DSI clock. */
+	cygnus_clkgate_enable(clk->clock_gate_ctrl_reg,
+		MIPI_DSI_CLK_GATE_EN, true);
+
+	clk->state = CLK_ENABLED;
+
+	return 0;
+}
+
+/*
+ * Turns off the MIPI PLL clock.
+ */
+static void cygnus_mipipll_disable(struct clk_hw *hwclk)
+{
+	struct cygnus_clk *clk = to_cygnus_clk(hwclk);
+
+	if (WARN_ON(!clk->clock_gate_ctrl_reg))
+		return;
+
+	pr_debug("Disabling MIPI PLL and LDO\n");
+
+	/* Disable MIPI DSI clock through top clock gating control. */
+	cygnus_clkgate_enable(clk->clock_gate_ctrl_reg,
+		MIPI_DSI_CLK_GATE_EN, false);
+
+	clk->state = CLK_DISABLED;
+}
+
+static const struct clk_ops cygnus_mipipll_ops = {
+	.prepare = cygnus_mipipll_prepare,
+	.unprepare = cygnus_mipipll_unprepare,
+	.enable = cygnus_mipipll_enable,
+	.disable = cygnus_mipipll_disable,
+	.recalc_rate = cygnus_mipipll_recalc_rate,
+};
+
+static void __init cygnus_mipipll_init(struct device_node *node)
+{
+	cygnus_clock_init(node, &cygnus_mipipll_ops);
+}
+CLK_OF_DECLARE(cygnus_mipipll, "brcm,cygnus-mipipll-clk", cygnus_mipipll_init);
+
+/*
+ * MIPI PLL clock channel management.
+ */
+
+/*
+ * Enables a MIPI PLL channel.
+ */
+static void mipi_pll_enable_chan(void __iomem *base, int chan, bool state)
+{
+	u32 val;
+
+	val = readl(base + GENPLL_CONTROL1_OFFSET);
+
+	/* ENABLEB_CH bit set to 0 to enable channel, 1 to disable. */
+	if (state)
+		val &= ~(1 << (chan + MIPI_DSI_GENPLL_ENABLEB_CH_SHIFT));
+	else
+		val |= (1 << (chan + MIPI_DSI_GENPLL_ENABLEB_CH_SHIFT));
+
+	writel(val, base + GENPLL_CONTROL1_OFFSET);
+}
+
+static unsigned long cygnus_mipipll_chan_recalc_rate(struct clk_hw *hwclk,
+	unsigned long parent_rate)
+{
+	struct cygnus_clk *clk = to_cygnus_clk(hwclk);
+
+	if (WARN_ON(!clk->clock_gate_ctrl_reg))
+		return 0;
+
+	if (clk->state != CLK_ENABLED)
+		return 0;
+
+	return cygnus_genpll_chan_get_rate(clk, parent_rate,
+		MIPI_DSI_GENPLL_ENABLEB_CH_SHIFT);
+}
+
+/*
+ * Enables the PLL channel and the top clock gating control for clocks that
+ * are controlled through it.
+ */
+static int cygnus_mipipll_chan_enable(struct clk_hw *hwclk)
+{
+	struct cygnus_clk *clk = to_cygnus_clk(hwclk);
+	struct clk *parent_clk = clk_get_parent(hwclk->clk);
+	int parent_rate;
+
+	if (WARN_ON(!clk->clock_gate_ctrl_reg))
+		return -EIO;
+
+	pr_debug("Enable MIPI PLL chan %d\n", clk->chan);
+
+	/*
+	 * Some MIPI PLL channels have to be enabled through the top clock
+	 * gating ctrl. Add support for other channels here.
+	 */
+	if (clk->chan == MIPI_PLL_CH1_LCD_CLK) {
+		cygnus_clkgate_enable(clk->clock_gate_ctrl_reg,
+			LCD_CLK_GATE_EN, true);
+	}
+
+	/* Enable the PLL channel. */
+	mipi_pll_enable_chan(clk->regs_base, clk->chan, true);
+
+	clk->state = CLK_ENABLED;
+
+	/* Ensure parent's clock rate is calculated. */
+	parent_rate = clk_get_rate(parent_clk);
+	if (WARN_ON(!parent_rate))
+		return -EIO;
+
+	return 0;
+}
+
+/*
+ * Disables the PLL channel. Some channels also have to be shut down through
+ * the top clock gating control.
+ */
+static void cygnus_mipipll_chan_disable(struct clk_hw *hwclk)
+{
+	struct cygnus_clk *clk = to_cygnus_clk(hwclk);
+
+	if (WARN_ON(!clk->clock_gate_ctrl_reg))
+		return;
+
+	pr_debug("Disable MIPI PLL chan %d\n", clk->chan);
+
+	/* Disable LCD clock through top clock gating control. */
+	if (clk->chan == MIPI_PLL_CH1_LCD_CLK) {
+		cygnus_clkgate_enable(clk->clock_gate_ctrl_reg,
+			LCD_CLK_GATE_EN, false);
+	}
+
+	/* Disable the PLL channel. */
+	mipi_pll_enable_chan(clk->regs_base, clk->chan, false);
+
+	clk->state = CLK_DISABLED;
+}
+
+static const struct clk_ops cygnus_mipipll_chan_ops = {
+	.enable = cygnus_mipipll_chan_enable,
+	.disable = cygnus_mipipll_chan_disable,
+	.recalc_rate = cygnus_mipipll_chan_recalc_rate,
+};
+
+static void __init cygnus_mipipll_ch_init(struct device_node *node)
+{
+	cygnus_clock_init(node, &cygnus_mipipll_chan_ops);
+}
+
+CLK_OF_DECLARE(cygnus_mipipll_ch, "brcm,cygnus-mipipll-ch",
+	cygnus_mipipll_ch_init);
diff --git a/drivers/clk/bcm/clk-iproc.c b/drivers/clk/bcm/clk-iproc.c
new file mode 100644
index 0000000..6029fd7
--- /dev/null
+++ b/drivers/clk/bcm/clk-iproc.c
@@ -0,0 +1,446 @@
+/*
+ * Copyright 2014 Broadcom Corporation.  All rights reserved.
+ *
+ * Unless you and Broadcom execute a separate written software license
+ * agreement governing use of this software, this software is licensed to you
+ * under the terms of the GNU General Public License version 2, available at
+ * http://www.broadcom.com/licenses/GPLv2.php (the "GPL").
+ */
+
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/err.h>
+#include <linux/clk-provider.h>
+#include <linux/io.h>
+#include <linux/of.h>
+#include <linux/clkdev.h>
+#include <linux/of_address.h>
+
+#define IPROC_CLK_POLICY_FREQ_OFFSET    0x008
+#define IPROC_CLK_POLICY0_MSK_OFFSET    0x010
+#define IPROC_CLK_APB_SW_DIV_OFFSET     0xA10
+#define IPROC_CLK_PLL_ARMA_OFFSET       0xC00
+#define IPROC_CLK_PLL_ARMB_OFFSET       0xC04
+#define IPROC_CLK_PLL_ARMC_OFFSET       0xC08
+#define IPROC_CLK_PLL_ARMCTL5_OFFSET    0xC20
+#define IPROC_CLK_PLL_ARM_OFFSET_OFFSET 0xC24
+#define IPROC_CLK_ARM_DIV_OFFSET        0xE00
+#define IPROC_CLK_POLICY_DBG_OFFSET     0xEC0
+
+#define IPROC_CLK_ARM_DIV_ARM_PLL_SELECT_OVERRIDE_SHIFT        4
+#define IPROC_CLK_ARM_DIV_ARM_PLL_SELECT_MASK                  0xf
+#define IPROC_CLK_POLICY_FREQ_OFFSET_POLICY_FREQ_MASK          0xf
+#define IPROC_CLK_POLICY_FREQ_OFFSET_POLICY_FREQ_SHIFT         8
+#define IPROC_CLK_POLICY_DBG_OFFSET_ACT_FREQ_SHIFT             12
+#define IPROC_CLK_POLICY_DBG_OFFSET_ACT_FREQ_MASK              7
+#define IPROC_CLK_PLL_ARM_OFFSET_PLLARM_OFFSET_SW_CTL_SHIFT    29
+#define CLK_PLL_ARM_OFFSET_PLLARM_NDIV_INT_OFFSET              20
+#define CLK_PLL_ARM_OFFSET_PLLARM_NDIV_INT_MASK                0xff
+#define CLK_PLL_ARM_OFFSET_PLLARM_NDIV_FRAC_OFFSET             0xfffff
+#define CLK_PLL_ARMA_PLLARM_NDIV_INT_SHIFT                     8
+#define CLK_PLL_ARMA_PLLARM_NDIV_INT_MASK                      0x3ff
+#define CLK_PLL_ARMB_PLLARM_NDIV_FRAC_MASK                     0xfffff
+#define CLK_PLL_ARMC_PLLARM_MDIV_MASK                          0xff
+#define CLK_PLL_ARMCTL5_PLLARM_H_MDIV_MASK                     0xff
+#define CLK_PLL_ARMC_PLLARM_BYPCLK_EN_SHIFT                    8
+#define CLK_PLL_ARMA_PLLARM_PDIV_SHIFT                         24
+#define CLK_PLL_ARMA_PLLARM_PDIV_MASK                          0xf
+#define CLK_PLL_ARMA_PLLARM_LOCK_SHIFT                         28
+#define CLK_ARM_DIV_APB0_FREE_DIV_SHIFT                        8
+#define CLK_ARM_DIV_APB0_FREE_DIV_MASK                         0x7
+#define CLK_ARM_DIV_ARM_SWITCH_DIV_SHIFT                       8
+#define CLK_ARM_DIV_ARM_SWITCH_DIV_MASK                        0x3
+#define CLK_APB_SW_DIV_APB_CLK_DIV_MASK                        0x3
+
+struct brcm_clk {
+	struct clk_hw   hw;
+	void __iomem    *regs_base;
+	int             chan;
+	unsigned long   rate;
+};
+
+/* Identifies derived clocks from ARM PLL. */
+enum {
+	ARMPLL_APB0_FREE_CLK   = 0,
+	ARMPLL_ARM_SWITCH_CLK  = 1,
+	ARMPLL_ARM_APB_CLK     = 2,
+	ARMPLL_ARM_PERIPH_CLK  = 3
+};
+
+/* Frequency id's from policy0_freq field of POLICY_FREQ register. */
+enum a9pll_policy_freq {
+	PLL_CRYSTAL_CLK   = 0,
+	PLL_SYS_CLK       = 2,
+	PLL_CH0_SLOW_CLK  = 6,
+	PLL_CH1_FAST_CLK  = 7
+};
+
+#define to_brcm_clk(p) container_of(p, struct brcm_clk, hw)
+
+static int iproc_cru_arm_freq_id(void __iomem *regs_base)
+{
+	u32 reg_f, reg;
+	unsigned policy = 0;
+	unsigned fid;
+	unsigned active_freq;
+
+	/* Read policy frequency. */
+	reg_f = readl(regs_base + IPROC_CLK_POLICY_FREQ_OFFSET);
+
+	/* Check for PLL policy software override. */
+	reg = readl(regs_base + IPROC_CLK_ARM_DIV_OFFSET);
+	if (reg & (1 << IPROC_CLK_ARM_DIV_ARM_PLL_SELECT_OVERRIDE_SHIFT))
+		policy = reg & IPROC_CLK_ARM_DIV_ARM_PLL_SELECT_MASK;
+
+	/* Get frequency ID based on policy. */
+	fid = (reg_f >>
+		(IPROC_CLK_POLICY_FREQ_OFFSET_POLICY_FREQ_SHIFT * policy)) &
+		IPROC_CLK_POLICY_FREQ_OFFSET_POLICY_FREQ_MASK;
+
+	/* Verify freq id from debug register. */
+	reg = readl(regs_base + IPROC_CLK_POLICY_DBG_OFFSET);
+	/* Read current active frequency id. */
+	active_freq = IPROC_CLK_POLICY_DBG_OFFSET_ACT_FREQ_MASK &
+		(reg >> IPROC_CLK_POLICY_DBG_OFFSET_ACT_FREQ_SHIFT);
+
+	if (fid != active_freq) {
+		pr_debug("IPROC CRU clock frequency id override %d->%d\n",
+			fid, active_freq);
+
+		fid = active_freq;
+	}
+
+	pr_debug("Active frequency ID %d\n", fid);
+
+	return fid;
+}
+
+/*
+ * Get ndiv integer and combine with fractional part to create 64 bit
+ * value.
+ */
+static u64 a9pll_get_ndiv(struct brcm_clk *clk)
+{
+	u32 arm_offset_reg;
+	u32 pllarma_reg;
+	u32 pllarmb_reg;
+	u32 ndiv_int;
+	u32 ndiv_frac;
+	u64 ndiv;
+
+	arm_offset_reg = readl(clk->regs_base +
+		IPROC_CLK_PLL_ARM_OFFSET_OFFSET);
+
+    /*
+	 * Check if offset mode is active to determine which register to
+	 * get ndiv from.
+	 */
+	if (arm_offset_reg &
+		(1 << IPROC_CLK_PLL_ARM_OFFSET_PLLARM_OFFSET_SW_CTL_SHIFT)) {
+		/* Offset mode active. Get integer divide from offset reg. */
+		ndiv_int = (arm_offset_reg >>
+			CLK_PLL_ARM_OFFSET_PLLARM_NDIV_INT_OFFSET) &
+			CLK_PLL_ARM_OFFSET_PLLARM_NDIV_INT_MASK;
+
+		if (ndiv_int == 0)
+			ndiv_int = 256;
+
+		/* Get ndiv fractional divider. */
+		ndiv_frac = arm_offset_reg &
+			CLK_PLL_ARM_OFFSET_PLLARM_NDIV_FRAC_OFFSET;
+	} else {
+		/* Offset mode not active so read PLL ndiv from PLLARMA. */
+		pllarma_reg = readl(clk->regs_base + IPROC_CLK_PLL_ARMA_OFFSET);
+		ndiv_int = (pllarma_reg >> CLK_PLL_ARMA_PLLARM_NDIV_INT_SHIFT) &
+			CLK_PLL_ARMA_PLLARM_NDIV_INT_MASK;
+
+		if (ndiv_int == 0)
+			ndiv_int = 1024;
+
+		/* Get ndiv fractional divider. */
+		pllarmb_reg = readl(clk->regs_base + IPROC_CLK_PLL_ARMB_OFFSET);
+		ndiv_frac = pllarmb_reg & CLK_PLL_ARMB_PLLARM_NDIV_FRAC_MASK;
+	}
+
+	ndiv = ((u64) ndiv_int << 20) | ndiv_frac;
+
+	return ndiv;
+}
+
+/*
+ * Determine mdiv (post divider) based on the frequency id being used.
+ * There are 4 clocks that can be used to derive the output clock rate:
+ *    - 25 MHz crystal
+ *    - sys_clk
+ *    - channel 0 (slow clock)
+ *    - channel 1 (fast clock)
+ *
+ * If the slow clock is being used then mdiv is read from PLLARMC. If
+ * the fast clock is being used then the channel 1 mdiv is used.
+ * Otherwise there is no post divider.
+ *
+ * @return The mdiv value. -EIO if an error occurred.
+ */
+static int a9pll_get_mdiv(struct brcm_clk *clk)
+{
+	u32 mdiv;
+	u32 pllarmc_reg;
+	u32 armctl5_reg;
+	u32 freq_id;
+
+	/* Get the policy frequency. */
+	freq_id = iproc_cru_arm_freq_id(clk->regs_base);
+
+	switch (freq_id) {
+	/* There is no divider for these frequency id's. */
+	case PLL_CRYSTAL_CLK:
+	case PLL_SYS_CLK:
+		mdiv = 1;
+		break;
+
+	case PLL_CH0_SLOW_CLK: {
+	    /* Read mdiv (post-divider) from PLLARMC bits 0:7 */
+	    pllarmc_reg = readl(clk->regs_base + IPROC_CLK_PLL_ARMC_OFFSET);
+	    mdiv = pllarmc_reg & CLK_PLL_ARMC_PLLARM_MDIV_MASK;
+	    if (mdiv == 0)
+			mdiv = 256;
+		break;
+	}
+
+	case PLL_CH1_FAST_CLK: {
+		/* Post divider for channel 1 is in CTL5 (pllarm_h_mdiv). */
+		armctl5_reg = readl(clk->regs_base +
+			IPROC_CLK_PLL_ARMCTL5_OFFSET);
+	    mdiv = armctl5_reg & CLK_PLL_ARMCTL5_PLLARM_H_MDIV_MASK;
+	    if (mdiv == 0)
+			mdiv = 256;
+		break;
+	}
+
+	default:
+		return -EIO;
+	}
+
+	return mdiv;
+}
+
+/*
+ * Calculate the output frequency of the ARM PLL. The main output clock
+ * is 'arm_clk'.
+ *
+ * The frequency is calculated based on the ARM PLL divider values:
+ *	 pdiv = ARM PLL input pre-divider
+ *   ndiv = ARM PLL feedback divider
+ *   mdiv = ARM PLL post divider
+ *
+ * The frequency is calculated by:
+ *   ((ndiv * parent clock rate) / pdiv) / mdiv
+ */
+static int a9pll_status(struct brcm_clk *clk, unsigned long parent_rate)
+{
+	u32 pllarma_reg;
+	u32 pllarmc_reg;
+	u32 pdiv;
+	u32 mdiv;
+	u64 ndiv;
+	u32 arm_clk_freq;
+
+	pr_debug("a9pll_status: clk 0x%x\n", (unsigned int)clk);
+
+	BUG_ON(!clk->regs_base);
+
+	pllarma_reg = readl(clk->regs_base + IPROC_CLK_PLL_ARMA_OFFSET);
+	pllarmc_reg = readl(clk->regs_base + IPROC_CLK_PLL_ARMC_OFFSET);
+
+	/* Check if PLL is in bypass mode - input frequency to output */
+	if (pllarmc_reg & (1 << CLK_PLL_ARMC_PLLARM_BYPCLK_EN_SHIFT)) {
+		clk->rate = parent_rate;
+		return 0;
+	}
+
+	/* Check if PLL is locked. It must be unlocked. */
+	if ((pllarma_reg &
+		(1 << CLK_PLL_ARMA_PLLARM_LOCK_SHIFT)) == 0) {
+		clk->rate = 0;
+		return -EIO;
+	}
+
+	/* Read pdiv from PLLARMA. */
+	pdiv = (pllarma_reg >> CLK_PLL_ARMA_PLLARM_PDIV_SHIFT) &
+		CLK_PLL_ARMA_PLLARM_PDIV_MASK;
+	if (pdiv == 0)
+		pdiv = 16;
+
+	/* Determine ndiv. */
+	ndiv = a9pll_get_ndiv(clk);
+
+	/* Determine mdiv (post divider). */
+	mdiv = a9pll_get_mdiv(clk);
+	if (mdiv == -EIO) {
+		clk->rate = 0;
+		return -EIO;
+	}
+
+	/* Calculate clock frequency. */
+	arm_clk_freq = (ndiv * parent_rate) >> 20;
+	arm_clk_freq = (arm_clk_freq / pdiv) / mdiv;
+
+	clk->rate = arm_clk_freq;
+
+	pr_debug("ARM PLL (arm_clk) rate %lu. parent rate = %lu, ",
+		clk->rate, parent_rate);
+	pr_debug("ndiv_int = %d, pdiv = %d, mdiv = %d\n",
+		 (u32)ndiv >> 20, pdiv, mdiv);
+
+	return clk->rate;
+}
+
+static unsigned long clk_a9pll_recalc_rate(struct clk_hw *hwclk,
+	unsigned long parent_rate)
+{
+	struct brcm_clk *bcm_clk = to_brcm_clk(hwclk);
+
+	return a9pll_status(bcm_clk, parent_rate);
+}
+
+static const struct clk_ops a9pll_ops = {
+	.recalc_rate = clk_a9pll_recalc_rate,
+};
+
+/*
+ * Get status of any of the ARMPLL output channels
+ */
+static int a9pll_chan_status(struct brcm_clk *clk, unsigned long parent_rate)
+{
+	u32 reg;
+	unsigned div;
+
+	BUG_ON(!clk->regs_base);
+
+	reg = readl(clk->regs_base + IPROC_CLK_ARM_DIV_OFFSET);
+	pr_debug("Clock Div = %#x\n", reg);
+
+	switch (clk->chan) {
+	case ARMPLL_APB0_FREE_CLK:
+		/* apb0_free_div bits 10:8 */
+		div = (reg >> CLK_ARM_DIV_APB0_FREE_DIV_SHIFT) &
+			CLK_ARM_DIV_APB0_FREE_DIV_MASK;
+		div++;
+		break;
+
+	case ARMPLL_ARM_SWITCH_CLK:
+		/* arm_switch_div bits 6:5 */
+		div = (reg >> CLK_ARM_DIV_ARM_SWITCH_DIV_SHIFT) &
+			CLK_ARM_DIV_ARM_SWITCH_DIV_MASK;
+		div++;
+		break;
+
+	case ARMPLL_ARM_APB_CLK:
+		/* IPROC_CLK_APB_SW_DIV_REG apb_clk_div bits 1:0 */
+		reg = readl(clk->regs_base + IPROC_CLK_APB_SW_DIV_OFFSET);
+		div = reg & CLK_APB_SW_DIV_APB_CLK_DIV_MASK;
+		div++;
+		break;
+
+	case ARMPLL_ARM_PERIPH_CLK:      /* periph_clk */
+		div = 2;
+		break;
+
+	default:
+		return -EINVAL;
+	}
+
+	clk->rate = parent_rate / div;
+	pr_debug("Clock rate A9PLL chan 0x%x: %lu, div: %d\n",
+		clk->chan, clk->rate, div);
+
+	return clk->rate;
+}
+
+static unsigned long clk_a9pll_chan_recalc_rate(struct clk_hw *hwclk,
+	unsigned long parent_rate)
+{
+	struct brcm_clk *bcm_clk = to_brcm_clk(hwclk);
+
+	return a9pll_chan_status(bcm_clk, parent_rate);
+}
+
+static const struct clk_ops a9pll_chan_ops = {
+	.recalc_rate = clk_a9pll_chan_recalc_rate,
+};
+
+static __init struct clk *iproc_clock_init(struct device_node *node,
+	const struct clk_ops *ops)
+{
+	u32 channel = 0;
+	struct clk *clk;
+	struct brcm_clk *brcm_clk;
+	const char *clk_name = node->name;
+	const char *parent_name;
+	struct clk_init_data init;
+	int rc;
+
+	pr_debug("Clock name %s\n", node->name);
+
+	rc = of_property_read_u32(node, "channel", &channel);
+	brcm_clk = kzalloc(sizeof(*brcm_clk), GFP_KERNEL);
+	if (WARN_ON(!brcm_clk))
+		return NULL;
+
+	/* Read base address from device tree and map to virtual address. */
+	brcm_clk->regs_base = of_iomap(node, 0);
+	if (WARN_ON(!brcm_clk->regs_base))
+		goto err_alloc;
+
+	brcm_clk->chan = channel;
+	of_property_read_string(node, "clock-output-names", &clk_name);
+
+	init.name = clk_name;
+	init.ops = ops;
+	init.flags = 0;
+	parent_name = of_clk_get_parent_name(node, 0);
+	init.parent_names = &parent_name;
+	init.num_parents = 1;
+
+	brcm_clk->hw.init = &init;
+
+	clk = clk_register(NULL, &brcm_clk->hw);
+	if (WARN_ON(IS_ERR(clk)))
+		goto err_unmap;
+
+	rc = of_clk_add_provider(node, of_clk_src_simple_get, clk);
+	if (WARN_ON(IS_ERR_VALUE(rc)))
+		goto err_unregister;
+
+	rc = clk_register_clkdev(clk, clk_name, NULL);
+	if (WARN_ON(IS_ERR_VALUE(rc)))
+		goto err_provider;
+
+	return clk;
+
+err_provider:
+	of_clk_del_provider(node);
+
+err_unregister:
+	clk_unregister(clk);
+
+err_unmap:
+	iounmap(brcm_clk->regs_base);
+
+err_alloc:
+	kfree(brcm_clk);
+
+	return NULL;
+}
+
+static void __init iproc_armpll_init(struct device_node *node)
+{
+	iproc_clock_init(node, &a9pll_ops);
+}
+CLK_OF_DECLARE(iproc_armpllx, "brcm,iproc-arm-a9pll", iproc_armpll_init);
+
+static void __init iproc_arm_ch_init(struct device_node *node)
+{
+	iproc_clock_init(node, &a9pll_chan_ops);
+}
+CLK_OF_DECLARE(iproc_arm_ch, "brcm,iproc-arm-ch", iproc_arm_ch_init);
-- 
1.7.9.5


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

* [PATCH 3/6] dt-bindings: Document Broadcom Cygnus SoC and clock driver
  2014-09-16 19:58 ` [PATCH 0/6] Add initial support for Broadcom Cygnus SoC Jonathan Richardson
  2014-09-16 19:58   ` [PATCH 1/6] ARM: cygnus: Initial " Jonathan Richardson
  2014-09-16 19:58   ` [PATCH 2/6] clk: Clock driver " Jonathan Richardson
@ 2014-09-16 19:58   ` Jonathan Richardson
  2014-09-16 19:58   ` [PATCH 4/6] ARM: dts: Enable Broadcom Cygnus SoC Jonathan Richardson
                     ` (3 subsequent siblings)
  6 siblings, 0 replies; 92+ messages in thread
From: Jonathan Richardson @ 2014-09-16 19:58 UTC (permalink / raw)
  To: Christian Daudt, Matt Porter, Russell King, Mike Turquette,
	Rob Herring, Pawel Moll, Mark Rutland, Ian Campbell, Kumar Gala,
	JD Zheng
  Cc: linux-arm-kernel, bcm-kernel-feedback-list, linux-kernel,
	devicetree, Scott Branden, Ray Jui, Jonathan Richardson

Reviewed-by: Arun Parameswaran <aparames@broadcom.com>
Tested-by: Jonathan Richardson <jonathar@broadcom.com>
Reviewed-by: JD (Jiandong) Zheng <jdzheng@broadcom.com>
Signed-off-by: Jonathan Richardson <jonathar@broadcom.com>
---
 Documentation/devicetree/bindings/arm/cygnus.txt   |   12 ++
 .../devicetree/bindings/clock/clk-cygnus.txt       |  121 ++++++++++++++++++++
 .../devicetree/bindings/clock/clk-iproc.txt        |   48 ++++++++
 3 files changed, 181 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/arm/cygnus.txt
 create mode 100644 Documentation/devicetree/bindings/clock/clk-cygnus.txt
 create mode 100644 Documentation/devicetree/bindings/clock/clk-iproc.txt

diff --git a/Documentation/devicetree/bindings/arm/cygnus.txt b/Documentation/devicetree/bindings/arm/cygnus.txt
new file mode 100644
index 0000000..a210377
--- /dev/null
+++ b/Documentation/devicetree/bindings/arm/cygnus.txt
@@ -0,0 +1,12 @@
+Broadcom Cygnus device tree bindings
+------------------------------------
+
+All Cygnus boards shall have the following properties:
+
+Required root node property:
+	- compatible = "brcm,cygnus";
+
+Boards variants shall have the following additional properties:
+
+Required root node property for the BCM911360_ENTPHN board:
+	- compatible = "brcm,bcm911360_entphn";
diff --git a/Documentation/devicetree/bindings/clock/clk-cygnus.txt b/Documentation/devicetree/bindings/clock/clk-cygnus.txt
new file mode 100644
index 0000000..7e03837
--- /dev/null
+++ b/Documentation/devicetree/bindings/clock/clk-cygnus.txt
@@ -0,0 +1,121 @@
+Broadcom Cygnus Clock Controller
+
+This binding uses the common clock binding:
+Documentation/devicetree/bindings/clock/clock-bindings.txt
+
+The Cygnus clock controller manages several PLL's and their channels, found only
+on the Cygnus chip. Clocks that are common to iProc can be found in the iProc
+clock controller. The controllers are split into a parent-child relationship
+where the parent is the PLL and the child controls the PLL's channels.
+
+All PLL's are derived from a 25MHz oscillator. The PLL's controlled are the
+GENPLL, LCPLL, the MIPI PLL. In addition, there are two clocks derived from
+GENPLL channel 0, and three that are derived directly from the oscillator.
+
+Required properties:
+- compatible: Must be one of the following:
+    "brcm,cygnus-lcpll-clk" - Controls LCPLL.
+    "brcm,cygnus-lcpll-ch" -  Controls LCPLL (parent) channels
+    "brcm,cygnus-genpll-clk" - Controls parent GENPLL
+    "brcm,cygnus-genpll-ch" - Controls GENPLL (parent) channels
+    "brcm,cygnus-mipipll-clk" - Controls MIPI PLL
+    "brcm,cygnus-mipipll-ch" - Controls parent MIPI PLL (parent) channels
+    "brcm,cygnus-osc-derived" - Controls oscillator (parent) derived channels
+        not controlled by any PLL.
+    "brcm,cygnus-pll-derived" - Controls clocks derived from GENPLL channel 0.
+	  These clocks have hard wired internal dividers and their clock rates
+	  scale according to the GENPLL channel.
+
+- reg: First register is the base address of the PLL. Register 2 and 3 are
+  required by some clocks. They are the top clock gating control used to
+  enable/disable clocks (ch 1), and the CRMU PLL AON CONTROL register which
+  powers on PLL/LDO's (ch 2).
+
+- clocks: The input parent clock phandle for the clock. This is either a PLL,
+  oscillator, or GENPLL channel 0.
+
+- channel: The PLL channel that the clock belongs to. This is used for
+  "brcm,cygnus-lcpll-ch", "brcm,cygnus-genpll-ch", "brcm,cygnus-mipipll-ch",
+  "brcm,cygnus-osc-derived" only.
+
+- div: Used by "brcm,cygnus-pll-derived" to define the hard coded internal
+  divider value. Used by "brcm,cygnus-osc-derived" to specify the programmable
+  divider.
+
+- #clock-cells: From common clock binding; shall be set to 0.
+
+Examples:
+
+		osc: oscillator {
+			#clock-cells = <0>;
+			compatible = "fixed-clock";
+			clock-frequency = <25000000>;
+		};
+
+		lcpll: lcpll@0301d02c {
+			#clock-cells = <0>;
+			compatible = "brcm,cygnus-lcpll-clk";
+			reg = <0x0301d02c 0x1c>;
+			clocks = <&osc>;
+		};
+
+		genpll: genpll@0301d000 {
+			#clock-cells = <0>;
+			compatible = "brcm,cygnus-genpll-clk";
+			reg = <0x0301d000 0x2c>,
+				  <0x180AA024 0x4>,
+				  <0x0301C020 0x4>;
+			clocks = <&osc>;
+		};
+
+		axi21_clk: genpll_ch0@0301d000 {
+			#clock-cells = <0>;
+			compatible = "brcm,cygnus-genpll-ch";
+			reg = <0x0301d000 0x2c>;
+			clocks = <&genpll>;
+			channel = <0>;
+		};
+
+		pcie_clk: lcpll_ch0@0301d02c {
+			compatible = "brcm,cygnus-lcpll-ch";
+			reg = <0x0301d02c 0x1c>;
+			#clock-cells = <0>;
+			clocks = <&lcpll>;
+			channel = <0>;
+		};
+
+		axi41_clk: axi41_clk {
+			reg = <0x0301d000 0x2c>;
+			#clock-cells = <0>;
+			compatible = "brcm,cygnus-pll-derived";
+			clocks = <&axi21_clk>;
+			div = <2>;
+		};
+
+		keypad_clk: keypad_clk@0301D048 {
+			compatible = "brcm,cygnus-osc-derived";
+			reg = <0x0301D048 0x4>,
+				  <0x180AA024 0x4>;
+			#clock-cells = <0>;
+			clocks = <&osc>;
+			channel = <0>;
+			div = <392>;
+		};
+
+		mipipll: mipipll@180a9800 {
+			#clock-cells = <0>;
+			compatible = "brcm,cygnus-mipipll-clk";
+			reg = <0x180a9800 0x2c>,
+				  top_clk_gating_ctrl: <0x180AA024 0x4>,
+				  crmu_pll_aon_ctrl: <0x0301C020 0x4>;
+			clocks = <&osc>;
+		};
+
+		lcd_clk: mipipll_ch1@180a9800 {
+			#clock-cells = <0>;
+			compatible = "brcm,cygnus-mipipll-ch";
+			reg = <0x180a9800 0x2c>,
+				  <0x180AA024 0x4>;
+			clocks = <&mipipll>;
+			channel = <1>;
+		};
diff --git a/Documentation/devicetree/bindings/clock/clk-iproc.txt b/Documentation/devicetree/bindings/clock/clk-iproc.txt
new file mode 100644
index 0000000..b5d4f08
--- /dev/null
+++ b/Documentation/devicetree/bindings/clock/clk-iproc.txt
@@ -0,0 +1,48 @@
+Broadcom iProc Clock Controller
+
+This binding uses the common clock binding:
+Documentation/devicetree/bindings/clock/clock-bindings.txt
+
+The iProc clock controller manages clocks that are common to iProc chips.
+The controllers are split into a parent-child relationship where the parent is
+the PLL and the child controls the PLL's channels.
+
+The only PLL controlled is the ARM PLL which is derived from a 25MHz crystal.
+
+Required properties:
+- compatible: Must be one of the following:
+    "brcm,iproc-arm-a9pll" - Controls ARM PLL.
+    "brcm,iproc-arm-ch" -  Controls ARM PLL (parent) channels
+
+- reg: The base address of the PLL.
+
+- clocks: The input parent clock phandle for the clock. This is either a PLL,
+  or oscillator.
+
+- channel: The PLL channel that the clock belongs to. This is used for
+  "brcm,iproc-arm-ch" only.
+
+- #clock-cells: From common clock binding; shall be set to 0.
+
+Example:
+
+	osc: oscillator {
+		#clock-cells = <0>;
+		compatible = "fixed-clock";
+		clock-frequency = <25000000>;
+	};
+
+	a9pll: arm_clk@19000000 {
+		compatible = "brcm,iproc-arm-a9pll";
+		reg = <0x19000000 0x1000>;
+		#clock-cells = <0>;
+		clocks = <&osc>;
+	};
+
+	periph_clk: periph_clk@19000000 {
+		compatible = "brcm,iproc-arm-ch";
+		reg = <0x19000000 0x1000>;
+		#clock-cells = <0>;
+		clocks = <&a9pll>;
+		channel = <3>;
+	};
-- 
1.7.9.5


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

* [PATCH 4/6] ARM: dts: Enable Broadcom Cygnus SoC
  2014-09-16 19:58 ` [PATCH 0/6] Add initial support for Broadcom Cygnus SoC Jonathan Richardson
                     ` (2 preceding siblings ...)
  2014-09-16 19:58   ` [PATCH 3/6] dt-bindings: Document Broadcom Cygnus SoC and clock driver Jonathan Richardson
@ 2014-09-16 19:58   ` Jonathan Richardson
  2014-09-16 19:58   ` [PATCH 5/6] ARM: cygnus defconfig : Initial defconfig for " Jonathan Richardson
                     ` (2 subsequent siblings)
  6 siblings, 0 replies; 92+ messages in thread
From: Jonathan Richardson @ 2014-09-16 19:58 UTC (permalink / raw)
  To: Christian Daudt, Matt Porter, Russell King, Mike Turquette,
	Rob Herring, Pawel Moll, Mark Rutland, Ian Campbell, Kumar Gala,
	JD Zheng
  Cc: linux-arm-kernel, bcm-kernel-feedback-list, linux-kernel,
	devicetree, Scott Branden, Ray Jui, Jonathan Richardson

DT files to enable cygnus consisting of the enterprise phone board variant and
cygnus core configuration.

Reviewed-by: Ray Jui <rjui@broadcom.com>
Reviewed-by: Arun Parameswaran <aparames@broadcom.com>
Reviewed-by: Scott Branden <sbranden@broadcom.com>
Tested-by: Jonathan Richardson <jonathar@broadcom.com>
Reviewed-by: JD (Jiandong) Zheng <jdzheng@broadcom.com>
Signed-off-by: Jonathan Richardson <jonathar@broadcom.com>
---
 arch/arm/boot/dts/Makefile             |    1 +
 arch/arm/boot/dts/bcm-cygnus.dtsi      |  344 ++++++++++++++++++++++++++++++++
 arch/arm/boot/dts/bcm911360_entphn.dts |   17 ++
 3 files changed, 362 insertions(+)
 create mode 100644 arch/arm/boot/dts/bcm-cygnus.dtsi
 create mode 100644 arch/arm/boot/dts/bcm911360_entphn.dts

diff --git a/arch/arm/boot/dts/Makefile b/arch/arm/boot/dts/Makefile
index b8c5cd3..b95d41d 100644
--- a/arch/arm/boot/dts/Makefile
+++ b/arch/arm/boot/dts/Makefile
@@ -52,6 +52,7 @@ dtb-$(CONFIG_ARCH_AT91)	+= sama5d36ek.dtb
 dtb-$(CONFIG_ARCH_ATLAS6) += atlas6-evb.dtb
 dtb-$(CONFIG_ARCH_AXXIA) += axm5516-amarillo.dtb
 dtb-$(CONFIG_ARCH_BCM2835) += bcm2835-rpi-b.dtb
+dtb-$(CONFIG_ARCH_BCM_CYGNUS) += bcm911360_entphn.dtb
 dtb-$(CONFIG_ARCH_BCM_5301X) += bcm4708-netgear-r6250.dtb
 dtb-$(CONFIG_ARCH_BCM_MOBILE) += bcm28155-ap.dtb \
 	bcm21664-garnet.dtb
diff --git a/arch/arm/boot/dts/bcm-cygnus.dtsi b/arch/arm/boot/dts/bcm-cygnus.dtsi
new file mode 100644
index 0000000..f575402
--- /dev/null
+++ b/arch/arm/boot/dts/bcm-cygnus.dtsi
@@ -0,0 +1,344 @@
+/*
+ * Copyright 2014 Broadcom Corporation.  All rights reserved.
+ *
+ * Unless you and Broadcom execute a separate written software license
+ * agreement governing use of this software, this software is licensed to you
+ * under the terms of the GNU General Public License version 2, available at
+ * http://www.broadcom.com/licenses/GPLv2.php (the "GPL").
+ */
+
+#include <dt-bindings/interrupt-controller/arm-gic.h>
+#include <dt-bindings/interrupt-controller/irq.h>
+
+#include "skeleton.dtsi"
+
+/ {
+	compatible = "brcm,cygnus";
+	model = "Broadcom Cygnus SoC";
+	interrupt-parent = <&gic>;
+
+	aliases {
+		serial0 = &uart3;
+		serial1 = &uart0;
+	};
+
+	chosen {
+		bootargs = "console=ttyS0,115200 earlyprintk debug";
+	};
+
+	cpus {
+		#address-cells = <1>;
+		#size-cells = <0>;
+
+		cpu@0 {
+			device_type = "cpu";
+			compatible = "arm,cortex-a9";
+			next-level-cache = <&L2>;
+			reg = <0x0>;
+		};
+	};
+
+	clocks {
+		#address-cells = <1>;
+		#size-cells = <1>;
+		ranges;
+
+		osc: oscillator {
+			#clock-cells = <0>;
+			compatible = "fixed-clock";
+			clock-frequency = <25000000>;
+		};
+
+		lcpll: lcpll@0301d02c {
+			#clock-cells = <0>;
+			compatible = "brcm,cygnus-lcpll-clk";
+			reg = <0x0301d02c 0x1c>;
+			clocks = <&osc>;
+		};
+
+		genpll: genpll@0301d000 {
+			#clock-cells = <0>;
+			compatible = "brcm,cygnus-genpll-clk";
+			reg = <0x0301d000 0x2c>,
+				  <0x180AA024 0x4>,
+				  <0x0301C020 0x4>;
+			clocks = <&osc>;
+		};
+
+		axi21_clk: genpll_ch0@0301d000 {
+			#clock-cells = <0>;
+			compatible = "brcm,cygnus-genpll-ch";
+			reg = <0x0301d000 0x2c>;
+			clocks = <&genpll>;
+			channel = <0>;
+		};
+
+		clk_25MHz: genpll_ch1@0301d000 {
+			#clock-cells = <0>;
+			compatible = "brcm,cygnus-genpll-ch";
+			reg = <0x0301d000 0x2c>;
+			clocks = <&genpll>;
+			channel = <1>;
+		};
+
+		sys_clk: genpll_ch2@0301d000 {
+			#clock-cells = <0>;
+			compatible = "brcm,cygnus-genpll-ch";
+			reg = <0x0301d000 0x2c>;
+			clocks = <&genpll>;
+			channel = <2>;
+		};
+
+		ethernet_clk: genpll_ch3@0301d000 {
+			#clock-cells = <0>;
+			compatible = "brcm,cygnus-genpll-ch";
+			reg = <0x0301d000 0x2c>;
+			clocks = <&genpll>;
+			channel = <3>;
+		};
+
+		asiu_audio_clk: genpll_ch4@0301d000 {
+			#clock-cells = <0>;
+			compatible = "brcm,cygnus-genpll-ch";
+			reg = <0x0301d000 0x2c>;
+			clocks = <&genpll>;
+			channel = <4>;
+		};
+
+		asiu_can_clk: genpll_ch5@0301d000 {
+			#clock-cells = <0>;
+			compatible = "brcm,cygnus-genpll-ch";
+			reg = <0x0301d000 0x2c>;
+			clocks = <&genpll>;
+			channel = <5>;
+		};
+
+		pcie_clk: lcpll_ch0@0301d02c {
+			compatible = "brcm,cygnus-lcpll-ch";
+			reg = <0x0301d02c 0x1c>;
+			#clock-cells = <0>;
+			clocks = <&lcpll>;
+			channel = <0>;
+		};
+
+		ddr_clk: lcpll_ch1@0301d02c {
+			compatible = "brcm,cygnus-lcpll-ch";
+			reg = <0x0301d02c 0x1c>;
+			#clock-cells = <0>;
+			clocks = <&lcpll>;
+			channel = <1>;
+		};
+
+		sdio_clk: lcpll_ch2@0301d02c {
+			compatible = "brcm,cygnus-lcpll-ch";
+			reg = <0x0301d02c 0x1c>;
+			#clock-cells = <0>;
+			clocks = <&lcpll>;
+			channel = <2>;
+		};
+
+		usb_clk: lcpll_ch3@0301d02c {
+		    compatible = "brcm,cygnus-lcpll-ch";
+			reg = <0x0301d02c 0x1c>;
+			#clock-cells = <0>;
+			clocks = <&lcpll>;
+			channel = <3>;
+		};
+
+		smart_card_clk: lcpll_ch4@0301d02c {
+			compatible = "brcm,cygnus-lcpll-ch";
+			reg = <0x0301d02c 0x1c>;
+			#clock-cells = <0>;
+			clocks = <&lcpll>;
+			channel = <4>;
+		};
+
+		ch5_unknown_clk: lcpll_ch5@0301d02c {
+			compatible = "brcm,cygnus-lcpll-ch";
+			reg = <0x0301d02c 0x1c>;
+			#clock-cells = <0>;
+			clocks = <&lcpll>;
+			channel = <5>;
+		};
+
+		/*
+		 * There are 2 clocks derived from genpll ch0 (axi21) which are
+		 * divided internally by 2 and 4. If axi21 clock rate changes, these
+		 * derived clock rates scale accordingly.
+		 */
+
+		axi41_clk: axi41_clk {
+			reg = <0x0301d000 0x2c>;
+			#clock-cells = <0>;
+			compatible = "brcm,cygnus-pll-derived";
+			clocks = <&axi21_clk>;
+			div = <2>;
+		};
+
+		axi81_clk: axi81_clk {
+			reg = <0x0301d000 0x2c>;
+			#clock-cells = <0>;
+			compatible = "brcm,cygnus-pll-derived";
+			clocks = <&axi21_clk>;
+			div = <4>;
+		};
+
+		/*
+		 * The main output of the ARM PLL is arm_clk with several derived
+		 * child clocks:
+		 * 		periph_clk
+		 * 		apb_clk
+		 * 		arm_switch
+		 * 		apb0_free
+		 */
+		a9pll: arm_clk@19000000 {
+			compatible = "brcm,iproc-arm-a9pll";
+			reg = <0x19000000 0x1000>;
+			#clock-cells = <0>;
+			clocks = <&osc>;
+		};
+
+		periph_clk: periph_clk@19000000 {
+			compatible = "brcm,iproc-arm-ch";
+			reg = <0x19000000 0x1000>;
+			#clock-cells = <0>;
+			clocks = <&a9pll>;
+			channel = <3>;
+		};
+
+		apb0_free: apb0_free@19000000 {
+			compatible = "brcm,iproc-arm-ch";
+			reg = <0x19000000 0x1000>;
+			#clock-cells = <0>;
+			clocks = <&a9pll>;
+			channel = <0>;
+		};
+
+		arm_switch: arm_switch@19000000 {
+			compatible = "brcm,iproc-arm-ch";
+			reg = <0x19000000 0x1000>;
+			#clock-cells = <0>;
+			clocks = <&a9pll>;
+			channel = <1>;
+		};
+
+		apb_clk: apb_clk@19000000 {
+			compatible = "brcm,iproc-arm-ch";
+			reg = <0x19000000 0x1000>;
+			#clock-cells = <0>;
+			clocks = <&a9pll>;
+			channel = <2>;
+		};
+
+		/*
+		 * Clocks derived from oscillator.
+		 */
+		keypad_clk: keypad_clk@0301D048 {
+			compatible = "brcm,cygnus-osc-derived";
+			reg = <0x0301D048 0x4>,
+				  <0x180AA024 0x4>;
+			#clock-cells = <0>;
+			clocks = <&osc>;
+			channel = <0>;
+			div = <392>;
+		};
+
+		adc_clk: adc_clk@0301D04C {
+			compatible = "brcm,cygnus-osc-derived";
+			reg = <0x0301D04C 0x4>,
+				  <0x180AA024 0x4>;
+			#clock-cells = <0>;
+			clocks = <&osc>;
+			channel = <1>;
+		};
+
+		pwm_clk: pwm_clk@0301D050 {
+			compatible = "brcm,cygnus-osc-derived";
+			reg = <0x0301D050 0x4>,
+				  <0x180AA024 0x4>;
+			#clock-cells = <0>;
+			clocks = <&osc>;
+			channel = <2>;
+		};
+
+		mipipll: mipipll@180a9800 {
+			#clock-cells = <0>;
+			compatible = "brcm,cygnus-mipipll-clk";
+			reg = <0x180a9800 0x2c>,
+				  top_clk_gating_ctrl: <0x180AA024 0x4>,
+				  crmu_pll_aon_ctrl: <0x0301C020 0x4>;
+			clocks = <&osc>;
+		};
+
+		lcd_clk: mipipll_ch1@180a9800 {
+			#clock-cells = <0>;
+			compatible = "brcm,cygnus-mipipll-ch";
+			reg = <0x180a9800 0x2c>,
+				  <0x180AA024 0x4>;
+			clocks = <&mipipll>;
+			channel = <1>;
+		};
+	};
+
+	amba {
+		#address-cells = <1>;
+		#size-cells = <1>;
+		compatible = "arm,amba-bus", "simple-bus";
+		interrupt-parent = <&gic>;
+		ranges;
+
+		wdt@18009000 {
+			 compatible = "arm,sp805" , "arm,primecell";
+			 reg = <0x18009000 0x1000>;
+			 interrupts = <GIC_SPI 91 IRQ_TYPE_LEVEL_HIGH>;
+			 clocks = <&axi81_clk>;
+			 clock-names = "apb_pclk";
+		};
+	};
+
+	uart3: serial@18023000 {
+		compatible = "snps,dw-apb-uart";
+		reg = <0x18023000 0x100>;
+		reg-shift = <2>;
+		reg-io-width = <4>;
+		interrupts = <GIC_SPI 76 IRQ_TYPE_LEVEL_HIGH>;
+		clock-frequency = <100000000>;
+		clocks = <&axi81_clk>;
+		status = "okay";
+	};
+
+	uart0: serial@18020000 {
+		compatible = "snps,dw-apb-uart";
+		reg = <0x18020000 0x100>;
+		reg-shift = <2>;
+		reg-io-width = <4>;
+		interrupts = <GIC_SPI 73 IRQ_TYPE_LEVEL_HIGH>;
+		clocks = <&axi81_clk>;
+		clock-frequency = <100000000>;
+		status = "okay";
+	};
+
+	gic: interrupt-controller@19021000 {
+		compatible = "arm,cortex-a9-gic";
+		#interrupt-cells = <3>;
+		#address-cells = <0>;
+		interrupt-controller;
+		reg = <0x19021000 0x1000>,
+		      <0x19020100 0x100>;
+	};
+
+	L2: l2-cache {
+		compatible = "arm,pl310-cache";
+		reg = <0x19022000 0x1000>;
+		cache-unified;
+		cache-level = <2>;
+	};
+
+	timer@19020200 {
+		compatible = "arm,cortex-a9-global-timer";
+		reg = <0x19020200 0x100>;
+		interrupts = <GIC_PPI 11 IRQ_TYPE_LEVEL_HIGH>;
+		clocks = <&periph_clk>;
+	};
+
+};
diff --git a/arch/arm/boot/dts/bcm911360_entphn.dts b/arch/arm/boot/dts/bcm911360_entphn.dts
new file mode 100644
index 0000000..db48004
--- /dev/null
+++ b/arch/arm/boot/dts/bcm911360_entphn.dts
@@ -0,0 +1,17 @@
+/*
+ * Copyright 2014 Broadcom Corporation.  All rights reserved.
+ *
+ * Unless you and Broadcom execute a separate written software license
+ * agreement governing use of this software, this software is licensed to you
+ * under the terms of the GNU General Public License version 2, available at
+ * http://www.broadcom.com/licenses/GPLv2.php (the "GPL").
+ */
+
+/dts-v1/;
+
+#include "bcm-cygnus.dtsi"
+
+/ {
+	model = "Cygnus Enterprise Phone (BCM911360_ENTPHN)";
+	compatible = "brcm,bcm911360_entphn", "brcm,cygnus";
+};
-- 
1.7.9.5


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

* [PATCH 5/6] ARM: cygnus defconfig : Initial defconfig for Broadcom Cygnus SoC
  2014-09-16 19:58 ` [PATCH 0/6] Add initial support for Broadcom Cygnus SoC Jonathan Richardson
                     ` (3 preceding siblings ...)
  2014-09-16 19:58   ` [PATCH 4/6] ARM: dts: Enable Broadcom Cygnus SoC Jonathan Richardson
@ 2014-09-16 19:58   ` Jonathan Richardson
  2014-09-16 19:58   ` [PATCH 6/6] MAINTAINERS: Entry for Cygnus/iproc arm architecture and clock drivers Jonathan Richardson
  2014-09-18 22:31   ` [PATCH 0/6] Add initial support for Broadcom Cygnus SoC Hauke Mehrtens
  6 siblings, 0 replies; 92+ messages in thread
From: Jonathan Richardson @ 2014-09-16 19:58 UTC (permalink / raw)
  To: Christian Daudt, Matt Porter, Russell King, Mike Turquette,
	Rob Herring, Pawel Moll, Mark Rutland, Ian Campbell, Kumar Gala,
	JD Zheng
  Cc: linux-arm-kernel, bcm-kernel-feedback-list, linux-kernel,
	devicetree, Scott Branden, Ray Jui, Jonathan Richardson

Tested-by: Jonathan Richardson <jonathar@broadcom.com>
Reviewed-by: JD (Jiandong) Zheng <jdzheng@broadcom.com>
Signed-off-by: Jonathan Richardson <jonathar@broadcom.com>
---
 arch/arm/configs/bcm_cygnus_defconfig |  223 +++++++++++++++++++++++++++++++++
 1 file changed, 223 insertions(+)
 create mode 100644 arch/arm/configs/bcm_cygnus_defconfig

diff --git a/arch/arm/configs/bcm_cygnus_defconfig b/arch/arm/configs/bcm_cygnus_defconfig
new file mode 100644
index 0000000..effed85
--- /dev/null
+++ b/arch/arm/configs/bcm_cygnus_defconfig
@@ -0,0 +1,223 @@
+CONFIG_KERNEL_XZ=y
+# CONFIG_SWAP is not set
+CONFIG_SYSVIPC=y
+CONFIG_IRQ_DOMAIN_DEBUG=y
+CONFIG_HIGH_RES_TIMERS=y
+CONFIG_BSD_PROCESS_ACCT=y
+CONFIG_BSD_PROCESS_ACCT_V3=y
+CONFIG_IKCONFIG=y
+CONFIG_IKCONFIG_PROC=y
+CONFIG_LOG_BUF_SHIFT=19
+CONFIG_CGROUPS=y
+CONFIG_CGROUP_FREEZER=y
+CONFIG_CGROUP_DEVICE=y
+CONFIG_CGROUP_CPUACCT=y
+CONFIG_RESOURCE_COUNTERS=y
+CONFIG_CGROUP_SCHED=y
+CONFIG_BLK_CGROUP=y
+CONFIG_NAMESPACES=y
+CONFIG_BLK_DEV_INITRD=y
+CONFIG_SYSCTL_SYSCALL=y
+CONFIG_EMBEDDED=y
+CONFIG_PERF_EVENTS=y
+# CONFIG_COMPAT_BRK is not set
+CONFIG_MODULES=y
+CONFIG_MODULE_UNLOAD=y
+# CONFIG_BLK_DEV_BSG is not set
+CONFIG_PARTITION_ADVANCED=y
+CONFIG_ARCH_BCM=y
+CONFIG_ARCH_BCM_IPROC=y
+CONFIG_ARCH_BCM_CYGNUS=y
+CONFIG_ARM_THUMBEE=y
+CONFIG_PREEMPT=y
+CONFIG_AEABI=y
+CONFIG_HIGHMEM=y
+# CONFIG_COMPACTION is not set
+# CONFIG_ATAGS is not set
+CONFIG_ZBOOT_ROM_TEXT=0x0
+CONFIG_ZBOOT_ROM_BSS=0x0
+CONFIG_ARM_APPENDED_DTB=y
+CONFIG_CPU_IDLE=y
+CONFIG_VFP=y
+CONFIG_NEON=y
+# CONFIG_SUSPEND is not set
+CONFIG_NET=y
+CONFIG_PACKET=y
+CONFIG_UNIX=y
+CONFIG_INET=y
+CONFIG_IP_MULTICAST=y
+CONFIG_IP_ADVANCED_ROUTER=y
+CONFIG_IP_MULTIPLE_TABLES=y
+CONFIG_IP_ROUTE_MULTIPATH=y
+CONFIG_IP_ROUTE_VERBOSE=y
+CONFIG_IP_PNP=y
+CONFIG_IP_PNP_DHCP=y
+CONFIG_IP_MROUTE=y
+CONFIG_IP_MROUTE_MULTIPLE_TABLES=y
+CONFIG_SYN_COOKIES=y
+# CONFIG_INET_XFRM_MODE_TRANSPORT is not set
+# CONFIG_INET_XFRM_MODE_TUNNEL is not set
+# CONFIG_INET_XFRM_MODE_BEET is not set
+# CONFIG_INET_LRO is not set
+# CONFIG_INET_DIAG is not set
+CONFIG_TCP_CONG_ADVANCED=y
+# CONFIG_TCP_CONG_BIC is not set
+# CONFIG_TCP_CONG_WESTWOOD is not set
+# CONFIG_TCP_CONG_HTCP is not set
+CONFIG_IPV6=y
+# CONFIG_INET6_XFRM_MODE_TRANSPORT is not set
+# CONFIG_INET6_XFRM_MODE_TUNNEL is not set
+# CONFIG_INET6_XFRM_MODE_BEET is not set
+# CONFIG_IPV6_SIT is not set
+CONFIG_IPV6_MULTIPLE_TABLES=y
+CONFIG_IPV6_SUBTREES=y
+CONFIG_IPV6_MROUTE=y
+CONFIG_NETFILTER=y
+# CONFIG_BRIDGE_NETFILTER is not set
+CONFIG_NF_CONNTRACK=y
+# CONFIG_NF_CONNTRACK_PROCFS is not set
+CONFIG_NF_CONNTRACK_FTP=y
+CONFIG_NF_CONNTRACK_IPV4=y
+CONFIG_IP_NF_IPTABLES=y
+CONFIG_IP_NF_FILTER=y
+CONFIG_IP_NF_TARGET_REJECT=y
+CONFIG_NF_NAT_IPV4=y
+CONFIG_IP_NF_TARGET_MASQUERADE=y
+CONFIG_IP_NF_TARGET_REDIRECT=y
+CONFIG_IP_NF_MANGLE=y
+CONFIG_IP_NF_RAW=y
+CONFIG_NF_CONNTRACK_IPV6=y
+CONFIG_IP6_NF_IPTABLES=y
+CONFIG_IP6_NF_MATCH_AH=y
+CONFIG_IP6_NF_MATCH_EUI64=y
+CONFIG_IP6_NF_MATCH_FRAG=y
+CONFIG_IP6_NF_MATCH_OPTS=y
+CONFIG_IP6_NF_MATCH_IPV6HEADER=y
+CONFIG_IP6_NF_MATCH_MH=y
+CONFIG_IP6_NF_MATCH_RT=y
+CONFIG_IP6_NF_FILTER=y
+CONFIG_IP6_NF_TARGET_REJECT=y
+CONFIG_IP6_NF_MANGLE=y
+CONFIG_IP6_NF_RAW=y
+CONFIG_BRIDGE=y
+# CONFIG_BRIDGE_IGMP_SNOOPING is not set
+CONFIG_VLAN_8021Q=y
+CONFIG_NET_SCHED=y
+CONFIG_NET_SCH_FQ_CODEL=y
+CONFIG_DEVTMPFS=y
+CONFIG_DEVTMPFS_MOUNT=y
+# CONFIG_FIRMWARE_IN_KERNEL is not set
+CONFIG_MTD=y
+CONFIG_MTD_CMDLINE_PARTS=y
+CONFIG_MTD_BLOCK=y
+CONFIG_MTD_NAND=y
+CONFIG_MTD_UBI=y
+# CONFIG_BLK_DEV is not set
+CONFIG_SCSI=y
+CONFIG_BLK_DEV_SD=y
+CONFIG_SCSI_MULTI_LUN=y
+CONFIG_NETDEVICES=y
+# CONFIG_NET_CADENCE is not set
+# CONFIG_NET_VENDOR_CIRRUS is not set
+# CONFIG_NET_VENDOR_FARADAY is not set
+# CONFIG_NET_VENDOR_INTEL is not set
+# CONFIG_NET_VENDOR_MARVELL is not set
+# CONFIG_NET_VENDOR_MICREL is not set
+# CONFIG_NET_VENDOR_NATSEMI is not set
+# CONFIG_NET_VENDOR_SEEQ is not set
+# CONFIG_NET_VENDOR_SMSC is not set
+# CONFIG_NET_VENDOR_STMICRO is not set
+# CONFIG_NET_VENDOR_WIZNET is not set
+CONFIG_PHYLIB=y
+CONFIG_BROADCOM_PHY=y
+# CONFIG_INPUT_MOUSEDEV is not set
+# CONFIG_KEYBOARD_ATKBD is not set
+# CONFIG_INPUT_MOUSE is not set
+# CONFIG_SERIO is not set
+# CONFIG_LEGACY_PTYS is not set
+CONFIG_SERIAL_8250=y
+# CONFIG_SERIAL_8250_DEPRECATED_OPTIONS is not set
+CONFIG_SERIAL_8250_CONSOLE=y
+CONFIG_SERIAL_8250_NR_UARTS=2
+CONFIG_SERIAL_8250_RUNTIME_UARTS=2
+CONFIG_SERIAL_8250_DW=y
+CONFIG_SERIAL_OF_PLATFORM=y
+# CONFIG_HW_RANDOM is not set
+CONFIG_I2C=y
+CONFIG_I2C_CHARDEV=y
+# CONFIG_I2C_HELPER_AUTO is not set
+CONFIG_I2C_SMBUS=y
+CONFIG_SPI=y
+CONFIG_SPI_PL022=y
+CONFIG_SPI_SPIDEV=y
+CONFIG_GPIO_SYSFS=y
+# CONFIG_HWMON is not set
+CONFIG_WATCHDOG=y
+CONFIG_ARM_SP805_WATCHDOG=y
+CONFIG_FB=y
+CONFIG_FB_ARMCLCD=y
+CONFIG_BACKLIGHT_LCD_SUPPORT=y
+# CONFIG_LCD_CLASS_DEVICE is not set
+CONFIG_BACKLIGHT_CLASS_DEVICE=y
+# CONFIG_BACKLIGHT_GENERIC is not set
+CONFIG_BACKLIGHT_PWM=y
+CONFIG_SOUND=y
+CONFIG_SND=y
+CONFIG_SND_DYNAMIC_MINORS=y
+CONFIG_SND_VERBOSE_PRINTK=y
+CONFIG_SND_DEBUG=y
+CONFIG_SND_USB_AUDIO=y
+CONFIG_SND_SOC=y
+CONFIG_USB=y
+CONFIG_USB_ANNOUNCE_NEW_DEVICES=y
+CONFIG_USB_EHCI_HCD=y
+CONFIG_USB_EHCI_ROOT_HUB_TT=y
+CONFIG_USB_EHCI_HCD_PLATFORM=y
+CONFIG_USB_STORAGE=y
+CONFIG_MMC=y
+CONFIG_MMC_SDHCI=y
+CONFIG_MMC_SDHCI_PLTFM=y
+CONFIG_PWM=y
+CONFIG_EXT4_FS=y
+CONFIG_MSDOS_FS=y
+CONFIG_VFAT_FS=y
+CONFIG_NTFS_FS=y
+CONFIG_TMPFS=y
+CONFIG_TMPFS_POSIX_ACL=y
+CONFIG_UBIFS_FS=y
+CONFIG_NFS_FS=y
+CONFIG_ROOT_NFS=y
+CONFIG_NLS_CODEPAGE_437=y
+CONFIG_NLS_ISO8859_1=y
+CONFIG_NLS_UTF8=y
+CONFIG_DYNAMIC_DEBUG=y
+CONFIG_DEBUG_INFO=y
+CONFIG_DEBUG_INFO_REDUCED=y
+CONFIG_STRIP_ASM_SYMS=y
+CONFIG_DEBUG_FS=y
+CONFIG_MAGIC_SYSRQ=y
+CONFIG_DEBUG_OBJECTS=y
+CONFIG_DEBUG_OBJECTS_RCU_HEAD=y
+CONFIG_SLUB_DEBUG_ON=y
+CONFIG_DEBUG_MEMORY_INIT=y
+CONFIG_DEBUG_SHIRQ=y
+CONFIG_DETECT_HUNG_TASK=y
+CONFIG_DEFAULT_HUNG_TASK_TIMEOUT=110
+CONFIG_BOOTPARAM_HUNG_TASK_PANIC=y
+# CONFIG_SCHED_DEBUG is not set
+CONFIG_SCHEDSTATS=y
+CONFIG_DEBUG_RT_MUTEXES=y
+CONFIG_PROVE_LOCKING=y
+CONFIG_DEBUG_ATOMIC_SLEEP=y
+# CONFIG_DEBUG_BUGVERBOSE is not set
+CONFIG_DEBUG_SG=y
+CONFIG_DEBUG_NOTIFIERS=y
+CONFIG_DEBUG_CREDENTIALS=y
+CONFIG_PROVE_RCU=y
+CONFIG_DEBUG_USER=y
+CONFIG_DEBUG_LL=y
+CONFIG_DEBUG_LL_UART_8250=y
+CONFIG_DEBUG_UART_PHYS=0x18023000
+CONFIG_DEBUG_UART_VIRT=0xf1023000
+CONFIG_EARLY_PRINTK=y
+# CONFIG_CRYPTO_ANSI_CPRNG is not set
-- 
1.7.9.5


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

* [PATCH 6/6] MAINTAINERS: Entry for Cygnus/iproc arm architecture and clock drivers
  2014-09-16 19:58 ` [PATCH 0/6] Add initial support for Broadcom Cygnus SoC Jonathan Richardson
                     ` (4 preceding siblings ...)
  2014-09-16 19:58   ` [PATCH 5/6] ARM: cygnus defconfig : Initial defconfig for " Jonathan Richardson
@ 2014-09-16 19:58   ` Jonathan Richardson
  2014-09-18 22:31   ` [PATCH 0/6] Add initial support for Broadcom Cygnus SoC Hauke Mehrtens
  6 siblings, 0 replies; 92+ messages in thread
From: Jonathan Richardson @ 2014-09-16 19:58 UTC (permalink / raw)
  To: Christian Daudt, Matt Porter, Russell King, Mike Turquette,
	Rob Herring, Pawel Moll, Mark Rutland, Ian Campbell, Kumar Gala,
	JD Zheng
  Cc: linux-arm-kernel, bcm-kernel-feedback-list, linux-kernel,
	devicetree, Scott Branden, Ray Jui, Jonathan Richardson

Tested-by: Jonathan Richardson <jonathar@broadcom.com>
Reviewed-by: Scott Branden <sbranden@broadcom.com>
Signed-off-by: Jonathan Richardson <jonathar@broadcom.com>
---
 MAINTAINERS |   21 +++++++++++++++++++++
 1 file changed, 21 insertions(+)

diff --git a/MAINTAINERS b/MAINTAINERS
index 809ecd6..2152ee0 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -2070,6 +2070,27 @@ L:	linux-scsi@vger.kernel.org
 S:	Supported
 F:	drivers/scsi/bnx2i/
 
+BROADCOM CYGNUS/IPROC ARM ARCHITECTURE
+M:	Jonathan Richardson <jonathar@broadcom.com>
+M:	Scott Branden <sbranden@broadcom.com>
+L:	linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
+S:	Maintained
+F:	Documentation/devicetree/bindings/arm/cygnus.txt
+F:	arch/arm/boot/dts/bcm-cygnus.dtsi
+F:	arch/arm/boot/dts/bcm911360_entphn.dts
+F:	arch/arm/configs/bcm_cygnus_defconfig
+F:	arch/arm/mach-bcm/board_bcm_cygnus.c
+
+BROADCOM CYGNUS/IPROC CLOCK DRIVERS
+M:	Jonathan Richardson <jonathar@broadcom.com>
+M:	Scott Branden <sbranden@broadcom.com>
+L:	linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
+S:	Maintained
+F:	Documentation/devicetree/bindings/clock/clk-cygnus.txt
+F:	Documentation/devicetree/bindings/clock/clk-iproc.txt
+F:	drivers/clk/bcm/clk-cygnus.c
+F:	drivers/clk/bcm/clk-iproc.c
+
 BROADCOM KONA GPIO DRIVER
 M:	Ray Jui <rjui@broadcom.com>
 L:	bcm-kernel-feedback-list@broadcom.com
-- 
1.7.9.5


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

* Re: [PATCH 1/6] ARM: cygnus: Initial support for Broadcom Cygnus SoC
  2014-09-16 19:58   ` [PATCH 1/6] ARM: cygnus: Initial " Jonathan Richardson
@ 2014-09-17  0:00     ` Mark Rutland
  2014-09-18 23:33       ` Jonathan Richardson
  0 siblings, 1 reply; 92+ messages in thread
From: Mark Rutland @ 2014-09-17  0:00 UTC (permalink / raw)
  To: Jonathan Richardson
  Cc: Christian Daudt, Matt Porter, Russell King, Mike Turquette,
	Rob Herring, Pawel Moll, Ian Campbell, Kumar Gala, JD Zheng,
	linux-arm-kernel, bcm-kernel-feedback-list, linux-kernel,
	devicetree, Scott Branden, Ray Jui

On Tue, Sep 16, 2014 at 08:58:12PM +0100, Jonathan Richardson wrote:
> Adds initial support for the Cygnus SoC based on Broadcom’s iProc series.
> 
> Reviewed-by: Ray Jui <rjui@broadcom.com>
> Reviewed-by: Desmond Liu <desmondl@broadcom.com>
> Reviewed-by: JD (Jiandong) Zheng <jdzheng@broadcom.com>
> Tested-by: Jonathan Richardson <jonathar@broadcom.com>
> Signed-off-by: Jonathan Richardson <jonathar@broadcom.com>
> ---
>  arch/arm/mach-bcm/Kconfig            |   34 +++++++
>  arch/arm/mach-bcm/Makefile           |    3 +
>  arch/arm/mach-bcm/board_bcm_cygnus.c |  166 ++++++++++++++++++++++++++++++++++

Is Cygnus an SoC or a board?

>  3 files changed, 203 insertions(+)
>  create mode 100644 arch/arm/mach-bcm/board_bcm_cygnus.c
> 
> diff --git a/arch/arm/mach-bcm/Kconfig b/arch/arm/mach-bcm/Kconfig
> index fc93800..58e0f20 100644
> --- a/arch/arm/mach-bcm/Kconfig
> +++ b/arch/arm/mach-bcm/Kconfig
> @@ -5,6 +5,40 @@ menuconfig ARCH_BCM
>  
>  if ARCH_BCM
>  
> +config ARCH_BCM_IPROC
> +	bool "Broadcom ARMv7 iProc boards" if ARCH_MULTI_V7
> +	select ARM_GIC
> +	select CACHE_L2X0
> +	select HAVE_ARM_SCU if SMP

I didn't spot any SMP code in this series.

> +	select HAVE_ARM_TWD if LOCAL_TIMERS
> +	select HAVE_CLK
> +	select CLKSRC_OF
> +	select CLKSRC_MMIO
> +	select LOCAL_TIMERS if SMP
> +	select GENERIC_CLOCKEVENTS_BUILD

You don't need to select this.

> +	select GENERIC_CLOCKEVENTS
> +	select ARM_GLOBAL_TIMER
> +	select ARCH_REQUIRE_GPIOLIB
> +	select ARM_AMBA
> +	select PINCTRL
> +	select DEBUG_UART_8250
> +	help
> +	  This enables support for systems based on Broadcom IPROC architected SoCs.
> +	  The IPROC complex contains one or more ARM CPUs along with common
> +	  core periperals. Application specific SoCs are created by adding a
> +	  uArchitecture containing peripherals outside of the IPROC complex.
> +	  Currently supported SoCs are Cygnus.
> +
> +menu "iProc SoC based Machine types"
> +	depends on ARCH_BCM_IPROC
> +
> +	config ARCH_BCM_CYGNUS
> +		bool "Support Broadcom Cygnus board"
> +		select USB_ARCH_HAS_EHCI if USB_SUPPORT
> +		help
> +		  Support for Broadcom Cygnus SoC.
> +endmenu
> +
>  config ARCH_BCM_MOBILE
>  	bool "Broadcom Mobile SoC Support" if ARCH_MULTI_V7
>  	select ARCH_REQUIRE_GPIOLIB
> diff --git a/arch/arm/mach-bcm/Makefile b/arch/arm/mach-bcm/Makefile
> index b19a396..dd14a10 100644
> --- a/arch/arm/mach-bcm/Makefile
> +++ b/arch/arm/mach-bcm/Makefile
> @@ -10,6 +10,9 @@
>  # of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
>  # GNU General Public License for more details.
>  
> +# Cygnus
> +obj-$(CONFIG_ARCH_BCM_CYGNUS) +=  board_bcm_cygnus.o
> +
>  # BCM281XX
>  obj-$(CONFIG_ARCH_BCM_281XX)	+= board_bcm281xx.o
>  
> diff --git a/arch/arm/mach-bcm/board_bcm_cygnus.c b/arch/arm/mach-bcm/board_bcm_cygnus.c
> new file mode 100644
> index 0000000..d67555a
> --- /dev/null
> +++ b/arch/arm/mach-bcm/board_bcm_cygnus.c
> @@ -0,0 +1,166 @@
> +/*
> + * Copyright 2014 Broadcom Corporation.  All rights reserved.
> + *
> + * Unless you and Broadcom execute a separate written software license
> + * agreement governing use of this software, this software is licensed to you
> + * under the terms of the GNU General Public License version 2, available at
> + * http://www.broadcom.com/licenses/GPLv2.php (the "GPL").

Why don't we point at the gnu.org copy as we do elsewhere?

> + */
> +
> +#include <linux/of_address.h>
> +#include <linux/of_platform.h>
> +#include <linux/clocksource.h>
> +#include <linux/clk-provider.h>
> +#include <linux/delay.h>
> +#include <asm/mach/arch.h>
> +#include <asm/mach/map.h>
> +#include <asm/proc-fns.h>
> +#include <asm/hardware/cache-l2x0.h>
> +
> +#define CRMU_MAIL_BOX1      0x03024028

Please don't hard code addresses in board files.

> +#define CRMU_SOFT_RESET_CMD 0xFFFFFFFF
> +
> +/* CRU_RESET register */
> +static void * __iomem crmu_mail_box1_reg;
> +
> +#ifdef CONFIG_NEON
> +
> +#define CRU_BASE                  0x1800e000

Another hard coded address that needs to go.

> +#define CRU_SIZE                  0x34
> +#define CRU_CONTROL_OFFSET        0x0
> +#define CRU_PWRDWN_EN_OFFSET      0x4
> +#define CRU_PWRDWN_STATUS_OFFSET  0x8
> +#define CRU_NEON0_HW_RESET  6
> +#define CRU_CLAMP_ON_NEON0  20
> +#define CRU_PWRONIN_NEON0   21
> +#define CRU_PWRONOUT_NEON0  21
> +#define CRU_PWROKIN_NEON0   22
> +#define CRU_PWROKOUT_NEON0  22
> +#define CRU_STATUS_DELAY_NS 500
> +#define CRU_MAX_RETRY_COUNT 10
> +#define CRU_RETRY_INTVL_US  1
> +
> +/* Power up the NEON/VFPv3 block. */
> +static void bcm_cygnus_powerup_neon(void)
> +{
> +	void * __iomem cru_base = ioremap_nocache(CRU_BASE, CRU_SIZE);

Why not plain ioremap?

> +	u32 reg, i;
> +
> +	BUG_ON(!cru_base);

This seems a little extreme. Can;t we continue without NEON?

> +
> +	/* De-assert the neon hardware block reset */
> +	reg = readl(cru_base + CRU_CONTROL_OFFSET);
> +	reg &= ~(1 << CRU_NEON0_HW_RESET);
> +	writel(reg, cru_base + CRU_CONTROL_OFFSET);
> +
> +	/* Assert the power ON register bit */
> +	reg = readl(cru_base + CRU_PWRDWN_EN_OFFSET);
> +	reg |= (1 << CRU_PWRONIN_NEON0);
> +	writel(reg, cru_base + CRU_PWRDWN_EN_OFFSET);
> +
> +	/*
> +	 * Wait up to 10 usec in 1 usec increments for the
> +	 * status register to acknowledge the power ON assert
> +	 */
> +	for (i = 0; i < CRU_MAX_RETRY_COUNT; i++) {
> +		reg = readl(cru_base + CRU_PWRDWN_STATUS_OFFSET);
> +		if (reg & CRU_PWRONOUT_NEON0)
> +			break;
> +
> +		udelay(CRU_RETRY_INTVL_US);
> +	}
> +
> +	if (i == CRU_MAX_RETRY_COUNT)
> +		panic("NEON power ON register not acknowledged\n");

We can't just disable NEON if we fail to enable the HW block?

[...]

> +static void __init bcm_cygnus_timer_init(void)
> +{
> +	/* Initialize all clocks declared in device tree */
> +	of_clk_init(NULL);
> +
> +	clocksource_of_init();
> +}

If you take a look at time_init in arch/arm/kernel/time.c you'll see
this is redundant.

Get rid of this.

> +
> +static void __init bcm_cygnus_init(void)
> +{
> +	of_platform_populate(NULL, of_default_bus_match_table, NULL, NULL);
> +
> +	l2x0_of_init(0, ~0UL);
> +
> +	crmu_mail_box1_reg = ioremap_nocache(CRMU_MAIL_BOX1, SZ_4);

Why not plain ioremap?

> +	BUG_ON(!crmu_mail_box1_reg);

We only use this for reboot later on, so do we need to blow up so
spectacularly in this case?

> +
> +#ifdef CONFIG_NEON
> +	bcm_cygnus_powerup_neon();
> +#endif
> +}
> +
> +/*
> + * Reset the system
> + */
> +void bcm_cygnus_restart(enum reboot_mode mode, const char *cmd)
> +{
> +	/* Send reset command to M0 via Mailbox. */
> +	writel(CRMU_SOFT_RESET_CMD, crmu_mail_box1_reg);
> +	iounmap(crmu_mail_box1_reg);
> +
> +	/* Wait for M0 to reset the chip. */
> +	while (1)
> +		cpu_do_idle();
> +}

This doesn't have to live in the machine descriptor. It could be a
separate driver.

Thanks,
Mark.

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

* Re: [PATCH 2/6] clk: Clock driver support for Broadcom Cygnus SoC
  2014-09-16 19:58   ` [PATCH 2/6] clk: Clock driver " Jonathan Richardson
@ 2014-09-17  0:47     ` Mark Rutland
  2014-09-18 23:43       ` Jonathan Richardson
  0 siblings, 1 reply; 92+ messages in thread
From: Mark Rutland @ 2014-09-17  0:47 UTC (permalink / raw)
  To: Jonathan Richardson
  Cc: Christian Daudt, Matt Porter, Russell King, Mike Turquette,
	Rob Herring, Pawel Moll, Ian Campbell, Kumar Gala, JD Zheng,
	linux-arm-kernel, bcm-kernel-feedback-list, linux-kernel,
	devicetree, Scott Branden, Ray Jui

On Tue, Sep 16, 2014 at 08:58:13PM +0100, Jonathan Richardson wrote:
> The iProc clock driver controls PLL's common across iProc chips. The

Nit: s/PLL's/PLLs/ (we aren't greengrocers [1]).

> cygnus driver controls cygnus specific features and variations.
> 
> Reviewed-by: Ray Jui <rjui@broadcom.com>
> Tested-by: Jonathan Richardson <jonathar@broadcom.com>
> Reviewed-by: JD (Jiandong) Zheng <jdzheng@broadcom.com>
> Signed-off-by: Jonathan Richardson <jonathar@broadcom.com>
> ---
>  drivers/clk/Makefile         |    1 +
>  drivers/clk/bcm/Makefile     |    2 +
>  drivers/clk/bcm/clk-cygnus.c | 1179 ++++++++++++++++++++++++++++++++++++++++++
>  drivers/clk/bcm/clk-iproc.c  |  446 ++++++++++++++++
>  4 files changed, 1628 insertions(+)
>  create mode 100644 drivers/clk/bcm/clk-cygnus.c
>  create mode 100644 drivers/clk/bcm/clk-iproc.c
 
[...]

> +/*
> + * Enable clocks controlled through the top clock gating control.
> + *
> + * @param state true = enable clock, false = disable clock
> + */
> +static void cygnus_clkgate_enable(void __iomem *clkgate_reg,
> +       enum cygnus_top_clk_gating_ctrl_offsets offset, bool state)
> +{
> +       u32 val = readl(clkgate_reg);
> +
> +       /* Enable or disable the clock. */

This function is misnamed if it does both, and 'state' is not a very
descriptive name.

> +       if (state)
> +               val |= 1 << offset;
> +       else
> +               val &= ~(1 << offset);
> +
> +       writel(val, clkgate_reg);
> +}
> +
> +/*
> + * Powers on/off the MIPI GENPLL using CRMU_PLL_AON_CTRL register.
> + *
> + * @param state true to power on PLL, false to power off
> + */
> +static void cygnus_mipi_genpll_poweron(void __iomem *pll_ctrl_reg,
> +       bool state)
> +{
> +       u32 val;
> +       u32 pll_ldo_on = ((1 << ASIU_MIPI_GENPLL_PWRON_SHIFT) |
> +               (1 << ASIU_MIPI_GENPLL_PWRON_PLL_SHIFT) |
> +               (1 << ASIU_MIPI_GENPLL_PWRON_BG_SHIFT)  |
> +               (1 << ASIU_MIPI_GENPLL_PWRON_LDO_SHIFT));
> +
> +       val = readl(pll_ctrl_reg);
> +
> +       /*
> +        * Set PLL on/off. Set input isolation mode to 1 when disabled, 0 when
> +        * enabled.
> +        */

As with cygnus_clkgate_enable, this function is misnamed and 'state' is
a confusing parameter name.

> +       if (state) {
> +               val |= pll_ldo_on;
> +               val &= ~(1 << ASIU_MIPI_GENPLL_ISO_IN_SHIFT);
> +       } else {
> +               val &= ~pll_ldo_on;
> +               val |= 1 << ASIU_MIPI_GENPLL_ISO_IN_SHIFT;
> +       }
> +
> +       writel(val, pll_ctrl_reg);
> +}
> +
> +/*
> + * Powers on/off the audio PLL using CRMU_PLL_AON_CTRL register.
> + *
> + * @param state true to power on PLL, false to power off
> + */
> +static void cygnus_audio_genpll_poweron(void __iomem *pll_ctrl_reg,
> +       bool state)
> +{
> +       u32 val;
> +       u32 pll_ldo_on = ((1 << ASIU_AUDIO_GENPLL_PWRON_PLL_SHIFT) |
> +               (1 << ASIU_AUDIO_GENPLL_PWRON_BG_SHIFT) |
> +               (1 << ASIU_AUDIO_GENPLL_PWRON_LDO_SHIFT));
> +
> +       val = readl(pll_ctrl_reg);
> +
> +       /*
> +        * Set PLL on/off. Set input isolation mode to 1 when disabled, 0 when
> +        * enabled.
> +        */

Misnamed function, confusing parameter name.

> +       if (state) {
> +               val |= pll_ldo_on;
> +               val &= ~(1 << ASIU_AUDIO_GENPLL_ISO_IN);
> +       } else {
> +               val &= ~pll_ldo_on;
> +               val |= 1 << ASIU_AUDIO_GENPLL_ISO_IN;
> +       }
> +
> +       writel(val, pll_ctrl_reg);
> +}

[...]

> +static __init struct clk *cygnus_clock_init(struct device_node *node,
> +       const struct clk_ops *ops)
> +{
> +       u32 channel = 0;
> +       struct clk *clk;
> +       struct cygnus_clk *cygnus_clk;
> +       const char *clk_name = node->name;
> +       const char *parent_name;
> +       struct clk_init_data init;
> +       int rc;
> +
> +       pr_debug("Clock name %s\n", node->name);
> +
> +       of_property_read_u32(node, "channel", &channel);
> +       cygnus_clk = kzalloc(sizeof(*cygnus_clk), GFP_KERNEL);
> +       if (WARN_ON(!cygnus_clk))
> +               return NULL;
> +
> +       cygnus_clk->state = CLK_DISABLED;
> +
> +       /* Read base address from device tree and map to virtual address. */
> +       cygnus_clk->regs_base = of_iomap(node, CYGNUS_CLK_BASE_REG);
> +       if (WARN_ON(!cygnus_clk->regs_base))
> +               goto err_alloc;
> +
> +       /* Read optional base addresses for PLL control and clock gating. */
> +       cygnus_clk->clock_gate_ctrl_reg = of_iomap(node,
> +               CYGNUS_CLK_GATE_CTRL_REG);
> +       cygnus_clk->pll_ctrl_reg = of_iomap(node, CYGNUS_PLL_CTRL_REG);
> +
> +       of_property_read_u32(node, "channel", &channel);

Why do we read this twice?

> +       cygnus_clk->chan = channel;
> +       of_property_read_string(node, "clock-output-names", &clk_name);

What happens if this is missing from the dt?

> +
> +       /*
> +        * Internal divider is optional and used for PLL derived clocks with
> +        * hardcoded dividers.
> +        */
> +       cygnus_clk->internal_div = CLK_RATE_NO_DIV;
> +       of_property_read_u32(node, "div", &cygnus_clk->internal_div);
> +
> +       init.name = clk_name;
> +       init.ops = ops;
> +       init.flags = CLK_GET_RATE_NOCACHE;
> +       parent_name = of_clk_get_parent_name(node, 0);
> +       init.parent_names = &parent_name;
> +       init.num_parents = 1;
> +
> +       cygnus_clk->hw.init = &init;
> +
> +       clk = clk_register(NULL, &cygnus_clk->hw);
> +       if (WARN_ON(IS_ERR(clk)))
> +               goto err_unmap;
> +
> +       rc = of_clk_add_provider(node, of_clk_src_simple_get, clk);
> +       if (WARN_ON(IS_ERR_VALUE(rc)))
> +               goto err_unregister;
> +
> +       rc = clk_register_clkdev(clk, clk_name, NULL);
> +       if (WARN_ON(IS_ERR_VALUE(rc)))
> +               goto err_provider;
> +
> +       return clk;
> +
> +err_provider:
> +       of_clk_del_provider(node);
> +
> +err_unregister:
> +       clk_unregister(clk);
> +
> +err_unmap:
> +       iounmap(cygnus_clk->regs_base);
> +       iounmap(cygnus_clk->clock_gate_ctrl_reg);
> +       iounmap(cygnus_clk->pll_ctrl_reg);
> +
> +err_alloc:
> +       kfree(cygnus_clk);
> +
> +       return NULL;
> +}

Thanks,
Mark.

[1] http://en.wikipedia.org/wiki/Apostrophe#Superfluous_apostrophes_.28.22greengrocers.27_apostrophes.22.29

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

* Re: [PATCH 0/6] Add initial support for Broadcom Cygnus SoC
  2014-09-16 19:58 ` [PATCH 0/6] Add initial support for Broadcom Cygnus SoC Jonathan Richardson
                     ` (5 preceding siblings ...)
  2014-09-16 19:58   ` [PATCH 6/6] MAINTAINERS: Entry for Cygnus/iproc arm architecture and clock drivers Jonathan Richardson
@ 2014-09-18 22:31   ` Hauke Mehrtens
  2014-09-18 22:39     ` Florian Fainelli
  6 siblings, 1 reply; 92+ messages in thread
From: Hauke Mehrtens @ 2014-09-18 22:31 UTC (permalink / raw)
  To: Jonathan Richardson, Christian Daudt, Matt Porter, Russell King,
	Mike Turquette, Rob Herring, Pawel Moll, Mark Rutland,
	Ian Campbell, Kumar Gala, JD Zheng
  Cc: devicetree, Scott Branden, Ray Jui, linux-kernel,
	bcm-kernel-feedback-list, linux-arm-kernel,
	Rafał Miłecki, Florian Fainelli

On 09/16/2014 09:58 PM, Jonathan Richardson wrote:
> Hi,
> 
> This patchset contains initial support for Broadcom's Cygnus SoC based on our
> iProc architecture. Initial support is minimal and includes just the mach
> platform code, clock driver, and a basic device tree configuration. Peripheral
> drivers will be submitted soon, as will device tree configurations for other
> Cygnus board variants.

This SoC looks similar to the BCM5301X (Northstar) SoCs even some cores
are at the same memory addresses. Does this SoC use an AXI bus with
Broadcom Plugins at address 0x18000000 ?

The BCM5301X (Northstar) SoCs also has an iProc Clock Control Unit and I
will try to use your driver for that SoC.

Is Broadcom Cygnus similar to BCM563XX or is it actually the same SoC?

Do you have some description of the hardware features of this SoC? Does
it have PCIe, or Ethernet?

Hauke

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

* Re: [PATCH 0/6] Add initial support for Broadcom Cygnus SoC
  2014-09-18 22:31   ` [PATCH 0/6] Add initial support for Broadcom Cygnus SoC Hauke Mehrtens
@ 2014-09-18 22:39     ` Florian Fainelli
  2014-09-18 22:54       ` Hauke Mehrtens
  0 siblings, 1 reply; 92+ messages in thread
From: Florian Fainelli @ 2014-09-18 22:39 UTC (permalink / raw)
  To: Hauke Mehrtens, Jonathan Richardson, Christian Daudt,
	Matt Porter, Russell King, Mike Turquette, Rob Herring,
	Pawel Moll, Mark Rutland, Ian Campbell, Kumar Gala, JD Zheng
  Cc: devicetree, Scott Branden, Ray Jui, Rafał Miłecki,
	linux-kernel, bcm-kernel-feedback-list, linux-arm-kernel

On 09/18/2014 03:31 PM, Hauke Mehrtens wrote:
> On 09/16/2014 09:58 PM, Jonathan Richardson wrote:
>> Hi,
>>
>> This patchset contains initial support for Broadcom's Cygnus SoC based on our
>> iProc architecture. Initial support is minimal and includes just the mach
>> platform code, clock driver, and a basic device tree configuration. Peripheral
>> drivers will be submitted soon, as will device tree configurations for other
>> Cygnus board variants.
> 
> This SoC looks similar to the BCM5301X (Northstar) SoCs even some cores
> are at the same memory addresses. Does this SoC use an AXI bus with
> Broadcom Plugins at address 0x18000000 ?
> 
> The BCM5301X (Northstar) SoCs also has an iProc Clock Control Unit and I
> will try to use your driver for that SoC.
> 
> Is Broadcom Cygnus similar to BCM563XX or is it actually the same SoC?

According to this link:
http://lists.denx.de/pipermail/u-boot/2014-August/186086.html

these SoCs, in particular BCM58622 would belong to the StrataGX network
processors:
http://www.broadcom.com/products/Processors/Home-and-Small-Business/BCM5862X-Series.

> 
> Do you have some description of the hardware features of this SoC? Does
> it have PCIe, or Ethernet?

>From the link above, it has Ethernet for sure, and certainly PCIe since
the Wi-Fi chips mentioned in the link above are PCIe chips.

It would be really good if all the work you and Rafal did was usable for
the Cygnus SoCs.
--
Florian

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

* Re: [PATCH 0/6] Add initial support for Broadcom Cygnus SoC
  2014-09-18 22:39     ` Florian Fainelli
@ 2014-09-18 22:54       ` Hauke Mehrtens
  2014-09-19  0:58         ` Scott Branden
  0 siblings, 1 reply; 92+ messages in thread
From: Hauke Mehrtens @ 2014-09-18 22:54 UTC (permalink / raw)
  To: Florian Fainelli, Jonathan Richardson, Christian Daudt,
	Matt Porter, Russell King, Mike Turquette, Rob Herring,
	Pawel Moll, Mark Rutland, Ian Campbell, Kumar Gala, JD Zheng
  Cc: devicetree, Scott Branden, Ray Jui, Rafał Miłecki,
	linux-kernel, bcm-kernel-feedback-list, linux-arm-kernel

On 09/19/2014 12:39 AM, Florian Fainelli wrote:
> On 09/18/2014 03:31 PM, Hauke Mehrtens wrote:
>> On 09/16/2014 09:58 PM, Jonathan Richardson wrote:
>>> Hi,
>>>
>>> This patchset contains initial support for Broadcom's Cygnus SoC based on our
>>> iProc architecture. Initial support is minimal and includes just the mach
>>> platform code, clock driver, and a basic device tree configuration. Peripheral
>>> drivers will be submitted soon, as will device tree configurations for other
>>> Cygnus board variants.
>>
>> This SoC looks similar to the BCM5301X (Northstar) SoCs even some cores
>> are at the same memory addresses. Does this SoC use an AXI bus with
>> Broadcom Plugins at address 0x18000000 ?
>>
>> The BCM5301X (Northstar) SoCs also has an iProc Clock Control Unit and I
>> will try to use your driver for that SoC.
>>
>> Is Broadcom Cygnus similar to BCM563XX or is it actually the same SoC?
> 
> According to this link:
> http://lists.denx.de/pipermail/u-boot/2014-August/186086.html
> 
> these SoCs, in particular BCM58622 would belong to the StrataGX network
> processors:
> http://www.broadcom.com/products/Processors/Home-and-Small-Business/BCM5862X-Series.

Broadcom claims that this SoC is pin and software compatible to BCM5301X:
> Pin compatible and software compatible products with previous
> generation BCM5301x products enable single design with easy
> upgradeable path

>> Do you have some description of the hardware features of this SoC? Does
>> it have PCIe, or Ethernet?
> 
> From the link above, it has Ethernet for sure, and certainly PCIe since
> the Wi-Fi chips mentioned in the link above are PCIe chips.
> 
> It would be really good if all the work you and Rafal did was usable for
> the Cygnus SoCs.

I also hope you can use much of the code and improve it. ;-)

Hauke


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

* Re: [PATCH 1/6] ARM: cygnus: Initial support for Broadcom Cygnus SoC
  2014-09-17  0:00     ` Mark Rutland
@ 2014-09-18 23:33       ` Jonathan Richardson
  0 siblings, 0 replies; 92+ messages in thread
From: Jonathan Richardson @ 2014-09-18 23:33 UTC (permalink / raw)
  To: Mark Rutland
  Cc: Christian Daudt, Matt Porter, Russell King, Mike Turquette,
	Rob Herring, Pawel Moll, Ian Campbell, Kumar Gala, JD Zheng,
	linux-arm-kernel, bcm-kernel-feedback-list, linux-kernel,
	devicetree, Scott Branden, Ray Jui

Hi Mark,

Thanks for the feedback.

On 14-09-16 05:00 PM, Mark Rutland wrote:
> On Tue, Sep 16, 2014 at 08:58:12PM +0100, Jonathan Richardson wrote:
>> Adds initial support for the Cygnus SoC based on Broadcom’s iProc series.
>>
>> Reviewed-by: Ray Jui <rjui@broadcom.com>
>> Reviewed-by: Desmond Liu <desmondl@broadcom.com>
>> Reviewed-by: JD (Jiandong) Zheng <jdzheng@broadcom.com>
>> Tested-by: Jonathan Richardson <jonathar@broadcom.com>
>> Signed-off-by: Jonathan Richardson <jonathar@broadcom.com>
>> ---
>>  arch/arm/mach-bcm/Kconfig            |   34 +++++++
>>  arch/arm/mach-bcm/Makefile           |    3 +
>>  arch/arm/mach-bcm/board_bcm_cygnus.c |  166 ++++++++++++++++++++++++++++++++++
> 
> Is Cygnus an SoC or a board?

SoC. I will rename it to bcm_cygnus.c

> 
>>  3 files changed, 203 insertions(+)
>>  create mode 100644 arch/arm/mach-bcm/board_bcm_cygnus.c
>>
>> diff --git a/arch/arm/mach-bcm/Kconfig b/arch/arm/mach-bcm/Kconfig
>> index fc93800..58e0f20 100644
>> --- a/arch/arm/mach-bcm/Kconfig
>> +++ b/arch/arm/mach-bcm/Kconfig
>> @@ -5,6 +5,40 @@ menuconfig ARCH_BCM
>>  
>>  if ARCH_BCM
>>  
>> +config ARCH_BCM_IPROC
>> +	bool "Broadcom ARMv7 iProc boards" if ARCH_MULTI_V7
>> +	select ARM_GIC
>> +	select CACHE_L2X0
>> +	select HAVE_ARM_SCU if SMP
> 
> I didn't spot any SMP code in this series.

It's single core. Will fix.
> 
>> +	select HAVE_ARM_TWD if LOCAL_TIMERS
>> +	select HAVE_CLK
>> +	select CLKSRC_OF
>> +	select CLKSRC_MMIO
>> +	select LOCAL_TIMERS if SMP
>> +	select GENERIC_CLOCKEVENTS_BUILD
> 
> You don't need to select this.

Will fix.
> 
>> +	select GENERIC_CLOCKEVENTS
>> +	select ARM_GLOBAL_TIMER
>> +	select ARCH_REQUIRE_GPIOLIB
>> +	select ARM_AMBA
>> +	select PINCTRL
>> +	select DEBUG_UART_8250
>> +	help
>> +	  This enables support for systems based on Broadcom IPROC architected SoCs.
>> +	  The IPROC complex contains one or more ARM CPUs along with common
>> +	  core periperals. Application specific SoCs are created by adding a
>> +	  uArchitecture containing peripherals outside of the IPROC complex.
>> +	  Currently supported SoCs are Cygnus.
>> +
>> +menu "iProc SoC based Machine types"
>> +	depends on ARCH_BCM_IPROC
>> +
>> +	config ARCH_BCM_CYGNUS
>> +		bool "Support Broadcom Cygnus board"
>> +		select USB_ARCH_HAS_EHCI if USB_SUPPORT
>> +		help
>> +		  Support for Broadcom Cygnus SoC.
>> +endmenu
>> +
>>  config ARCH_BCM_MOBILE
>>  	bool "Broadcom Mobile SoC Support" if ARCH_MULTI_V7
>>  	select ARCH_REQUIRE_GPIOLIB
>> diff --git a/arch/arm/mach-bcm/Makefile b/arch/arm/mach-bcm/Makefile
>> index b19a396..dd14a10 100644
>> --- a/arch/arm/mach-bcm/Makefile
>> +++ b/arch/arm/mach-bcm/Makefile
>> @@ -10,6 +10,9 @@
>>  # of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
>>  # GNU General Public License for more details.
>>  
>> +# Cygnus
>> +obj-$(CONFIG_ARCH_BCM_CYGNUS) +=  board_bcm_cygnus.o
>> +
>>  # BCM281XX
>>  obj-$(CONFIG_ARCH_BCM_281XX)	+= board_bcm281xx.o
>>  
>> diff --git a/arch/arm/mach-bcm/board_bcm_cygnus.c b/arch/arm/mach-bcm/board_bcm_cygnus.c
>> new file mode 100644
>> index 0000000..d67555a
>> --- /dev/null
>> +++ b/arch/arm/mach-bcm/board_bcm_cygnus.c
>> @@ -0,0 +1,166 @@
>> +/*
>> + * Copyright 2014 Broadcom Corporation.  All rights reserved.
>> + *
>> + * Unless you and Broadcom execute a separate written software license
>> + * agreement governing use of this software, this software is licensed to you
>> + * under the terms of the GNU General Public License version 2, available at
>> + * http://www.broadcom.com/licenses/GPLv2.php (the "GPL").
> 
> Why don't we point at the gnu.org copy as we do elsewhere?
>

I am enquiring.

>> + */
>> +
>> +#include <linux/of_address.h>
>> +#include <linux/of_platform.h>
>> +#include <linux/clocksource.h>
>> +#include <linux/clk-provider.h>
>> +#include <linux/delay.h>
>> +#include <asm/mach/arch.h>
>> +#include <asm/mach/map.h>
>> +#include <asm/proc-fns.h>
>> +#include <asm/hardware/cache-l2x0.h>
>> +
>> +#define CRMU_MAIL_BOX1      0x03024028
> 
> Please don't hard code addresses in board files.

Would a separate header file be sufficient? I notice this approach was
taken in vexpress A9x4 (out of date?). I couldn't find a home for them
in dt and I don't think anyone would want to see them there. They
shouldn't ever change.

We have a couple of more addresses that will be added in future
revisions of this file for DMA and LCD (for reset/power up procedures),
as those drivers are added.

> 
>> +#define CRMU_SOFT_RESET_CMD 0xFFFFFFFF
>> +
>> +/* CRU_RESET register */
>> +static void * __iomem crmu_mail_box1_reg;
>> +
>> +#ifdef CONFIG_NEON
>> +
>> +#define CRU_BASE                  0x1800e000
> 
> Another hard coded address that needs to go.
> 
>> +#define CRU_SIZE                  0x34
>> +#define CRU_CONTROL_OFFSET        0x0
>> +#define CRU_PWRDWN_EN_OFFSET      0x4
>> +#define CRU_PWRDWN_STATUS_OFFSET  0x8
>> +#define CRU_NEON0_HW_RESET  6
>> +#define CRU_CLAMP_ON_NEON0  20
>> +#define CRU_PWRONIN_NEON0   21
>> +#define CRU_PWRONOUT_NEON0  21
>> +#define CRU_PWROKIN_NEON0   22
>> +#define CRU_PWROKOUT_NEON0  22
>> +#define CRU_STATUS_DELAY_NS 500
>> +#define CRU_MAX_RETRY_COUNT 10
>> +#define CRU_RETRY_INTVL_US  1
>> +
>> +/* Power up the NEON/VFPv3 block. */
>> +static void bcm_cygnus_powerup_neon(void)
>> +{
>> +	void * __iomem cru_base = ioremap_nocache(CRU_BASE, CRU_SIZE);
> 
> Why not plain ioremap?
> 
>> +	u32 reg, i;
>> +
>> +	BUG_ON(!cru_base);
> 
> This seems a little extreme. Can;t we continue without NEON?

We can yes. The reason for this was to prevent difficult troubleshooting
if it ever failed. But a WARN_ON would probably be sufficient.

> 
>> +
>> +	/* De-assert the neon hardware block reset */
>> +	reg = readl(cru_base + CRU_CONTROL_OFFSET);
>> +	reg &= ~(1 << CRU_NEON0_HW_RESET);
>> +	writel(reg, cru_base + CRU_CONTROL_OFFSET);
>> +
>> +	/* Assert the power ON register bit */
>> +	reg = readl(cru_base + CRU_PWRDWN_EN_OFFSET);
>> +	reg |= (1 << CRU_PWRONIN_NEON0);
>> +	writel(reg, cru_base + CRU_PWRDWN_EN_OFFSET);
>> +
>> +	/*
>> +	 * Wait up to 10 usec in 1 usec increments for the
>> +	 * status register to acknowledge the power ON assert
>> +	 */
>> +	for (i = 0; i < CRU_MAX_RETRY_COUNT; i++) {
>> +		reg = readl(cru_base + CRU_PWRDWN_STATUS_OFFSET);
>> +		if (reg & CRU_PWRONOUT_NEON0)
>> +			break;
>> +
>> +		udelay(CRU_RETRY_INTVL_US);
>> +	}
>> +
>> +	if (i == CRU_MAX_RETRY_COUNT)
>> +		panic("NEON power ON register not acknowledged\n");
> 
> We can't just disable NEON if we fail to enable the HW block?
> 
> [...]
> 
>> +static void __init bcm_cygnus_timer_init(void)
>> +{
>> +	/* Initialize all clocks declared in device tree */
>> +	of_clk_init(NULL);
>> +
>> +	clocksource_of_init();
>> +}
> 
> If you take a look at time_init in arch/arm/kernel/time.c you'll see
> this is redundant.

Will fix.

> 
> Get rid of this.
> 
>> +
>> +static void __init bcm_cygnus_init(void)
>> +{
>> +	of_platform_populate(NULL, of_default_bus_match_table, NULL, NULL);
>> +
>> +	l2x0_of_init(0, ~0UL);
>> +
>> +	crmu_mail_box1_reg = ioremap_nocache(CRMU_MAIL_BOX1, SZ_4);
> 
> Why not plain ioremap?

I will change them to ioremap.

> 
>> +	BUG_ON(!crmu_mail_box1_reg);
> 
> We only use this for reboot later on, so do we need to blow up so
> spectacularly in this case?

Will fix.

> 
>> +
>> +#ifdef CONFIG_NEON
>> +	bcm_cygnus_powerup_neon();
>> +#endif
>> +}
>> +
>> +/*
>> + * Reset the system
>> + */
>> +void bcm_cygnus_restart(enum reboot_mode mode, const char *cmd)
>> +{
>> +	/* Send reset command to M0 via Mailbox. */
>> +	writel(CRMU_SOFT_RESET_CMD, crmu_mail_box1_reg);
>> +	iounmap(crmu_mail_box1_reg);
>> +
>> +	/* Wait for M0 to reset the chip. */
>> +	while (1)
>> +		cpu_do_idle();
>> +}
> 
> This doesn't have to live in the machine descriptor. It could be a
> separate driver.

I'm not sure if a separate driver is the way we want to go with this
right now. If we had more of this M0 communication then I would agree,
and we may in the future. But if we don't then there would just be a
reset handler in the driver. If more interaction and a driver is
required we would move this to a driver.

Was your suggestion more related to the hard coded addresses in this
file or the mysterious nature of the reset procedure?

> 
> Thanks,
> Mark.
> 

Thanks.
Jon

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

* Re: [PATCH 2/6] clk: Clock driver support for Broadcom Cygnus SoC
  2014-09-17  0:47     ` Mark Rutland
@ 2014-09-18 23:43       ` Jonathan Richardson
  0 siblings, 0 replies; 92+ messages in thread
From: Jonathan Richardson @ 2014-09-18 23:43 UTC (permalink / raw)
  To: Mark Rutland
  Cc: Christian Daudt, Matt Porter, Russell King, Mike Turquette,
	Rob Herring, Pawel Moll, Ian Campbell, Kumar Gala, JD Zheng,
	linux-arm-kernel, bcm-kernel-feedback-list, linux-kernel,
	devicetree, Scott Branden, Ray Jui

On 14-09-16 05:47 PM, Mark Rutland wrote:
> On Tue, Sep 16, 2014 at 08:58:13PM +0100, Jonathan Richardson wrote:
>> The iProc clock driver controls PLL's common across iProc chips. The
> 
> Nit: s/PLL's/PLLs/ (we aren't greengrocers [1]).

Will fix.

> 
>> cygnus driver controls cygnus specific features and variations.
>>
>> Reviewed-by: Ray Jui <rjui@broadcom.com>
>> Tested-by: Jonathan Richardson <jonathar@broadcom.com>
>> Reviewed-by: JD (Jiandong) Zheng <jdzheng@broadcom.com>
>> Signed-off-by: Jonathan Richardson <jonathar@broadcom.com>
>> ---
>>  drivers/clk/Makefile         |    1 +
>>  drivers/clk/bcm/Makefile     |    2 +
>>  drivers/clk/bcm/clk-cygnus.c | 1179 ++++++++++++++++++++++++++++++++++++++++++
>>  drivers/clk/bcm/clk-iproc.c  |  446 ++++++++++++++++
>>  4 files changed, 1628 insertions(+)
>>  create mode 100644 drivers/clk/bcm/clk-cygnus.c
>>  create mode 100644 drivers/clk/bcm/clk-iproc.c
>  
> [...]
> 
>> +/*
>> + * Enable clocks controlled through the top clock gating control.
>> + *
>> + * @param state true = enable clock, false = disable clock
>> + */
>> +static void cygnus_clkgate_enable(void __iomem *clkgate_reg,
>> +       enum cygnus_top_clk_gating_ctrl_offsets offset, bool state)
>> +{
>> +       u32 val = readl(clkgate_reg);
>> +
>> +       /* Enable or disable the clock. */
> 
> This function is misnamed if it does both, and 'state' is not a very
> descriptive name.

Will fix.

> 
>> +       if (state)
>> +               val |= 1 << offset;
>> +       else
>> +               val &= ~(1 << offset);
>> +
>> +       writel(val, clkgate_reg);
>> +}
>> +
>> +/*
>> + * Powers on/off the MIPI GENPLL using CRMU_PLL_AON_CTRL register.
>> + *
>> + * @param state true to power on PLL, false to power off
>> + */
>> +static void cygnus_mipi_genpll_poweron(void __iomem *pll_ctrl_reg,
>> +       bool state)
>> +{
>> +       u32 val;
>> +       u32 pll_ldo_on = ((1 << ASIU_MIPI_GENPLL_PWRON_SHIFT) |
>> +               (1 << ASIU_MIPI_GENPLL_PWRON_PLL_SHIFT) |
>> +               (1 << ASIU_MIPI_GENPLL_PWRON_BG_SHIFT)  |
>> +               (1 << ASIU_MIPI_GENPLL_PWRON_LDO_SHIFT));
>> +
>> +       val = readl(pll_ctrl_reg);
>> +
>> +       /*
>> +        * Set PLL on/off. Set input isolation mode to 1 when disabled, 0 when
>> +        * enabled.
>> +        */
> 
> As with cygnus_clkgate_enable, this function is misnamed and 'state' is
> a confusing parameter name.

Will fix.

> 
>> +       if (state) {
>> +               val |= pll_ldo_on;
>> +               val &= ~(1 << ASIU_MIPI_GENPLL_ISO_IN_SHIFT);
>> +       } else {
>> +               val &= ~pll_ldo_on;
>> +               val |= 1 << ASIU_MIPI_GENPLL_ISO_IN_SHIFT;
>> +       }
>> +
>> +       writel(val, pll_ctrl_reg);
>> +}
>> +
>> +/*
>> + * Powers on/off the audio PLL using CRMU_PLL_AON_CTRL register.
>> + *
>> + * @param state true to power on PLL, false to power off
>> + */
>> +static void cygnus_audio_genpll_poweron(void __iomem *pll_ctrl_reg,
>> +       bool state)
>> +{
>> +       u32 val;
>> +       u32 pll_ldo_on = ((1 << ASIU_AUDIO_GENPLL_PWRON_PLL_SHIFT) |
>> +               (1 << ASIU_AUDIO_GENPLL_PWRON_BG_SHIFT) |
>> +               (1 << ASIU_AUDIO_GENPLL_PWRON_LDO_SHIFT));
>> +
>> +       val = readl(pll_ctrl_reg);
>> +
>> +       /*
>> +        * Set PLL on/off. Set input isolation mode to 1 when disabled, 0 when
>> +        * enabled.
>> +        */
> 
> Misnamed function, confusing parameter name.

Will fix.

> 
>> +       if (state) {
>> +               val |= pll_ldo_on;
>> +               val &= ~(1 << ASIU_AUDIO_GENPLL_ISO_IN);
>> +       } else {
>> +               val &= ~pll_ldo_on;
>> +               val |= 1 << ASIU_AUDIO_GENPLL_ISO_IN;
>> +       }
>> +
>> +       writel(val, pll_ctrl_reg);
>> +}
> 
> [...]
> 
>> +static __init struct clk *cygnus_clock_init(struct device_node *node,
>> +       const struct clk_ops *ops)
>> +{
>> +       u32 channel = 0;
>> +       struct clk *clk;
>> +       struct cygnus_clk *cygnus_clk;
>> +       const char *clk_name = node->name;
>> +       const char *parent_name;
>> +       struct clk_init_data init;
>> +       int rc;
>> +
>> +       pr_debug("Clock name %s\n", node->name);
>> +
>> +       of_property_read_u32(node, "channel", &channel);
>> +       cygnus_clk = kzalloc(sizeof(*cygnus_clk), GFP_KERNEL);
>> +       if (WARN_ON(!cygnus_clk))
>> +               return NULL;
>> +
>> +       cygnus_clk->state = CLK_DISABLED;
>> +
>> +       /* Read base address from device tree and map to virtual address. */
>> +       cygnus_clk->regs_base = of_iomap(node, CYGNUS_CLK_BASE_REG);
>> +       if (WARN_ON(!cygnus_clk->regs_base))
>> +               goto err_alloc;
>> +
>> +       /* Read optional base addresses for PLL control and clock gating. */
>> +       cygnus_clk->clock_gate_ctrl_reg = of_iomap(node,
>> +               CYGNUS_CLK_GATE_CTRL_REG);
>> +       cygnus_clk->pll_ctrl_reg = of_iomap(node, CYGNUS_PLL_CTRL_REG);
>> +
>> +       of_property_read_u32(node, "channel", &channel);
> 
> Why do we read this twice?

Missed that one. Will fix.

> 
>> +       cygnus_clk->chan = channel;
>> +       of_property_read_string(node, "clock-output-names", &clk_name);
> 
> What happens if this is missing from the dt?

It will (and does) fail and uses the name of the DT node instead. Please
see default value at beginning of function:

const char *clk_name = node->name;

> 
>> +
>> +       /*
>> +        * Internal divider is optional and used for PLL derived clocks with
>> +        * hardcoded dividers.
>> +        */
>> +       cygnus_clk->internal_div = CLK_RATE_NO_DIV;
>> +       of_property_read_u32(node, "div", &cygnus_clk->internal_div);
>> +
>> +       init.name = clk_name;
>> +       init.ops = ops;
>> +       init.flags = CLK_GET_RATE_NOCACHE;
>> +       parent_name = of_clk_get_parent_name(node, 0);
>> +       init.parent_names = &parent_name;
>> +       init.num_parents = 1;
>> +
>> +       cygnus_clk->hw.init = &init;
>> +
>> +       clk = clk_register(NULL, &cygnus_clk->hw);
>> +       if (WARN_ON(IS_ERR(clk)))
>> +               goto err_unmap;
>> +
>> +       rc = of_clk_add_provider(node, of_clk_src_simple_get, clk);
>> +       if (WARN_ON(IS_ERR_VALUE(rc)))
>> +               goto err_unregister;
>> +
>> +       rc = clk_register_clkdev(clk, clk_name, NULL);
>> +       if (WARN_ON(IS_ERR_VALUE(rc)))
>> +               goto err_provider;
>> +
>> +       return clk;
>> +
>> +err_provider:
>> +       of_clk_del_provider(node);
>> +
>> +err_unregister:
>> +       clk_unregister(clk);
>> +
>> +err_unmap:
>> +       iounmap(cygnus_clk->regs_base);
>> +       iounmap(cygnus_clk->clock_gate_ctrl_reg);
>> +       iounmap(cygnus_clk->pll_ctrl_reg);
>> +
>> +err_alloc:
>> +       kfree(cygnus_clk);
>> +
>> +       return NULL;
>> +}
> 
> Thanks,
> Mark.
> 
> [1] http://en.wikipedia.org/wiki/Apostrophe#Superfluous_apostrophes_.28.22greengrocers.27_apostrophes.22.29
> --
> To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
> Please read the FAQ at  http://www.tux.org/lkml/
> 

Thanks for the feedback.

Jon


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

* Re: [PATCH 0/6] Add initial support for Broadcom Cygnus SoC
  2014-09-18 22:54       ` Hauke Mehrtens
@ 2014-09-19  0:58         ` Scott Branden
  0 siblings, 0 replies; 92+ messages in thread
From: Scott Branden @ 2014-09-19  0:58 UTC (permalink / raw)
  To: Hauke Mehrtens, Florian Fainelli, Jonathan Richardson,
	Christian Daudt, Matt Porter, Russell King, Mike Turquette,
	Rob Herring, Pawel Moll, Mark Rutland, Ian Campbell, Kumar Gala,
	JD Zheng
  Cc: devicetree, Ray Jui, Rafał Miłecki, linux-kernel,
	bcm-kernel-feedback-list, linux-arm-kernel

On 14-09-18 03:54 PM, Hauke Mehrtens wrote:
> On 09/19/2014 12:39 AM, Florian Fainelli wrote:
>> On 09/18/2014 03:31 PM, Hauke Mehrtens wrote:
>>> On 09/16/2014 09:58 PM, Jonathan Richardson wrote:
>>>> Hi,
>>>>
>>>> This patchset contains initial support for Broadcom's Cygnus SoC based on our
>>>> iProc architecture. Initial support is minimal and includes just the mach
>>>> platform code, clock driver, and a basic device tree configuration. Peripheral
>>>> drivers will be submitted soon, as will device tree configurations for other
>>>> Cygnus board variants.
>>>
>>> This SoC looks similar to the BCM5301X (Northstar) SoCs even some cores
>>> are at the same memory addresses. Does this SoC use an AXI bus with
>>> Broadcom Plugins at address 0x18000000 ?
>>>
>>> The BCM5301X (Northstar) SoCs also has an iProc Clock Control Unit and I
>>> will try to use your driver for that SoC.
>>>
>>> Is Broadcom Cygnus similar to BCM563XX or is it actually the same SoC?
Cygnus is a next generation product with similarities to other Broadcom 
SoC's.  It takes technology from other parts for sure.  Our first step 
is to upstream the core IPROC code and Cygnus code.  From there we will 
upstream individual drivers which are reusable on some other Broadcom 
chips (or will need minor additions/quirks added as identified).  There 
are also other IPROC-based Broadcom chips that can also be upstreamed 
more easily with this patchset going forward.

I know the BCM5301X iProc Clock Control Unit is an older.  I think you 
may run into some difficulties running this code as is.  But hopefully 
we can build up more support for other chips from this initial 
submission for Cygnus support.
>>
>> According to this link:
>> http://lists.denx.de/pipermail/u-boot/2014-August/186086.html
>>
>> these SoCs, in particular BCM58622 would belong to the StrataGX network
>> processors:
>> http://www.broadcom.com/products/Processors/Home-and-Small-Business/BCM5862X-Series.
>
> Broadcom claims that this SoC is pin and software compatible to BCM5301X:
>> Pin compatible and software compatible products with previous
>> generation BCM5301x products enable single design with easy
>> upgradeable path
>
>>> Do you have some description of the hardware features of this SoC? Does
>>> it have PCIe, or Ethernet?
Yes, Some variants of Cygnus do have PCIe or Ethernet.  Drivers to be 
upstreamed once cleaned up fully.  The drivers will be built into our 
bcm_cygnus_defconfig and then enabled in device tree.
>>
>>  From the link above, it has Ethernet for sure, and certainly PCIe since
>> the Wi-Fi chips mentioned in the link above are PCIe chips.
>>
>> It would be really good if all the work you and Rafal did was usable for
>> the Cygnus SoCs.
>
> I also hope you can use much of the code and improve it. ;-)
>
> Hauke

>


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

* [PATCH v2 0/6] Add initial support for Broadcom Cygnus SoC
       [not found] <Jonathan Richardson <jonathar@broadcom.com>
  2014-09-16 19:58 ` [PATCH 0/6] Add initial support for Broadcom Cygnus SoC Jonathan Richardson
@ 2014-09-23 21:17 ` Jonathan Richardson
  2014-09-23 21:17   ` [PATCH v2 1/6] ARM: cygnus: Initial " Jonathan Richardson
                     ` (6 more replies)
  2014-12-11  1:07 ` [PATCH v2 1/2] pwm: kona: Fix incorrect enable, config, and disable procedures Jonathan Richardson
                   ` (11 subsequent siblings)
  13 siblings, 7 replies; 92+ messages in thread
From: Jonathan Richardson @ 2014-09-23 21:17 UTC (permalink / raw)
  To: Christian Daudt, Matt Porter, Russell King, Mike Turquette,
	Rob Herring, Pawel Moll, Mark Rutland, Ian Campbell, Kumar Gala,
	JD Zheng
  Cc: linux-arm-kernel, bcm-kernel-feedback-list, linux-kernel,
	devicetree, Scott Branden, Ray Jui, Jonathan Richardson

Hi,

This patchset contains initial support for Broadcom's Cygnus SoC based on our
iProc architecture. Initial support is minimal and includes just the mach
platform code, clock driver, and a basic device tree configuration. Peripheral
drivers will be submitted soon, as will device tree configurations for other
Cygnus board variants.

Changes from v1:
 - Address code review comments as per previous responses.
 - Copyright headers updated to remove Broadcom URL.
 - mach platform code still contains hard coded adresses. These address are
   the same for all Cygnus variants. Could you please provide guidance on where
   they should go if you would still like them changed.
   
Thanks,
Jon

Jonathan Richardson (6):
  ARM: cygnus: Initial support for Broadcom Cygnus SoC
  clk: Clock driver support for Broadcom Cygnus SoC
  dt-bindings: Document Broadcom Cygnus SoC and clock driver
  ARM: dts: Enable Broadcom Cygnus SoC
  ARM: cygnus defconfig : Initial defconfig for Broadcom Cygnus SoC
  MAINTAINERS: Entry for Cygnus/iproc arm architecture and clock
    drivers

 Documentation/devicetree/bindings/arm/cygnus.txt   |   12 +
 .../devicetree/bindings/clock/clk-cygnus.txt       |  121 ++
 .../devicetree/bindings/clock/clk-iproc.txt        |   48 +
 MAINTAINERS                                        |   21 +
 arch/arm/boot/dts/Makefile                         |    1 +
 arch/arm/boot/dts/bcm-cygnus.dtsi                  |  349 ++++++
 arch/arm/boot/dts/bcm911360_entphn.dts             |   22 +
 arch/arm/configs/bcm_cygnus_defconfig              |  223 ++++
 arch/arm/mach-bcm/Kconfig                          |   31 +
 arch/arm/mach-bcm/Makefile                         |    3 +
 arch/arm/mach-bcm/bcm_cygnus.c                     |  166 +++
 drivers/clk/Makefile                               |    1 +
 drivers/clk/bcm/Makefile                           |    2 +
 drivers/clk/bcm/clk-cygnus.c                       | 1186 ++++++++++++++++++++
 drivers/clk/bcm/clk-iproc.c                        |  451 ++++++++
 15 files changed, 2637 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/arm/cygnus.txt
 create mode 100644 Documentation/devicetree/bindings/clock/clk-cygnus.txt
 create mode 100644 Documentation/devicetree/bindings/clock/clk-iproc.txt
 create mode 100644 arch/arm/boot/dts/bcm-cygnus.dtsi
 create mode 100644 arch/arm/boot/dts/bcm911360_entphn.dts
 create mode 100644 arch/arm/configs/bcm_cygnus_defconfig
 create mode 100644 arch/arm/mach-bcm/bcm_cygnus.c
 create mode 100644 drivers/clk/bcm/clk-cygnus.c
 create mode 100644 drivers/clk/bcm/clk-iproc.c

-- 
1.7.9.5


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

* [PATCH v2 1/6] ARM: cygnus: Initial support for Broadcom Cygnus SoC
  2014-09-23 21:17 ` [PATCH v2 " Jonathan Richardson
@ 2014-09-23 21:17   ` Jonathan Richardson
  2014-09-23 21:17   ` [PATCH v2 2/6] clk: Clock driver " Jonathan Richardson
                     ` (5 subsequent siblings)
  6 siblings, 0 replies; 92+ messages in thread
From: Jonathan Richardson @ 2014-09-23 21:17 UTC (permalink / raw)
  To: Christian Daudt, Matt Porter, Russell King, Mike Turquette,
	Rob Herring, Pawel Moll, Mark Rutland, Ian Campbell, Kumar Gala,
	JD Zheng
  Cc: linux-arm-kernel, bcm-kernel-feedback-list, linux-kernel,
	devicetree, Scott Branden, Ray Jui, Jonathan Richardson

Adds initial support for the Cygnus SoC based on Broadcom’s iProc series.

Reviewed-by: Ray Jui <rjui@broadcom.com>
Reviewed-by: Desmond Liu <desmondl@broadcom.com>
Reviewed-by: JD (Jiandong) Zheng <jdzheng@broadcom.com>
Tested-by: Jonathan Richardson <jonathar@broadcom.com>
Signed-off-by: Jonathan Richardson <jonathar@broadcom.com>
---
 arch/arm/mach-bcm/Kconfig      |   31 ++++++++
 arch/arm/mach-bcm/Makefile     |    3 +
 arch/arm/mach-bcm/bcm_cygnus.c |  166 ++++++++++++++++++++++++++++++++++++++++
 3 files changed, 200 insertions(+)
 create mode 100644 arch/arm/mach-bcm/bcm_cygnus.c

diff --git a/arch/arm/mach-bcm/Kconfig b/arch/arm/mach-bcm/Kconfig
index fc93800..2dd3f78 100644
--- a/arch/arm/mach-bcm/Kconfig
+++ b/arch/arm/mach-bcm/Kconfig
@@ -5,6 +5,37 @@ menuconfig ARCH_BCM
 
 if ARCH_BCM
 
+config ARCH_BCM_IPROC
+	bool "Broadcom ARMv7 iProc boards" if ARCH_MULTI_V7
+	select ARM_GIC
+	select CACHE_L2X0
+	select HAVE_ARM_TWD if LOCAL_TIMERS
+	select HAVE_CLK
+	select CLKSRC_OF
+	select CLKSRC_MMIO
+	select GENERIC_CLOCKEVENTS
+	select ARM_GLOBAL_TIMER
+	select ARCH_REQUIRE_GPIOLIB
+	select ARM_AMBA
+	select PINCTRL
+	select DEBUG_UART_8250
+	help
+	  This enables support for systems based on Broadcom IPROC architected SoCs.
+	  The IPROC complex contains one or more ARM CPUs along with common
+	  core periperals. Application specific SoCs are created by adding a
+	  uArchitecture containing peripherals outside of the IPROC complex.
+	  Currently supported SoCs are Cygnus.
+
+menu "iProc SoC based Machine types"
+	depends on ARCH_BCM_IPROC
+
+	config ARCH_BCM_CYGNUS
+		bool "Support Broadcom Cygnus board"
+		select USB_ARCH_HAS_EHCI if USB_SUPPORT
+		help
+		  Support for Broadcom Cygnus SoC.
+endmenu
+
 config ARCH_BCM_MOBILE
 	bool "Broadcom Mobile SoC Support" if ARCH_MULTI_V7
 	select ARCH_REQUIRE_GPIOLIB
diff --git a/arch/arm/mach-bcm/Makefile b/arch/arm/mach-bcm/Makefile
index b19a396..46e092a 100644
--- a/arch/arm/mach-bcm/Makefile
+++ b/arch/arm/mach-bcm/Makefile
@@ -10,6 +10,9 @@
 # of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 # GNU General Public License for more details.
 
+# Cygnus
+obj-$(CONFIG_ARCH_BCM_CYGNUS) +=  bcm_cygnus.o
+
 # BCM281XX
 obj-$(CONFIG_ARCH_BCM_281XX)	+= board_bcm281xx.o
 
diff --git a/arch/arm/mach-bcm/bcm_cygnus.c b/arch/arm/mach-bcm/bcm_cygnus.c
new file mode 100644
index 0000000..8e430ed
--- /dev/null
+++ b/arch/arm/mach-bcm/bcm_cygnus.c
@@ -0,0 +1,166 @@
+/*
+ * Copyright 2014 Broadcom Corporation.  All rights reserved.
+ *
+ * Unless you and Broadcom execute a separate written software license
+ * agreement governing use of this software, this software is licensed to you
+ * under the terms of the GNU General Public License as
+ * published by the Free Software Foundation version 2.
+ *
+ * This program is distributed "as is" WITHOUT ANY WARRANTY of any
+ * kind, whether express or implied; without even the implied warranty
+ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/of_address.h>
+#include <linux/of_platform.h>
+#include <linux/clocksource.h>
+#include <linux/clk-provider.h>
+#include <linux/delay.h>
+#include <asm/mach/arch.h>
+#include <asm/mach/map.h>
+#include <asm/proc-fns.h>
+#include <asm/hardware/cache-l2x0.h>
+
+#define CRMU_MAIL_BOX1      0x03024028
+#define CRMU_SOFT_RESET_CMD 0xFFFFFFFF
+
+/* CRU_RESET register */
+static void * __iomem crmu_mail_box1_reg;
+
+#ifdef CONFIG_NEON
+
+#define CRU_BASE                  0x1800e000
+#define CRU_SIZE                  0x34
+#define CRU_CONTROL_OFFSET        0x0
+#define CRU_PWRDWN_EN_OFFSET      0x4
+#define CRU_PWRDWN_STATUS_OFFSET  0x8
+#define CRU_NEON0_HW_RESET  6
+#define CRU_CLAMP_ON_NEON0  20
+#define CRU_PWRONIN_NEON0   21
+#define CRU_PWRONOUT_NEON0  21
+#define CRU_PWROKIN_NEON0   22
+#define CRU_PWROKOUT_NEON0  22
+#define CRU_STATUS_DELAY_NS 500
+#define CRU_MAX_RETRY_COUNT 10
+#define CRU_RETRY_INTVL_US  1
+
+/* Power up the NEON/VFPv3 block. */
+static void bcm_cygnus_powerup_neon(void)
+{
+	void * __iomem cru_base = ioremap(CRU_BASE, CRU_SIZE);
+	u32 reg, i;
+
+	if (WARN_ON(!cru_base))
+		return;
+
+	/* De-assert the neon hardware block reset */
+	reg = readl(cru_base + CRU_CONTROL_OFFSET);
+	reg &= ~(1 << CRU_NEON0_HW_RESET);
+	writel(reg, cru_base + CRU_CONTROL_OFFSET);
+
+	/* Assert the power ON register bit */
+	reg = readl(cru_base + CRU_PWRDWN_EN_OFFSET);
+	reg |= (1 << CRU_PWRONIN_NEON0);
+	writel(reg, cru_base + CRU_PWRDWN_EN_OFFSET);
+
+	/*
+	 * Wait up to 10 usec in 1 usec increments for the
+	 * status register to acknowledge the power ON assert
+	 */
+	for (i = 0; i < CRU_MAX_RETRY_COUNT; i++) {
+		reg = readl(cru_base + CRU_PWRDWN_STATUS_OFFSET);
+		if (reg & CRU_PWRONOUT_NEON0)
+			break;
+
+		udelay(CRU_RETRY_INTVL_US);
+	}
+
+	if (WARN_ON(i == CRU_MAX_RETRY_COUNT))
+		goto neon_unmap;
+
+	/* Wait 0.5 usec = 500 nsec */
+	ndelay(CRU_STATUS_DELAY_NS);
+
+	/* Assert the power OK register bit */
+	reg = readl(cru_base + CRU_PWRDWN_EN_OFFSET);
+	reg |= (1 << CRU_PWROKIN_NEON0);
+	writel(reg, cru_base + CRU_PWRDWN_EN_OFFSET);
+
+	/*
+	 * Wait up to 10 usec in 1 usec increments for the
+	 * status register to acknowledge the power OK assert
+	 */
+	for (i = 0; i < CRU_MAX_RETRY_COUNT; i++) {
+		reg = readl(cru_base + CRU_PWRDWN_STATUS_OFFSET);
+		if (reg & CRU_PWROKOUT_NEON0)
+			break;
+
+		udelay(CRU_RETRY_INTVL_US);
+	}
+
+	if (WARN_ON(i == CRU_MAX_RETRY_COUNT))
+		goto neon_unmap;
+
+	/* Wait 0.5 usec = 500 nsec */
+	ndelay(CRU_STATUS_DELAY_NS);
+
+	/* Set the logic clamp for the neon block */
+	reg = readl(cru_base + CRU_PWRDWN_EN_OFFSET);
+	reg &= ~(1 << CRU_CLAMP_ON_NEON0);
+	writel(reg, cru_base + CRU_PWRDWN_EN_OFFSET);
+
+	/* Wait 0.5 usec = 500 nsec */
+	ndelay(CRU_STATUS_DELAY_NS);
+
+	/* Reset the neon hardware block */
+	reg = readl(cru_base + CRU_CONTROL_OFFSET);
+	reg |= (1 << CRU_NEON0_HW_RESET);
+	writel(reg, cru_base + CRU_CONTROL_OFFSET);
+
+neon_unmap:
+	iounmap(cru_base);
+}
+#endif /* CONFIG_NEON */
+
+static void __init bcm_cygnus_init(void)
+{
+	of_platform_populate(NULL, of_default_bus_match_table, NULL, NULL);
+
+	l2x0_of_init(0, ~0UL);
+
+	crmu_mail_box1_reg = ioremap(CRMU_MAIL_BOX1, SZ_4);
+	WARN_ON(!crmu_mail_box1_reg);
+
+#ifdef CONFIG_NEON
+	bcm_cygnus_powerup_neon();
+#endif
+}
+
+/*
+ * Reset the system
+ */
+void bcm_cygnus_restart(enum reboot_mode mode, const char *cmd)
+{
+	/* Send reset command to M0 via Mailbox. */
+	if (crmu_mail_box1_reg) {
+		writel(CRMU_SOFT_RESET_CMD, crmu_mail_box1_reg);
+		iounmap(crmu_mail_box1_reg);
+	}
+
+	/* Wait for M0 to reset the chip. */
+	while (1)
+		cpu_do_idle();
+}
+
+static const char const *bcm_cygnus_dt_compat[] = {
+	"brcm,cygnus",
+	NULL,
+};
+
+DT_MACHINE_START(BCM_CYGNUS_DT, "Broadcom Cygnus SoC")
+	.init_machine = bcm_cygnus_init,
+	.map_io = debug_ll_io_init,
+	.dt_compat = bcm_cygnus_dt_compat,
+	.restart   = bcm_cygnus_restart
+MACHINE_END
-- 
1.7.9.5


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

* [PATCH v2 2/6] clk: Clock driver support for Broadcom Cygnus SoC
  2014-09-23 21:17 ` [PATCH v2 " Jonathan Richardson
  2014-09-23 21:17   ` [PATCH v2 1/6] ARM: cygnus: Initial " Jonathan Richardson
@ 2014-09-23 21:17   ` Jonathan Richardson
  2014-09-23 21:17   ` [PATCH v2 3/6] dt-bindings: Document Broadcom Cygnus SoC and clock driver Jonathan Richardson
                     ` (4 subsequent siblings)
  6 siblings, 0 replies; 92+ messages in thread
From: Jonathan Richardson @ 2014-09-23 21:17 UTC (permalink / raw)
  To: Christian Daudt, Matt Porter, Russell King, Mike Turquette,
	Rob Herring, Pawel Moll, Mark Rutland, Ian Campbell, Kumar Gala,
	JD Zheng
  Cc: linux-arm-kernel, bcm-kernel-feedback-list, linux-kernel,
	devicetree, Scott Branden, Ray Jui, Jonathan Richardson

The iProc clock driver controls PLLs common across iProc chips. The
cygnus driver controls cygnus specific features and variations.

Reviewed-by: Ray Jui <rjui@broadcom.com>
Tested-by: Jonathan Richardson <jonathar@broadcom.com>
Reviewed-by: JD (Jiandong) Zheng <jdzheng@broadcom.com>
Signed-off-by: Jonathan Richardson <jonathar@broadcom.com>
---
 drivers/clk/Makefile         |    1 +
 drivers/clk/bcm/Makefile     |    2 +
 drivers/clk/bcm/clk-cygnus.c | 1186 ++++++++++++++++++++++++++++++++++++++++++
 drivers/clk/bcm/clk-iproc.c  |  451 ++++++++++++++++
 4 files changed, 1640 insertions(+)
 create mode 100644 drivers/clk/bcm/clk-cygnus.c
 create mode 100644 drivers/clk/bcm/clk-iproc.c

diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile
index f537a0b..8ac0a31 100644
--- a/drivers/clk/Makefile
+++ b/drivers/clk/Makefile
@@ -37,6 +37,7 @@ obj-$(CONFIG_ARCH_VT8500)		+= clk-vt8500.o
 obj-$(CONFIG_COMMON_CLK_WM831X)		+= clk-wm831x.o
 obj-$(CONFIG_COMMON_CLK_XGENE)		+= clk-xgene.o
 obj-$(CONFIG_COMMON_CLK_AT91)		+= at91/
+obj-$(CONFIG_ARCH_BCM_IPROC)	+= bcm/
 obj-$(CONFIG_ARCH_BCM_MOBILE)		+= bcm/
 obj-$(CONFIG_ARCH_BERLIN)		+= berlin/
 obj-$(CONFIG_ARCH_HI3xxx)		+= hisilicon/
diff --git a/drivers/clk/bcm/Makefile b/drivers/clk/bcm/Makefile
index 6297d05..f803919 100644
--- a/drivers/clk/bcm/Makefile
+++ b/drivers/clk/bcm/Makefile
@@ -2,3 +2,5 @@ obj-$(CONFIG_CLK_BCM_KONA)	+= clk-kona.o
 obj-$(CONFIG_CLK_BCM_KONA)	+= clk-kona-setup.o
 obj-$(CONFIG_CLK_BCM_KONA)	+= clk-bcm281xx.o
 obj-$(CONFIG_CLK_BCM_KONA)	+= clk-bcm21664.o
+obj-$(CONFIG_ARCH_BCM_IPROC)	+= clk-iproc.o
+obj-$(CONFIG_ARCH_BCM_CYGNUS)	+= clk-cygnus.o
diff --git a/drivers/clk/bcm/clk-cygnus.c b/drivers/clk/bcm/clk-cygnus.c
new file mode 100644
index 0000000..2a4f976
--- /dev/null
+++ b/drivers/clk/bcm/clk-cygnus.c
@@ -0,0 +1,1186 @@
+/*
+ * Copyright 2014 Broadcom Corporation.  All rights reserved.
+ *
+ * Unless you and Broadcom execute a separate written software license
+ * agreement governing use of this software, this software is licensed to you
+ * under the terms of the GNU General Public License as
+ * published by the Free Software Foundation version 2.
+ *
+ * This program is distributed "as is" WITHOUT ANY WARRANTY of any
+ * kind, whether express or implied; without even the implied warranty
+ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+#include <linux/kernel.h>
+#include <linux/err.h>
+#include <linux/clk-provider.h>
+#include <linux/io.h>
+#include <linux/of.h>
+#include <linux/clkdev.h>
+#include <linux/of_address.h>
+
+/*
+ * The CRU contains two similar PLLs: LCPLL and GENPLL,
+ * both with several output channels divided from the PLL
+ * output.
+ */
+
+#define CRU_LCPLL_CONTROL1_OFFSET  0x04
+#define CRU_LCPLL_STATUS_OFFSET    0x18
+
+#define LCPLL0_PDIV_SHIFT       26
+#define LCPLL0_PDIV_MASK        0xf
+#define LCPLL0_NDIV_SHIFT       16
+#define LCPLL0_NDIV_MASK        0x3ff
+#define LCPLL_ENABLEB_CH_SHIFT  7
+#define LCPLL_ENABLEB_CH_MASK   0x3f
+#define LCPLL_MDIV_MASK         0xff
+#define LCPLL_STATUS_LOCK_SHIFT 12
+
+#define LCPLL0_CONTROL0_OFFSET  0x00
+#define LCPLL0_CONTROL1_OFFSET  0x04
+#define LCPLL0_CONTROL2_OFFSET  0x08
+#define LCPLL0_CONTROL3_OFFSET  0x0c
+
+#define GENPLL_CONTROL0_OFFSET 0x00
+#define GENPLL_CONTROL1_OFFSET 0x04
+#define GENPLL_CONTROL2_OFFSET 0x08
+#define GENPLL_CONTROL3_OFFSET 0x0c
+#define GENPLL_CONTROL4_OFFSET 0x10
+#define GENPLL_CONTROL5_OFFSET 0x14
+#define GENPLL_CONTROL6_OFFSET 0x18
+#define GENPLL_CONTROL7_OFFSET 0x1c
+#define GENPLL_CONTROL8_OFFSET 0x20
+#define GENPLL_CONTROL9_OFFSET 0x24
+#define GENPLL_STATUS_OFFSET   0x28
+
+#define GENPLL_ENABLEB_CH_SHIFT    0x6
+#define GENPLL_ENABLEB_CH_MASK     0x3f
+
+#define GENPLL_STATUS_LOCK_SHIFT           12
+#define GENPLL_STATUS_LOCK_MASK            1
+#define GENPLL_CONTROL4_NDIV_INT_SHIFT     20
+#define GENPLL_CONTROL4_NDIV_INT_MASK      0x3FF
+#define GENPLL_CONTROL4_NDIV_FRAC_SHIFT    0
+#define GENPLL_CONTROL4_NDIV_FRAC_MASK     0xFFFFF
+#define GENPLL_CONTROL5_PDIV_SHIFT         0
+#define GENPLL_CONTROL5_PDIV_MASK          0xF
+#define GENPLL_MDIV_MASK                   0xff
+
+#define MIPI_DSI_GENPLL_ENABLEB_CH_SHIFT   12
+#define NDIV_FRAC_DIVISOR                  0x100000
+
+#define ASIU_MIPI_GENPLL_PWRON_SHIFT      20
+#define ASIU_MIPI_GENPLL_PWRON_PLL_SHIFT  19
+#define ASIU_MIPI_GENPLL_PWRON_BG_SHIFT   18
+#define ASIU_MIPI_GENPLL_PWRON_LDO_SHIFT  17
+#define ASIU_MIPI_GENPLL_ISO_IN_SHIFT     16
+#define ASIU_AUDIO_GENPLL_PWRON_PLL_SHIFT 11
+#define ASIU_AUDIO_GENPLL_PWRON_BG_SHIFT  10
+#define ASIU_AUDIO_GENPLL_PWRON_LDO_SHIFT 9
+#define ASIU_AUDIO_GENPLL_ISO_IN          8
+
+#define CLK_RATE_NO_DIV                   -1
+
+/*
+ * The clock framework may call recalc even if a clock is is unused, and
+ * therefore before being prepared/enabled. State checking is done for the
+ * MIPI PLL to prevent reading from a MIPI DSI register before the PLL is
+ * powered up because it will cause corruption (imprecise external aborts)
+ * sometimer later on.
+ */
+enum clock_state {
+	CLK_ENABLED,
+	CLK_PREPARED,
+	CLK_DISABLED
+};
+
+struct cygnus_clk {
+	struct clk_hw   hw;
+	void __iomem    *regs_base;
+	void __iomem    *pll_ctrl_reg;
+	void __iomem    *clock_gate_ctrl_reg;
+	int             chan;
+	int             internal_div;
+	unsigned long   rate;
+	enum clock_state state;
+};
+
+#define to_cygnus_clk(p) container_of(p, struct cygnus_clk, hw)
+
+/* Identifies LCPLL clock channels. */
+enum cygnus_lcpll_clk_chan {
+	LCPLL_CH0_PCIE_PHY_REF_CLK      = 0,
+	LCPLL_CH1_DDR_CLK               = 1,
+	LCPLL_CH2_SDIO_CLK              = 2,
+	LCPLL_CH3_USB_PHY_REF_CLK       = 3,
+	LCPLL_CH4_ASIU_SMART_CARD_CLK   = 4,
+	LCPLL_CH5                       = 5
+};
+
+/* Identifies GENPLL clock channels. */
+enum cygnus_genpll_clk_chan {
+	GENPLL_CH0_AXI21_CLK      = 0,
+	GENPLL_CH1_25MHZ_CLK      = 1,
+	GENPLL_CH2_SYS_CLK        = 2,
+	GENPLL_CH3_ETHERNET_CLK   = 3,
+	GENPLL_CH4_ASIU_AUDIO_CLK = 4,
+	GENPLL_CH5_ASIU_CAN_CLK   = 5
+};
+
+/*
+ * Channels for Oscillator dervived clocks are values used to determine
+ * which clock to enable/disable from the top clock gating control.
+ */
+enum cygnus_osc_derived_clk_chan {
+	OSC_DERIVED_CH0_KEYPAD_CLK = 0,
+	OSC_DERIVED_CH1_ADC_CLK    = 1,
+	OSC_DERIVED_CH2_PWM_CLK    = 2,
+};
+
+enum cygnus_mipi_pll_clk_chan {
+	MIPI_PLL_CH0_MIPI_PHY_CLK    = 0,
+	MIPI_PLL_CH1_LCD_CLK         = 1,
+	MIPI_PLL_CH2_3D_GRAPHICS_CLK = 2,
+};
+
+/* Order of registers defined in DT. */
+enum cygnus_clk_dt_regs {
+	CYGNUS_CLK_BASE_REG = 0,
+	CYGNUS_CLK_GATE_CTRL_REG,
+	CYGNUS_PLL_CTRL_REG
+};
+
+enum cygnus_top_clk_gating_ctrl_offsets {
+	GFX_CLK_GATE_EN = 0,
+	AUD_CLK_GATE_EN,
+	CAM_CLK_GATE_EN,
+	MIPI_DSI_CLK_GATE_EN,
+	LCD_CLK_GATE_EN,
+	D1W_CLK_GATE_EN,
+	CAN_CLK_GATE_EN,
+	KEYPAD_CLK_GATE_EN,
+	SMARTCARD_CLK_GATE_EN,
+	ADC_CLK_GATE_EN,
+	CRYPTO_CLK_GATE_EN
+};
+
+/*
+ * Enable clocks controlled through the top clock gating control.
+ *
+ * @param enable true = enable clock, false = disable clock
+ */
+static void cygnus_clkgate_enable_disable(void __iomem *clkgate_reg,
+	enum cygnus_top_clk_gating_ctrl_offsets offset, bool enable)
+{
+	u32 val = readl(clkgate_reg);
+
+	/* Enable or disable the clock. */
+	if (enable)
+		val |= 1 << offset;
+	else
+		val &= ~(1 << offset);
+
+	writel(val, clkgate_reg);
+}
+
+/*
+ * Powers on/off the MIPI GENPLL using CRMU_PLL_AON_CTRL register.
+ *
+ * @param power_on true to power on PLL, false to power off
+ */
+static void cygnus_mipi_genpll_power_on_off(void __iomem *pll_ctrl_reg,
+	bool power_on)
+{
+	u32 val;
+	u32 pll_ldo_on = ((1 << ASIU_MIPI_GENPLL_PWRON_SHIFT) |
+		(1 << ASIU_MIPI_GENPLL_PWRON_PLL_SHIFT) |
+		(1 << ASIU_MIPI_GENPLL_PWRON_BG_SHIFT)  |
+		(1 << ASIU_MIPI_GENPLL_PWRON_LDO_SHIFT));
+
+	val = readl(pll_ctrl_reg);
+
+	/*
+	 * Set PLL on/off. Set input isolation mode to 1 when disabled, 0 when
+	 * enabled.
+	 */
+	if (power_on) {
+		val |= pll_ldo_on;
+		val &= ~(1 << ASIU_MIPI_GENPLL_ISO_IN_SHIFT);
+	} else {
+		val &= ~pll_ldo_on;
+		val |= 1 << ASIU_MIPI_GENPLL_ISO_IN_SHIFT;
+	}
+
+	writel(val, pll_ctrl_reg);
+}
+
+/*
+ * Powers on/off the audio PLL using CRMU_PLL_AON_CTRL register.
+ *
+ * @param power_on true to power on PLL, false to power off
+ */
+static void cygnus_audio_genpll_power_on_off(void __iomem *pll_ctrl_reg,
+	bool power_on)
+{
+	u32 val;
+	u32 pll_ldo_on = ((1 << ASIU_AUDIO_GENPLL_PWRON_PLL_SHIFT) |
+		(1 << ASIU_AUDIO_GENPLL_PWRON_BG_SHIFT) |
+		(1 << ASIU_AUDIO_GENPLL_PWRON_LDO_SHIFT));
+
+	val = readl(pll_ctrl_reg);
+
+	/*
+	 * Set PLL on/off. Set input isolation mode to 1 when disabled, 0 when
+	 * enabled.
+	 */
+	if (power_on) {
+		val |= pll_ldo_on;
+		val &= ~(1 << ASIU_AUDIO_GENPLL_ISO_IN);
+	} else {
+		val &= ~pll_ldo_on;
+		val |= 1 << ASIU_AUDIO_GENPLL_ISO_IN;
+	}
+
+	writel(val, pll_ctrl_reg);
+}
+
+/*
+ * Get PLL running status and calculate output frequency
+ */
+static unsigned long cygnus_lcpll_status(struct cygnus_clk *clk,
+	unsigned long parent_rate)
+{
+	u32 reg;
+	unsigned pdiv, ndiv;
+
+	/* read status register */
+	reg = readl(clk->regs_base + CRU_LCPLL_STATUS_OFFSET);
+
+	/* Must be locked for proper PLL operation. */
+	if ((reg & (1 << LCPLL_STATUS_LOCK_SHIFT)) == 0) {
+		clk->rate = 0;
+		return -EIO;
+	}
+
+	/*
+	 * Calculate PLL frequency based on LCPLL divider values:
+	 *	 pdiv = LCPLL pre-divider ratio
+	 *   ndiv = LCPLL feedback divider
+	 *
+	 * The frequency is calculated by:
+	 *   ndiv * (parent clock rate / pdiv)
+	 */
+
+	reg = readl(clk->regs_base + CRU_LCPLL_CONTROL1_OFFSET);
+
+	/* feedback divider integer and fraction parts */
+	pdiv = (reg >> LCPLL0_PDIV_SHIFT) & LCPLL0_PDIV_MASK;
+	ndiv = (reg >> LCPLL0_NDIV_SHIFT) & LCPLL0_NDIV_MASK;
+
+	if (pdiv == 0)
+		return -EIO;
+
+	clk->rate = ndiv * (parent_rate / pdiv);
+
+	return clk->rate;
+}
+
+static unsigned long cygnus_lcpll_clk_recalc_rate(struct clk_hw *hwclk,
+	unsigned long parent_rate)
+{
+	struct cygnus_clk *bcm_clk = to_cygnus_clk(hwclk);
+
+	return cygnus_lcpll_status(bcm_clk, parent_rate);
+}
+
+static const struct clk_ops cygnus_lcpll_ops = {
+	.recalc_rate = cygnus_lcpll_clk_recalc_rate,
+};
+
+static int cygnus_lcpll_chan_status(struct cygnus_clk *clk,
+	unsigned long parent_rate)
+{
+	void * __iomem base;
+	u32 reg;
+	unsigned enable;
+	unsigned mdiv;
+	int offset = 0;
+	int shift = 0;
+
+	/* Register address is only stored in PLL structure */
+	base = clk->regs_base;
+	BUG_ON(base == NULL);
+
+	/* enable bit is in enableb_ch[] inversed */
+	enable = ((readl(base + LCPLL0_CONTROL0_OFFSET) >>
+		LCPLL_ENABLEB_CH_SHIFT) & LCPLL_ENABLEB_CH_MASK) ^
+		LCPLL_ENABLEB_CH_MASK;
+
+	if ((enable & (1 << clk->chan)) == 0) {
+		clk->rate = 0;
+		return -EIO;
+	}
+
+	/* MDIV for the 6 channels is spread over two registers. */
+	switch (clk->chan) {
+	case LCPLL_CH0_PCIE_PHY_REF_CLK:
+		offset = LCPLL0_CONTROL2_OFFSET; shift = 0;
+		break;
+
+	case LCPLL_CH1_DDR_CLK:
+		offset = LCPLL0_CONTROL2_OFFSET; shift = 10;
+		break;
+
+	case LCPLL_CH2_SDIO_CLK:
+		offset = LCPLL0_CONTROL2_OFFSET; shift = 20;
+		break;
+
+	case LCPLL_CH3_USB_PHY_REF_CLK:
+		offset = LCPLL0_CONTROL3_OFFSET; shift = 0;
+		break;
+
+	case LCPLL_CH4_ASIU_SMART_CARD_CLK:
+		offset = LCPLL0_CONTROL3_OFFSET; shift = 10;
+		break;
+
+	case LCPLL_CH5:
+		offset = LCPLL0_CONTROL3_OFFSET; shift = 20;
+		break;
+
+	default:
+		return -EINVAL;
+	}
+
+	/* Read MDIV for requested channel. */
+	reg = readl(base + offset);
+	mdiv = (reg >> shift) & LCPLL_MDIV_MASK;
+
+	/* when divisor is 0, it behaves as max+1 */
+	if (mdiv == 0)
+		mdiv = 256;
+
+	clk->rate = parent_rate / mdiv;
+
+	pr_debug("LCPLL[%d] mdiv=%u Prate=%lu rate=%lu\n",
+		clk->chan, mdiv, parent_rate, clk->rate);
+
+	return clk->rate;
+}
+
+static unsigned long cygnus_lcpll_chan_recalc_rate(struct clk_hw *hwclk,
+	unsigned long parent_rate)
+{
+	struct cygnus_clk *bcm_clk = to_cygnus_clk(hwclk);
+
+	return cygnus_lcpll_chan_status(bcm_clk, parent_rate);
+}
+
+static const struct clk_ops cygnus_lcpll_chan_ops = {
+	.recalc_rate = cygnus_lcpll_chan_recalc_rate,
+};
+
+/*
+ * Get PLL running status and calculate output frequency
+ */
+static unsigned long cygnus_genpll_status(struct cygnus_clk *clk,
+	unsigned long parent_rate)
+{
+	u32 reg;
+	unsigned pdiv;
+	unsigned ndiv_int;
+	unsigned ndiv_frac;
+
+	/* Read PLL status register. It must be locked. */
+	reg = readl(clk->regs_base + GENPLL_STATUS_OFFSET);
+	if ((reg & (1 << GENPLL_STATUS_LOCK_SHIFT)) == 0) {
+		clk->rate = 0;
+		return -EIO;
+	}
+
+	/* Calculate PLL frequency */
+
+	/* Get PLL feedback divider values. */
+	reg = readl(clk->regs_base + GENPLL_CONTROL4_OFFSET);
+
+	/* feedback divider integer and fraction parts */
+	ndiv_int = reg >> GENPLL_CONTROL4_NDIV_INT_SHIFT;
+	ndiv_frac = reg & GENPLL_CONTROL4_NDIV_INT_MASK;
+	ndiv_int += ndiv_frac / NDIV_FRAC_DIVISOR;
+
+	/* Get pdiv - first 4 bits. */
+	reg = readl(clk->regs_base + GENPLL_CONTROL5_OFFSET);
+	pdiv = reg & GENPLL_CONTROL5_PDIV_MASK;
+	if (pdiv == 0)
+		return -EIO;
+
+	clk->rate = (parent_rate / pdiv) * ndiv_int;
+
+	return clk->rate;
+}
+
+static unsigned long cygnus_genpll_recalc_rate(struct clk_hw *hwclk,
+	unsigned long parent_rate)
+{
+	struct cygnus_clk *bcm_clk = to_cygnus_clk(hwclk);
+
+	return cygnus_genpll_status(bcm_clk, parent_rate);
+}
+
+static const struct clk_ops cygnus_genpll_ops = {
+	.recalc_rate = cygnus_genpll_recalc_rate,
+};
+
+/*
+ * Calculates clock rate of the GENPLL channel requested. The clock rate is
+ * calculated as: the configured clock rate
+ *     Parent clock rate / mdiv
+ */
+static unsigned long cygnus_genpll_chan_get_rate(struct cygnus_clk *clk,
+	unsigned long parent_rate, int enableb_ch_shift)
+{
+	u32 reg;
+	unsigned enable;
+	unsigned mdiv;
+	unsigned offset = 0;
+	unsigned shift = 0;
+
+	/*
+	 * Read ENABLEB_CH to determine which channels are enabled. The enable
+	 * bits are inversed: 0 = channel enabled, 1 = channel disabled.
+	 */
+	reg = readl(clk->regs_base + GENPLL_CONTROL1_OFFSET);
+	enable = ((reg >> enableb_ch_shift) &
+		GENPLL_ENABLEB_CH_MASK) ^ GENPLL_ENABLEB_CH_MASK;
+
+	/* If channel is disabled the rate is 0. */
+	if ((enable & (1 << clk->chan)) == 0) {
+		clk->rate = 0;
+		return -EIO;
+	}
+
+	/* MDIV for the 6 channels is spread over two registers. */
+	switch (clk->chan) {
+	case 0:
+		offset = GENPLL_CONTROL8_OFFSET; shift = 0;
+		break;
+
+	case 1:
+		offset = GENPLL_CONTROL8_OFFSET; shift = 10;
+		break;
+
+	case 2:
+		offset = GENPLL_CONTROL8_OFFSET; shift = 20;
+		break;
+
+	case 3:
+		offset = GENPLL_CONTROL9_OFFSET; shift = 0;
+		break;
+
+	case 4:
+		offset = GENPLL_CONTROL9_OFFSET; shift = 10;
+		break;
+
+	case 5:
+		offset = GENPLL_CONTROL9_OFFSET; shift = 20;
+		break;
+
+	default:
+		return -EINVAL;
+	}
+
+	/* Read MDIV (post divider ratio) for requested channel. */
+	reg = readl(clk->regs_base + offset);
+	mdiv = (reg >> shift) & GENPLL_MDIV_MASK;
+
+	/* When divisor is 0, it behaves as max+1. */
+	if (mdiv == 0)
+		mdiv = 256;
+
+	clk->rate = parent_rate / mdiv;
+
+	pr_debug("GENPLL[%d] mdiv=%u parent rate=%lu rate=%lu\n",
+		clk->chan, mdiv, parent_rate, clk->rate);
+
+	return clk->rate;
+}
+
+/*
+ * Powers on the audio PLL for the audio channel from the PLL. No other
+ * GENPLL channels require powering on.
+ */
+static int cygnus_genpll_chan_prepare(struct clk_hw *hwclk)
+{
+	struct cygnus_clk *clk = to_cygnus_clk(hwclk);
+	struct clk *parent_clk = clk_get_parent(hwclk->clk);
+	struct cygnus_clk *cyg_parent_clk =
+		to_cygnus_clk(__clk_get_hw(parent_clk));
+
+	if (WARN_ON(!cyg_parent_clk->pll_ctrl_reg))
+		return -EIO;
+
+	if (clk->chan == GENPLL_CH4_ASIU_AUDIO_CLK) {
+		pr_debug("GENPLL[%d]: Powering on audio PLL/LDO\n", clk->chan);
+		cygnus_audio_genpll_power_on_off(
+			cyg_parent_clk->pll_ctrl_reg, true);
+	}
+
+	return 0;
+}
+
+/*
+ * Powers off the audio PLL for the audio channel from the PLL. No other
+ * GENPLL channels require powering off.
+ */
+static void cygnus_genpll_chan_unprepare(struct clk_hw *hwclk)
+{
+	struct cygnus_clk *clk = to_cygnus_clk(hwclk);
+	struct clk *parent_clk = clk_get_parent(hwclk->clk);
+	struct cygnus_clk *cyg_parent_clk =
+		to_cygnus_clk(__clk_get_hw(parent_clk));
+
+	if (WARN_ON(!cyg_parent_clk->pll_ctrl_reg))
+		return;
+
+	if (clk->chan == GENPLL_CH4_ASIU_AUDIO_CLK) {
+		pr_debug("GENPLL[%d]: Powering down audio PLL and LDO\n",
+			clk->chan);
+		cygnus_audio_genpll_power_on_off(cyg_parent_clk->pll_ctrl_reg,
+			false);
+	}
+}
+
+static unsigned long cygnus_genpll_chan_recalc_rate(struct clk_hw *hwclk,
+	unsigned long parent_rate)
+{
+	struct cygnus_clk *bcm_clk = to_cygnus_clk(hwclk);
+
+	return cygnus_genpll_chan_get_rate(bcm_clk, parent_rate,
+		GENPLL_ENABLEB_CH_SHIFT);
+}
+
+/*
+ * Enables GENPLL channels. The only PLL channel that is controlled through
+ * the top clock gating control is the audio clock which requires enabling.
+ *
+ * Individual channels aren't enabled/disabled on the PLL because they are
+ * enabled by default and drivers don't always refer to them, meaning the
+ * clock framework would disable them. This can be added later when power
+ * saving is a concern.
+ */
+static int cygnus_genpll_chan_enable(struct clk_hw *hwclk)
+{
+	struct cygnus_clk *clk = to_cygnus_clk(hwclk);
+	struct clk *parent_clk = clk_get_parent(hwclk->clk);
+	struct cygnus_clk *cyg_parent_clk =
+		to_cygnus_clk(__clk_get_hw(parent_clk));
+	int parent_rate;
+
+	if (WARN_ON(!cyg_parent_clk->clock_gate_ctrl_reg))
+		return -EIO;
+
+	pr_debug("Enable GENPLL chan %d\n", clk->chan);
+
+	if (clk->chan == GENPLL_CH4_ASIU_AUDIO_CLK) {
+		cygnus_clkgate_enable_disable(
+			cyg_parent_clk->clock_gate_ctrl_reg,
+			AUD_CLK_GATE_EN, true);
+
+		/* Ensure parent's clock rate is calculated. */
+		parent_rate = clk_get_rate(parent_clk);
+		if (WARN_ON(!parent_rate))
+			return -EIO;
+	}
+
+	return 0;
+}
+
+static void cygnus_genpll_chan_disable(struct clk_hw *hwclk)
+{
+	struct cygnus_clk *clk = to_cygnus_clk(hwclk);
+	struct clk *parent_clk = clk_get_parent(hwclk->clk);
+	struct cygnus_clk *cyg_parent_clk =
+		to_cygnus_clk(__clk_get_hw(parent_clk));
+
+	if (WARN_ON(!cyg_parent_clk->clock_gate_ctrl_reg))
+		return;
+
+	pr_debug("GENPLL: disable chan %d\n", clk->chan);
+
+	/* Enable audio clock. */
+	if (clk->chan == GENPLL_CH4_ASIU_AUDIO_CLK)
+		cygnus_clkgate_enable_disable(
+			cyg_parent_clk->clock_gate_ctrl_reg,
+			AUD_CLK_GATE_EN, false);
+}
+
+static const struct clk_ops cygnus_genpll_chan_ops = {
+	.prepare = cygnus_genpll_chan_prepare,
+	.unprepare = cygnus_genpll_chan_unprepare,
+	.enable = cygnus_genpll_chan_enable,
+	.disable = cygnus_genpll_chan_disable,
+	.recalc_rate = cygnus_genpll_chan_recalc_rate,
+};
+
+static __init struct clk *cygnus_clock_init(struct device_node *node,
+	const struct clk_ops *ops)
+{
+	u32 channel = 0;
+	struct clk *clk;
+	struct cygnus_clk *cygnus_clk;
+	const char *clk_name = node->name;
+	const char *parent_name;
+	struct clk_init_data init;
+	int rc;
+
+	pr_debug("Clock name %s\n", node->name);
+
+	cygnus_clk = kzalloc(sizeof(*cygnus_clk), GFP_KERNEL);
+	if (WARN_ON(!cygnus_clk))
+		return NULL;
+
+	cygnus_clk->state = CLK_DISABLED;
+
+	/* Read base address from device tree and map to virtual address. */
+	cygnus_clk->regs_base = of_iomap(node, CYGNUS_CLK_BASE_REG);
+	if (WARN_ON(!cygnus_clk->regs_base))
+		goto err_alloc;
+
+	/* Read optional base addresses for PLL control and clock gating. */
+	cygnus_clk->clock_gate_ctrl_reg = of_iomap(node,
+		CYGNUS_CLK_GATE_CTRL_REG);
+	cygnus_clk->pll_ctrl_reg = of_iomap(node, CYGNUS_PLL_CTRL_REG);
+
+	of_property_read_u32(node, "channel", &channel);
+	cygnus_clk->chan = channel;
+	of_property_read_string(node, "clock-output-names", &clk_name);
+
+	/*
+	 * Internal divider is optional and used for PLL derived clocks with
+	 * hardcoded dividers.
+	 */
+	cygnus_clk->internal_div = CLK_RATE_NO_DIV;
+	of_property_read_u32(node, "div", &cygnus_clk->internal_div);
+
+	init.name = clk_name;
+	init.ops = ops;
+	init.flags = CLK_GET_RATE_NOCACHE;
+	parent_name = of_clk_get_parent_name(node, 0);
+	init.parent_names = &parent_name;
+	init.num_parents = 1;
+
+	cygnus_clk->hw.init = &init;
+
+	clk = clk_register(NULL, &cygnus_clk->hw);
+	if (WARN_ON(IS_ERR(clk)))
+		goto err_unmap;
+
+	rc = of_clk_add_provider(node, of_clk_src_simple_get, clk);
+	if (WARN_ON(IS_ERR_VALUE(rc)))
+		goto err_unregister;
+
+	rc = clk_register_clkdev(clk, clk_name, NULL);
+	if (WARN_ON(IS_ERR_VALUE(rc)))
+		goto err_provider;
+
+	return clk;
+
+err_provider:
+	of_clk_del_provider(node);
+
+err_unregister:
+	clk_unregister(clk);
+
+err_unmap:
+	iounmap(cygnus_clk->regs_base);
+	iounmap(cygnus_clk->clock_gate_ctrl_reg);
+	iounmap(cygnus_clk->pll_ctrl_reg);
+
+err_alloc:
+	kfree(cygnus_clk);
+
+	return NULL;
+}
+
+static void __init cygnus_lcpll_init(struct device_node *node)
+{
+	cygnus_clock_init(node, &cygnus_lcpll_ops);
+}
+CLK_OF_DECLARE(cygnus_lcpll, "brcm,cygnus-lcpll-clk", cygnus_lcpll_init);
+
+static void __init cygnus_genpll_init(struct device_node *node)
+{
+	cygnus_clock_init(node, &cygnus_genpll_ops);
+}
+CLK_OF_DECLARE(cygnus_genpll, "brcm,cygnus-genpll-clk", cygnus_genpll_init);
+
+static void __init cygnus_lcpll_ch_init(struct device_node *node)
+{
+	cygnus_clock_init(node, &cygnus_lcpll_chan_ops);
+}
+CLK_OF_DECLARE(cygnus_lcpll_ch, "brcm,cygnus-lcpll-ch", cygnus_lcpll_ch_init);
+
+static void __init cygnus_genpll_ch_init(struct device_node *node)
+{
+	cygnus_clock_init(node, &cygnus_genpll_chan_ops);
+}
+CLK_OF_DECLARE(cygnus_genpll_ch, "brcm,cygnus-genpll-ch",
+	cygnus_genpll_ch_init);
+
+/*
+ * Some clocks on Cygnus are derived from the oscillator directly without
+ * going through either the GENPLL or LCPLL. These clocks have specific
+ * registers for their dividers. The clocks included are: keypad, ADC, PWM.
+ */
+
+#define ASIU_CLK_DIV_ENABLE_SHIFT  31
+#define ASIU_CLK_DIV_ENABLE_MASK   0x1
+#define ASIU_CLK_DIV_HIGH_SHIFT    16
+#define ASIU_CLK_DIV_HIGH_MASK     0x3ff
+#define ASIU_CLK_DIV_LOW_SHIFT     0
+#define ASIU_CLK_DIV_LOW_MASK      0x3ff
+
+/*
+ * Calculate clock frequency for clocks derived from oscillator.
+ *
+ * @return The clock rate in Hz
+ */
+static int cygnus_osc_derived_clk_get_rate(struct cygnus_clk *clk,
+	unsigned long parent_rate)
+{
+	int reg_val;
+	int enabled;
+	int clk_div_high;
+	int clk_div_low;
+	unsigned long rate = 0;
+
+	reg_val = readl(clk->regs_base);
+
+	/* Ensure clock is enabled. */
+	enabled = (reg_val >> ASIU_CLK_DIV_ENABLE_SHIFT) &
+		ASIU_CLK_DIV_ENABLE_MASK;
+	if (!enabled)
+		return rate;
+
+	clk_div_high = (reg_val >> ASIU_CLK_DIV_HIGH_SHIFT) &
+		ASIU_CLK_DIV_HIGH_MASK;
+	clk_div_high += 1;
+
+	clk_div_low = (reg_val >> ASIU_CLK_DIV_LOW_SHIFT) &
+		ASIU_CLK_DIV_LOW_MASK;
+	clk_div_low += 1;
+
+	/*
+	 * Rate calculated as:
+	 *   (oscillator rate) / ((clk high + 1) + (clk_low + 1))
+	 */
+	rate = parent_rate / (clk_div_high + clk_div_low);
+
+	pr_debug("Osc derived clk: Prate=%lu div_high=%d div_low=%d rate=%lu\n",
+		parent_rate, clk_div_high, clk_div_low, rate);
+
+	return rate;
+}
+
+static unsigned long cygnus_osc_derived_clk_recalc_rate(struct clk_hw *hwclk,
+	unsigned long parent_rate)
+{
+	struct cygnus_clk *bcm_clk = to_cygnus_clk(hwclk);
+
+	return cygnus_osc_derived_clk_get_rate(bcm_clk, parent_rate);
+}
+
+/*
+ * Enables the top clock gating control for clocks that require it.
+ */
+static int cygnus_osc_derived_clk_enable(struct clk_hw *hwclk)
+{
+	struct cygnus_clk *clk = to_cygnus_clk(hwclk);
+	struct clk *parent_clk = clk_get_parent(hwclk->clk);
+	int parent_rate;
+	u32 val;
+
+	if (WARN_ON(!clk->clock_gate_ctrl_reg))
+		return 0;
+
+	pr_debug("OSC derived clk enable chan %d\n", clk->chan);
+
+	/* Enable top clock gating control if necessary. */
+	if (clk->chan == OSC_DERIVED_CH0_KEYPAD_CLK)
+		cygnus_clkgate_enable_disable(clk->clock_gate_ctrl_reg,
+			KEYPAD_CLK_GATE_EN, true);
+	else if (clk->chan == OSC_DERIVED_CH1_ADC_CLK)
+		cygnus_clkgate_enable_disable(clk->clock_gate_ctrl_reg,
+			ADC_CLK_GATE_EN, true);
+
+	/* Set and enable divider if specified. */
+	if (clk->internal_div != CLK_RATE_NO_DIV) {
+		val = (1 << ASIU_CLK_DIV_ENABLE_SHIFT) |
+			((clk->internal_div & ASIU_CLK_DIV_HIGH_MASK) <<
+			ASIU_CLK_DIV_HIGH_SHIFT) |
+			((clk->internal_div & ASIU_CLK_DIV_LOW_MASK) <<
+			ASIU_CLK_DIV_LOW_SHIFT);
+		writel(val, clk->regs_base);
+	}
+
+	/* Ensure parent's clock rate is calculated. */
+	parent_rate = clk_get_rate(parent_clk);
+	if (WARN_ON(!parent_rate))
+		return -EIO;
+
+	return 0;
+}
+
+/*
+ * Disables top clock gating control for clocks that were enabled.
+ */
+static void cygnus_osc_derived_clk_disable(struct clk_hw *hwclk)
+{
+	struct cygnus_clk *clk = to_cygnus_clk(hwclk);
+
+	if (WARN_ON(!clk->clock_gate_ctrl_reg))
+		return;
+
+	pr_debug("OSC derived clk disable chan %d\n", clk->chan);
+
+	/* Disable top clock gating control if necessary. */
+	if (clk->chan == OSC_DERIVED_CH0_KEYPAD_CLK)
+		cygnus_clkgate_enable_disable(clk->clock_gate_ctrl_reg,
+			KEYPAD_CLK_GATE_EN, false);
+	else if (clk->chan == OSC_DERIVED_CH1_ADC_CLK)
+		cygnus_clkgate_enable_disable(clk->clock_gate_ctrl_reg,
+			ADC_CLK_GATE_EN, false);
+}
+
+static const struct clk_ops cygnus_osc_derived_clk_ops = {
+	.enable = cygnus_osc_derived_clk_enable,
+	.disable = cygnus_osc_derived_clk_disable,
+	.recalc_rate = cygnus_osc_derived_clk_recalc_rate,
+};
+
+static void __init cygnus_osc_derived_init(struct device_node *node)
+{
+	cygnus_clock_init(node, &cygnus_osc_derived_clk_ops);
+}
+
+CLK_OF_DECLARE(cygnus_osc_derived, "brcm,cygnus-osc-derived",
+	cygnus_osc_derived_init);
+
+/*
+ * Some clocks are derived from a PLL. The dividers are internal and can't
+ * be read from a register. If the parent clock rate changes then the derived
+ * clock rates scale accordingly.
+ */
+
+ /*
+  * Calculate clock frequency for clocks derived from oscillator.
+  * Rate calculated as:  parent rate / internal divider
+  * The internal divider must be specified in DT.
+  *
+  * @return The clock rate in Hz.
+  */
+static unsigned long cygnus_pll_derived_clk_get_rate(struct cygnus_clk *clk,
+	unsigned long parent_rate)
+{
+	unsigned long rate = parent_rate / clk->internal_div;
+
+	pr_debug("PLL derived clk: Prate=%lu rate=%lu\n", parent_rate, rate);
+
+	return rate;
+}
+
+static unsigned long cygnus_pll_derived_clk_recalc_rate(struct clk_hw *hwclk,
+	unsigned long parent_rate)
+{
+	struct cygnus_clk *bcm_clk = to_cygnus_clk(hwclk);
+
+	return cygnus_pll_derived_clk_get_rate(bcm_clk, parent_rate);
+}
+
+static const struct clk_ops cygnus_pll_derived_clk_ops = {
+	.recalc_rate = cygnus_pll_derived_clk_recalc_rate,
+};
+
+static void __init cygnus_pll_derived_init(struct device_node *node)
+{
+	cygnus_clock_init(node, &cygnus_pll_derived_clk_ops);
+}
+
+CLK_OF_DECLARE(cygnus_pll_derived, "brcm,cygnus-pll-derived",
+	cygnus_pll_derived_init);
+
+/*
+ * MIPI DSI GENPLL
+ */
+
+/*
+ * Get PLL running status and calculate output frequency.
+ */
+static unsigned long cygnus_mipipll_get_rate(struct cygnus_clk *clk,
+	unsigned long parent_rate)
+{
+	u32 reg;
+	u32 rate;
+	u32 pdiv;
+	u32 ndiv_int;
+	u32 ndiv_frac;
+	int pll_locked;
+
+	/* Read lock field from PLL status register. It must be unlocked. */
+	reg = readl(clk->regs_base + GENPLL_STATUS_OFFSET);
+
+	pll_locked = (reg >> GENPLL_STATUS_LOCK_SHIFT) &
+		GENPLL_STATUS_LOCK_MASK;
+	if (pll_locked) {
+		clk->rate = 0;
+		return -EIO;
+	}
+	/*
+	 * Calculate PLL frequency:
+	 *   PLL freq = ((crystal clock / pdiv) * ndiv ) / mdiv
+	 */
+
+	/* Get PLL feedback divider values. */
+	reg = readl(clk->regs_base + GENPLL_CONTROL4_OFFSET);
+
+	/* Feedback divider integer and fractional parts. */
+	ndiv_int = (reg >> GENPLL_CONTROL4_NDIV_INT_SHIFT) &
+		GENPLL_CONTROL4_NDIV_INT_MASK;
+	ndiv_frac = (reg >> GENPLL_CONTROL4_NDIV_FRAC_SHIFT) &
+		GENPLL_CONTROL4_NDIV_FRAC_MASK;
+	ndiv_int += ndiv_frac / NDIV_FRAC_DIVISOR;
+
+	/* Get pdiv. */
+	reg = readl(clk->regs_base + GENPLL_CONTROL5_OFFSET);
+	pdiv = (reg >> GENPLL_CONTROL5_PDIV_SHIFT) &
+		GENPLL_CONTROL5_PDIV_MASK;
+
+	/* If pdiv is 0, divide by 0.5 - doubler. */
+	if (pdiv == 0)
+		rate = parent_rate * 2;
+	else
+		rate = parent_rate / pdiv;
+
+	clk->rate = rate * ndiv_int;
+
+	pr_debug("[MIPI PLL] parent rate=%lu, ndiv int=%d, pdiv=%d, rate=%lu\n",
+	    parent_rate, ndiv_int, pdiv, clk->rate);
+
+	return clk->rate;
+}
+
+/*
+ * Powers on the necessary PLL's and LDO for MIPI GEN PLL.
+ */
+static int cygnus_mipipll_prepare(struct clk_hw *hwclk)
+{
+	struct cygnus_clk *clk = to_cygnus_clk(hwclk);
+
+	if (WARN_ON(!clk->pll_ctrl_reg))
+		return -EIO;
+
+	pr_debug("Powering up MIPI PLL and LDO\n");
+
+	/* Power on the PLL. */
+	cygnus_mipi_genpll_power_on_off(clk->pll_ctrl_reg, true);
+
+	clk->state = CLK_PREPARED;
+
+	return 0;
+}
+
+/*
+ * Powers off the PLL's and LDO for MIPI GEN PLL.
+ */
+static void cygnus_mipipll_unprepare(struct clk_hw *hwclk)
+{
+	struct cygnus_clk *clk = to_cygnus_clk(hwclk);
+
+	if (WARN_ON(!clk->pll_ctrl_reg))
+		return;
+
+	pr_debug("Powering down MIPI PLL and LDO\n");
+
+	/* Power off the PLL. */
+	cygnus_mipi_genpll_power_on_off(clk->pll_ctrl_reg, false);
+
+	clk->state = CLK_DISABLED;
+}
+
+static unsigned long cygnus_mipipll_recalc_rate(struct clk_hw *hwclk,
+	unsigned long parent_rate)
+{
+	struct cygnus_clk *bcm_clk = to_cygnus_clk(hwclk);
+
+	if (bcm_clk->state != CLK_ENABLED)
+		return 0;
+
+	return cygnus_mipipll_get_rate(bcm_clk, parent_rate);
+}
+
+/*
+ * Enables the MIPI DSI clock gate through the top clock gating control.
+ */
+static int cygnus_mipipll_enable(struct clk_hw *hwclk)
+{
+	struct cygnus_clk *clk = to_cygnus_clk(hwclk);
+
+	if (WARN_ON(!clk->clock_gate_ctrl_reg))
+		return -EIO;
+
+	pr_debug("Enable MIPI PLL\n");
+
+	/* Enable MIPI DSI clock. */
+	cygnus_clkgate_enable_disable(clk->clock_gate_ctrl_reg,
+		MIPI_DSI_CLK_GATE_EN, true);
+
+	clk->state = CLK_ENABLED;
+
+	return 0;
+}
+
+/*
+ * Turns off the MIPI PLL clock.
+ */
+static void cygnus_mipipll_disable(struct clk_hw *hwclk)
+{
+	struct cygnus_clk *clk = to_cygnus_clk(hwclk);
+
+	if (WARN_ON(!clk->clock_gate_ctrl_reg))
+		return;
+
+	pr_debug("Disabling MIPI PLL and LDO\n");
+
+	/* Disable MIPI DSI clock through top clock gating control. */
+	cygnus_clkgate_enable_disable(clk->clock_gate_ctrl_reg,
+		MIPI_DSI_CLK_GATE_EN, false);
+
+	clk->state = CLK_DISABLED;
+}
+
+static const struct clk_ops cygnus_mipipll_ops = {
+	.prepare = cygnus_mipipll_prepare,
+	.unprepare = cygnus_mipipll_unprepare,
+	.enable = cygnus_mipipll_enable,
+	.disable = cygnus_mipipll_disable,
+	.recalc_rate = cygnus_mipipll_recalc_rate,
+};
+
+static void __init cygnus_mipipll_init(struct device_node *node)
+{
+	cygnus_clock_init(node, &cygnus_mipipll_ops);
+}
+CLK_OF_DECLARE(cygnus_mipipll, "brcm,cygnus-mipipll-clk", cygnus_mipipll_init);
+
+/*
+ * MIPI PLL clock channel management.
+ */
+
+/*
+ * Enables a MIPI PLL channel.
+ */
+static void mipi_pll_enable_chan(void __iomem *base, int chan, bool state)
+{
+	u32 val;
+
+	val = readl(base + GENPLL_CONTROL1_OFFSET);
+
+	/* ENABLEB_CH bit set to 0 to enable channel, 1 to disable. */
+	if (state)
+		val &= ~(1 << (chan + MIPI_DSI_GENPLL_ENABLEB_CH_SHIFT));
+	else
+		val |= (1 << (chan + MIPI_DSI_GENPLL_ENABLEB_CH_SHIFT));
+
+	writel(val, base + GENPLL_CONTROL1_OFFSET);
+}
+
+static unsigned long cygnus_mipipll_chan_recalc_rate(struct clk_hw *hwclk,
+	unsigned long parent_rate)
+{
+	struct cygnus_clk *clk = to_cygnus_clk(hwclk);
+
+	if (WARN_ON(!clk->clock_gate_ctrl_reg))
+		return 0;
+
+	if (clk->state != CLK_ENABLED)
+		return 0;
+
+	return cygnus_genpll_chan_get_rate(clk, parent_rate,
+		MIPI_DSI_GENPLL_ENABLEB_CH_SHIFT);
+}
+
+/*
+ * Enables the PLL channel and the top clock gating control for clocks that
+ * are controlled through it.
+ */
+static int cygnus_mipipll_chan_enable(struct clk_hw *hwclk)
+{
+	struct cygnus_clk *clk = to_cygnus_clk(hwclk);
+	struct clk *parent_clk = clk_get_parent(hwclk->clk);
+	int parent_rate;
+
+	if (WARN_ON(!clk->clock_gate_ctrl_reg))
+		return -EIO;
+
+	pr_debug("Enable MIPI PLL chan %d\n", clk->chan);
+
+	/*
+	 * Some MIPI PLL channels have to be enabled through the top clock
+	 * gating ctrl. Add support for other channels here.
+	 */
+	if (clk->chan == MIPI_PLL_CH1_LCD_CLK) {
+		cygnus_clkgate_enable_disable(clk->clock_gate_ctrl_reg,
+			LCD_CLK_GATE_EN, true);
+	}
+
+	/* Enable the PLL channel. */
+	mipi_pll_enable_chan(clk->regs_base, clk->chan, true);
+
+	clk->state = CLK_ENABLED;
+
+	/* Ensure parent's clock rate is calculated. */
+	parent_rate = clk_get_rate(parent_clk);
+	if (WARN_ON(!parent_rate))
+		return -EIO;
+
+	return 0;
+}
+
+/*
+ * Disables the PLL channel. Some channels also have to be shut down through
+ * the top clock gating control.
+ */
+static void cygnus_mipipll_chan_disable(struct clk_hw *hwclk)
+{
+	struct cygnus_clk *clk = to_cygnus_clk(hwclk);
+
+	if (WARN_ON(!clk->clock_gate_ctrl_reg))
+		return;
+
+	pr_debug("Disable MIPI PLL chan %d\n", clk->chan);
+
+	/* Disable LCD clock through top clock gating control. */
+	if (clk->chan == MIPI_PLL_CH1_LCD_CLK) {
+		cygnus_clkgate_enable_disable(clk->clock_gate_ctrl_reg,
+			LCD_CLK_GATE_EN, false);
+	}
+
+	/* Disable the PLL channel. */
+	mipi_pll_enable_chan(clk->regs_base, clk->chan, false);
+
+	clk->state = CLK_DISABLED;
+}
+
+static const struct clk_ops cygnus_mipipll_chan_ops = {
+	.enable = cygnus_mipipll_chan_enable,
+	.disable = cygnus_mipipll_chan_disable,
+	.recalc_rate = cygnus_mipipll_chan_recalc_rate,
+};
+
+static void __init cygnus_mipipll_ch_init(struct device_node *node)
+{
+	cygnus_clock_init(node, &cygnus_mipipll_chan_ops);
+}
+
+CLK_OF_DECLARE(cygnus_mipipll_ch, "brcm,cygnus-mipipll-ch",
+	cygnus_mipipll_ch_init);
diff --git a/drivers/clk/bcm/clk-iproc.c b/drivers/clk/bcm/clk-iproc.c
new file mode 100644
index 0000000..aca4851
--- /dev/null
+++ b/drivers/clk/bcm/clk-iproc.c
@@ -0,0 +1,451 @@
+/*
+ * Copyright 2014 Broadcom Corporation.  All rights reserved.
+ *
+ * Unless you and Broadcom execute a separate written software license
+ * agreement governing use of this software, this software is licensed to you
+ * under the terms of the GNU General Public License as
+ * published by the Free Software Foundation version 2.
+ *
+ * This program is distributed "as is" WITHOUT ANY WARRANTY of any
+ * kind, whether express or implied; without even the implied warranty
+ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/err.h>
+#include <linux/clk-provider.h>
+#include <linux/io.h>
+#include <linux/of.h>
+#include <linux/clkdev.h>
+#include <linux/of_address.h>
+
+#define IPROC_CLK_POLICY_FREQ_OFFSET    0x008
+#define IPROC_CLK_POLICY0_MSK_OFFSET    0x010
+#define IPROC_CLK_APB_SW_DIV_OFFSET     0xA10
+#define IPROC_CLK_PLL_ARMA_OFFSET       0xC00
+#define IPROC_CLK_PLL_ARMB_OFFSET       0xC04
+#define IPROC_CLK_PLL_ARMC_OFFSET       0xC08
+#define IPROC_CLK_PLL_ARMCTL5_OFFSET    0xC20
+#define IPROC_CLK_PLL_ARM_OFFSET_OFFSET 0xC24
+#define IPROC_CLK_ARM_DIV_OFFSET        0xE00
+#define IPROC_CLK_POLICY_DBG_OFFSET     0xEC0
+
+#define IPROC_CLK_ARM_DIV_ARM_PLL_SELECT_OVERRIDE_SHIFT        4
+#define IPROC_CLK_ARM_DIV_ARM_PLL_SELECT_MASK                  0xf
+#define IPROC_CLK_POLICY_FREQ_OFFSET_POLICY_FREQ_MASK          0xf
+#define IPROC_CLK_POLICY_FREQ_OFFSET_POLICY_FREQ_SHIFT         8
+#define IPROC_CLK_POLICY_DBG_OFFSET_ACT_FREQ_SHIFT             12
+#define IPROC_CLK_POLICY_DBG_OFFSET_ACT_FREQ_MASK              7
+#define IPROC_CLK_PLL_ARM_OFFSET_PLLARM_OFFSET_SW_CTL_SHIFT    29
+#define CLK_PLL_ARM_OFFSET_PLLARM_NDIV_INT_OFFSET              20
+#define CLK_PLL_ARM_OFFSET_PLLARM_NDIV_INT_MASK                0xff
+#define CLK_PLL_ARM_OFFSET_PLLARM_NDIV_FRAC_OFFSET             0xfffff
+#define CLK_PLL_ARMA_PLLARM_NDIV_INT_SHIFT                     8
+#define CLK_PLL_ARMA_PLLARM_NDIV_INT_MASK                      0x3ff
+#define CLK_PLL_ARMB_PLLARM_NDIV_FRAC_MASK                     0xfffff
+#define CLK_PLL_ARMC_PLLARM_MDIV_MASK                          0xff
+#define CLK_PLL_ARMCTL5_PLLARM_H_MDIV_MASK                     0xff
+#define CLK_PLL_ARMC_PLLARM_BYPCLK_EN_SHIFT                    8
+#define CLK_PLL_ARMA_PLLARM_PDIV_SHIFT                         24
+#define CLK_PLL_ARMA_PLLARM_PDIV_MASK                          0xf
+#define CLK_PLL_ARMA_PLLARM_LOCK_SHIFT                         28
+#define CLK_ARM_DIV_APB0_FREE_DIV_SHIFT                        8
+#define CLK_ARM_DIV_APB0_FREE_DIV_MASK                         0x7
+#define CLK_ARM_DIV_ARM_SWITCH_DIV_SHIFT                       8
+#define CLK_ARM_DIV_ARM_SWITCH_DIV_MASK                        0x3
+#define CLK_APB_SW_DIV_APB_CLK_DIV_MASK                        0x3
+
+struct brcm_clk {
+	struct clk_hw   hw;
+	void __iomem    *regs_base;
+	int             chan;
+	unsigned long   rate;
+};
+
+/* Identifies derived clocks from ARM PLL. */
+enum {
+	ARMPLL_APB0_FREE_CLK   = 0,
+	ARMPLL_ARM_SWITCH_CLK  = 1,
+	ARMPLL_ARM_APB_CLK     = 2,
+	ARMPLL_ARM_PERIPH_CLK  = 3
+};
+
+/* Frequency id's from policy0_freq field of POLICY_FREQ register. */
+enum a9pll_policy_freq {
+	PLL_CRYSTAL_CLK   = 0,
+	PLL_SYS_CLK       = 2,
+	PLL_CH0_SLOW_CLK  = 6,
+	PLL_CH1_FAST_CLK  = 7
+};
+
+#define to_brcm_clk(p) container_of(p, struct brcm_clk, hw)
+
+static int iproc_cru_arm_freq_id(void __iomem *regs_base)
+{
+	u32 reg_f, reg;
+	unsigned policy = 0;
+	unsigned fid;
+	unsigned active_freq;
+
+	/* Read policy frequency. */
+	reg_f = readl(regs_base + IPROC_CLK_POLICY_FREQ_OFFSET);
+
+	/* Check for PLL policy software override. */
+	reg = readl(regs_base + IPROC_CLK_ARM_DIV_OFFSET);
+	if (reg & (1 << IPROC_CLK_ARM_DIV_ARM_PLL_SELECT_OVERRIDE_SHIFT))
+		policy = reg & IPROC_CLK_ARM_DIV_ARM_PLL_SELECT_MASK;
+
+	/* Get frequency ID based on policy. */
+	fid = (reg_f >>
+		(IPROC_CLK_POLICY_FREQ_OFFSET_POLICY_FREQ_SHIFT * policy)) &
+		IPROC_CLK_POLICY_FREQ_OFFSET_POLICY_FREQ_MASK;
+
+	/* Verify freq id from debug register. */
+	reg = readl(regs_base + IPROC_CLK_POLICY_DBG_OFFSET);
+	/* Read current active frequency id. */
+	active_freq = IPROC_CLK_POLICY_DBG_OFFSET_ACT_FREQ_MASK &
+		(reg >> IPROC_CLK_POLICY_DBG_OFFSET_ACT_FREQ_SHIFT);
+
+	if (fid != active_freq) {
+		pr_debug("IPROC CRU clock frequency id override %d->%d\n",
+			fid, active_freq);
+
+		fid = active_freq;
+	}
+
+	pr_debug("Active frequency ID %d\n", fid);
+
+	return fid;
+}
+
+/*
+ * Get ndiv integer and combine with fractional part to create 64 bit
+ * value.
+ */
+static u64 a9pll_get_ndiv(struct brcm_clk *clk)
+{
+	u32 arm_offset_reg;
+	u32 pllarma_reg;
+	u32 pllarmb_reg;
+	u32 ndiv_int;
+	u32 ndiv_frac;
+	u64 ndiv;
+
+	arm_offset_reg = readl(clk->regs_base +
+		IPROC_CLK_PLL_ARM_OFFSET_OFFSET);
+
+    /*
+	 * Check if offset mode is active to determine which register to
+	 * get ndiv from.
+	 */
+	if (arm_offset_reg &
+		(1 << IPROC_CLK_PLL_ARM_OFFSET_PLLARM_OFFSET_SW_CTL_SHIFT)) {
+		/* Offset mode active. Get integer divide from offset reg. */
+		ndiv_int = (arm_offset_reg >>
+			CLK_PLL_ARM_OFFSET_PLLARM_NDIV_INT_OFFSET) &
+			CLK_PLL_ARM_OFFSET_PLLARM_NDIV_INT_MASK;
+
+		if (ndiv_int == 0)
+			ndiv_int = 256;
+
+		/* Get ndiv fractional divider. */
+		ndiv_frac = arm_offset_reg &
+			CLK_PLL_ARM_OFFSET_PLLARM_NDIV_FRAC_OFFSET;
+	} else {
+		/* Offset mode not active so read PLL ndiv from PLLARMA. */
+		pllarma_reg = readl(clk->regs_base + IPROC_CLK_PLL_ARMA_OFFSET);
+		ndiv_int = (pllarma_reg >> CLK_PLL_ARMA_PLLARM_NDIV_INT_SHIFT) &
+			CLK_PLL_ARMA_PLLARM_NDIV_INT_MASK;
+
+		if (ndiv_int == 0)
+			ndiv_int = 1024;
+
+		/* Get ndiv fractional divider. */
+		pllarmb_reg = readl(clk->regs_base + IPROC_CLK_PLL_ARMB_OFFSET);
+		ndiv_frac = pllarmb_reg & CLK_PLL_ARMB_PLLARM_NDIV_FRAC_MASK;
+	}
+
+	ndiv = ((u64) ndiv_int << 20) | ndiv_frac;
+
+	return ndiv;
+}
+
+/*
+ * Determine mdiv (post divider) based on the frequency id being used.
+ * There are 4 clocks that can be used to derive the output clock rate:
+ *    - 25 MHz crystal
+ *    - sys_clk
+ *    - channel 0 (slow clock)
+ *    - channel 1 (fast clock)
+ *
+ * If the slow clock is being used then mdiv is read from PLLARMC. If
+ * the fast clock is being used then the channel 1 mdiv is used.
+ * Otherwise there is no post divider.
+ *
+ * @return The mdiv value. -EIO if an error occurred.
+ */
+static int a9pll_get_mdiv(struct brcm_clk *clk)
+{
+	u32 mdiv;
+	u32 pllarmc_reg;
+	u32 armctl5_reg;
+	u32 freq_id;
+
+	/* Get the policy frequency. */
+	freq_id = iproc_cru_arm_freq_id(clk->regs_base);
+
+	switch (freq_id) {
+	/* There is no divider for these frequency id's. */
+	case PLL_CRYSTAL_CLK:
+	case PLL_SYS_CLK:
+		mdiv = 1;
+		break;
+
+	case PLL_CH0_SLOW_CLK: {
+	    /* Read mdiv (post-divider) from PLLARMC bits 0:7 */
+	    pllarmc_reg = readl(clk->regs_base + IPROC_CLK_PLL_ARMC_OFFSET);
+	    mdiv = pllarmc_reg & CLK_PLL_ARMC_PLLARM_MDIV_MASK;
+	    if (mdiv == 0)
+			mdiv = 256;
+		break;
+	}
+
+	case PLL_CH1_FAST_CLK: {
+		/* Post divider for channel 1 is in CTL5 (pllarm_h_mdiv). */
+		armctl5_reg = readl(clk->regs_base +
+			IPROC_CLK_PLL_ARMCTL5_OFFSET);
+	    mdiv = armctl5_reg & CLK_PLL_ARMCTL5_PLLARM_H_MDIV_MASK;
+	    if (mdiv == 0)
+			mdiv = 256;
+		break;
+	}
+
+	default:
+		return -EIO;
+	}
+
+	return mdiv;
+}
+
+/*
+ * Calculate the output frequency of the ARM PLL. The main output clock
+ * is 'arm_clk'.
+ *
+ * The frequency is calculated based on the ARM PLL divider values:
+ *	 pdiv = ARM PLL input pre-divider
+ *   ndiv = ARM PLL feedback divider
+ *   mdiv = ARM PLL post divider
+ *
+ * The frequency is calculated by:
+ *   ((ndiv * parent clock rate) / pdiv) / mdiv
+ */
+static int a9pll_status(struct brcm_clk *clk, unsigned long parent_rate)
+{
+	u32 pllarma_reg;
+	u32 pllarmc_reg;
+	u32 pdiv;
+	u32 mdiv;
+	u64 ndiv;
+	u32 arm_clk_freq;
+
+	pr_debug("a9pll_status: clk 0x%x\n", (unsigned int)clk);
+
+	BUG_ON(!clk->regs_base);
+
+	pllarma_reg = readl(clk->regs_base + IPROC_CLK_PLL_ARMA_OFFSET);
+	pllarmc_reg = readl(clk->regs_base + IPROC_CLK_PLL_ARMC_OFFSET);
+
+	/* Check if PLL is in bypass mode - input frequency to output */
+	if (pllarmc_reg & (1 << CLK_PLL_ARMC_PLLARM_BYPCLK_EN_SHIFT)) {
+		clk->rate = parent_rate;
+		return 0;
+	}
+
+	/* Check if PLL is locked. It must be unlocked. */
+	if ((pllarma_reg &
+		(1 << CLK_PLL_ARMA_PLLARM_LOCK_SHIFT)) == 0) {
+		clk->rate = 0;
+		return -EIO;
+	}
+
+	/* Read pdiv from PLLARMA. */
+	pdiv = (pllarma_reg >> CLK_PLL_ARMA_PLLARM_PDIV_SHIFT) &
+		CLK_PLL_ARMA_PLLARM_PDIV_MASK;
+	if (pdiv == 0)
+		pdiv = 16;
+
+	/* Determine ndiv. */
+	ndiv = a9pll_get_ndiv(clk);
+
+	/* Determine mdiv (post divider). */
+	mdiv = a9pll_get_mdiv(clk);
+	if (mdiv == -EIO) {
+		clk->rate = 0;
+		return -EIO;
+	}
+
+	/* Calculate clock frequency. */
+	arm_clk_freq = (ndiv * parent_rate) >> 20;
+	arm_clk_freq = (arm_clk_freq / pdiv) / mdiv;
+
+	clk->rate = arm_clk_freq;
+
+	pr_debug("ARM PLL (arm_clk) rate %lu. parent rate = %lu, ",
+		clk->rate, parent_rate);
+	pr_debug("ndiv_int = %d, pdiv = %d, mdiv = %d\n",
+		 (u32)ndiv >> 20, pdiv, mdiv);
+
+	return clk->rate;
+}
+
+static unsigned long clk_a9pll_recalc_rate(struct clk_hw *hwclk,
+	unsigned long parent_rate)
+{
+	struct brcm_clk *bcm_clk = to_brcm_clk(hwclk);
+
+	return a9pll_status(bcm_clk, parent_rate);
+}
+
+static const struct clk_ops a9pll_ops = {
+	.recalc_rate = clk_a9pll_recalc_rate,
+};
+
+/*
+ * Get status of any of the ARMPLL output channels
+ */
+static int a9pll_chan_status(struct brcm_clk *clk, unsigned long parent_rate)
+{
+	u32 reg;
+	unsigned div;
+
+	BUG_ON(!clk->regs_base);
+
+	reg = readl(clk->regs_base + IPROC_CLK_ARM_DIV_OFFSET);
+	pr_debug("Clock Div = %#x\n", reg);
+
+	switch (clk->chan) {
+	case ARMPLL_APB0_FREE_CLK:
+		/* apb0_free_div bits 10:8 */
+		div = (reg >> CLK_ARM_DIV_APB0_FREE_DIV_SHIFT) &
+			CLK_ARM_DIV_APB0_FREE_DIV_MASK;
+		div++;
+		break;
+
+	case ARMPLL_ARM_SWITCH_CLK:
+		/* arm_switch_div bits 6:5 */
+		div = (reg >> CLK_ARM_DIV_ARM_SWITCH_DIV_SHIFT) &
+			CLK_ARM_DIV_ARM_SWITCH_DIV_MASK;
+		div++;
+		break;
+
+	case ARMPLL_ARM_APB_CLK:
+		/* IPROC_CLK_APB_SW_DIV_REG apb_clk_div bits 1:0 */
+		reg = readl(clk->regs_base + IPROC_CLK_APB_SW_DIV_OFFSET);
+		div = reg & CLK_APB_SW_DIV_APB_CLK_DIV_MASK;
+		div++;
+		break;
+
+	case ARMPLL_ARM_PERIPH_CLK:      /* periph_clk */
+		div = 2;
+		break;
+
+	default:
+		return -EINVAL;
+	}
+
+	clk->rate = parent_rate / div;
+	pr_debug("Clock rate A9PLL chan 0x%x: %lu, div: %d\n",
+		clk->chan, clk->rate, div);
+
+	return clk->rate;
+}
+
+static unsigned long clk_a9pll_chan_recalc_rate(struct clk_hw *hwclk,
+	unsigned long parent_rate)
+{
+	struct brcm_clk *bcm_clk = to_brcm_clk(hwclk);
+
+	return a9pll_chan_status(bcm_clk, parent_rate);
+}
+
+static const struct clk_ops a9pll_chan_ops = {
+	.recalc_rate = clk_a9pll_chan_recalc_rate,
+};
+
+static __init struct clk *iproc_clock_init(struct device_node *node,
+	const struct clk_ops *ops)
+{
+	u32 channel = 0;
+	struct clk *clk;
+	struct brcm_clk *brcm_clk;
+	const char *clk_name = node->name;
+	const char *parent_name;
+	struct clk_init_data init;
+	int rc;
+
+	pr_debug("Clock name %s\n", node->name);
+
+	rc = of_property_read_u32(node, "channel", &channel);
+	brcm_clk = kzalloc(sizeof(*brcm_clk), GFP_KERNEL);
+	if (WARN_ON(!brcm_clk))
+		return NULL;
+
+	/* Read base address from device tree and map to virtual address. */
+	brcm_clk->regs_base = of_iomap(node, 0);
+	if (WARN_ON(!brcm_clk->regs_base))
+		goto err_alloc;
+
+	brcm_clk->chan = channel;
+	of_property_read_string(node, "clock-output-names", &clk_name);
+
+	init.name = clk_name;
+	init.ops = ops;
+	init.flags = 0;
+	parent_name = of_clk_get_parent_name(node, 0);
+	init.parent_names = &parent_name;
+	init.num_parents = 1;
+
+	brcm_clk->hw.init = &init;
+
+	clk = clk_register(NULL, &brcm_clk->hw);
+	if (WARN_ON(IS_ERR(clk)))
+		goto err_unmap;
+
+	rc = of_clk_add_provider(node, of_clk_src_simple_get, clk);
+	if (WARN_ON(IS_ERR_VALUE(rc)))
+		goto err_unregister;
+
+	rc = clk_register_clkdev(clk, clk_name, NULL);
+	if (WARN_ON(IS_ERR_VALUE(rc)))
+		goto err_provider;
+
+	return clk;
+
+err_provider:
+	of_clk_del_provider(node);
+
+err_unregister:
+	clk_unregister(clk);
+
+err_unmap:
+	iounmap(brcm_clk->regs_base);
+
+err_alloc:
+	kfree(brcm_clk);
+
+	return NULL;
+}
+
+static void __init iproc_armpll_init(struct device_node *node)
+{
+	iproc_clock_init(node, &a9pll_ops);
+}
+CLK_OF_DECLARE(iproc_armpllx, "brcm,iproc-arm-a9pll", iproc_armpll_init);
+
+static void __init iproc_arm_ch_init(struct device_node *node)
+{
+	iproc_clock_init(node, &a9pll_chan_ops);
+}
+CLK_OF_DECLARE(iproc_arm_ch, "brcm,iproc-arm-ch", iproc_arm_ch_init);
-- 
1.7.9.5


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

* [PATCH v2 3/6] dt-bindings: Document Broadcom Cygnus SoC and clock driver
  2014-09-23 21:17 ` [PATCH v2 " Jonathan Richardson
  2014-09-23 21:17   ` [PATCH v2 1/6] ARM: cygnus: Initial " Jonathan Richardson
  2014-09-23 21:17   ` [PATCH v2 2/6] clk: Clock driver " Jonathan Richardson
@ 2014-09-23 21:17   ` Jonathan Richardson
  2014-09-23 21:17   ` [PATCH v2 4/6] ARM: dts: Enable Broadcom Cygnus SoC Jonathan Richardson
                     ` (3 subsequent siblings)
  6 siblings, 0 replies; 92+ messages in thread
From: Jonathan Richardson @ 2014-09-23 21:17 UTC (permalink / raw)
  To: Christian Daudt, Matt Porter, Russell King, Mike Turquette,
	Rob Herring, Pawel Moll, Mark Rutland, Ian Campbell, Kumar Gala,
	JD Zheng
  Cc: linux-arm-kernel, bcm-kernel-feedback-list, linux-kernel,
	devicetree, Scott Branden, Ray Jui, Jonathan Richardson

Reviewed-by: Arun Parameswaran <aparames@broadcom.com>
Tested-by: Jonathan Richardson <jonathar@broadcom.com>
Reviewed-by: JD (Jiandong) Zheng <jdzheng@broadcom.com>
Signed-off-by: Jonathan Richardson <jonathar@broadcom.com>
---
 Documentation/devicetree/bindings/arm/cygnus.txt   |   12 ++
 .../devicetree/bindings/clock/clk-cygnus.txt       |  121 ++++++++++++++++++++
 .../devicetree/bindings/clock/clk-iproc.txt        |   48 ++++++++
 3 files changed, 181 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/arm/cygnus.txt
 create mode 100644 Documentation/devicetree/bindings/clock/clk-cygnus.txt
 create mode 100644 Documentation/devicetree/bindings/clock/clk-iproc.txt

diff --git a/Documentation/devicetree/bindings/arm/cygnus.txt b/Documentation/devicetree/bindings/arm/cygnus.txt
new file mode 100644
index 0000000..a210377
--- /dev/null
+++ b/Documentation/devicetree/bindings/arm/cygnus.txt
@@ -0,0 +1,12 @@
+Broadcom Cygnus device tree bindings
+------------------------------------
+
+All Cygnus boards shall have the following properties:
+
+Required root node property:
+	- compatible = "brcm,cygnus";
+
+Boards variants shall have the following additional properties:
+
+Required root node property for the BCM911360_ENTPHN board:
+	- compatible = "brcm,bcm911360_entphn";
diff --git a/Documentation/devicetree/bindings/clock/clk-cygnus.txt b/Documentation/devicetree/bindings/clock/clk-cygnus.txt
new file mode 100644
index 0000000..7e03837
--- /dev/null
+++ b/Documentation/devicetree/bindings/clock/clk-cygnus.txt
@@ -0,0 +1,121 @@
+Broadcom Cygnus Clock Controller
+
+This binding uses the common clock binding:
+Documentation/devicetree/bindings/clock/clock-bindings.txt
+
+The Cygnus clock controller manages several PLL's and their channels, found only
+on the Cygnus chip. Clocks that are common to iProc can be found in the iProc
+clock controller. The controllers are split into a parent-child relationship
+where the parent is the PLL and the child controls the PLL's channels.
+
+All PLL's are derived from a 25MHz oscillator. The PLL's controlled are the
+GENPLL, LCPLL, the MIPI PLL. In addition, there are two clocks derived from
+GENPLL channel 0, and three that are derived directly from the oscillator.
+
+Required properties:
+- compatible: Must be one of the following:
+    "brcm,cygnus-lcpll-clk" - Controls LCPLL.
+    "brcm,cygnus-lcpll-ch" -  Controls LCPLL (parent) channels
+    "brcm,cygnus-genpll-clk" - Controls parent GENPLL
+    "brcm,cygnus-genpll-ch" - Controls GENPLL (parent) channels
+    "brcm,cygnus-mipipll-clk" - Controls MIPI PLL
+    "brcm,cygnus-mipipll-ch" - Controls parent MIPI PLL (parent) channels
+    "brcm,cygnus-osc-derived" - Controls oscillator (parent) derived channels
+        not controlled by any PLL.
+    "brcm,cygnus-pll-derived" - Controls clocks derived from GENPLL channel 0.
+	  These clocks have hard wired internal dividers and their clock rates
+	  scale according to the GENPLL channel.
+
+- reg: First register is the base address of the PLL. Register 2 and 3 are
+  required by some clocks. They are the top clock gating control used to
+  enable/disable clocks (ch 1), and the CRMU PLL AON CONTROL register which
+  powers on PLL/LDO's (ch 2).
+
+- clocks: The input parent clock phandle for the clock. This is either a PLL,
+  oscillator, or GENPLL channel 0.
+
+- channel: The PLL channel that the clock belongs to. This is used for
+  "brcm,cygnus-lcpll-ch", "brcm,cygnus-genpll-ch", "brcm,cygnus-mipipll-ch",
+  "brcm,cygnus-osc-derived" only.
+
+- div: Used by "brcm,cygnus-pll-derived" to define the hard coded internal
+  divider value. Used by "brcm,cygnus-osc-derived" to specify the programmable
+  divider.
+
+- #clock-cells: From common clock binding; shall be set to 0.
+
+Examples:
+
+		osc: oscillator {
+			#clock-cells = <0>;
+			compatible = "fixed-clock";
+			clock-frequency = <25000000>;
+		};
+
+		lcpll: lcpll@0301d02c {
+			#clock-cells = <0>;
+			compatible = "brcm,cygnus-lcpll-clk";
+			reg = <0x0301d02c 0x1c>;
+			clocks = <&osc>;
+		};
+
+		genpll: genpll@0301d000 {
+			#clock-cells = <0>;
+			compatible = "brcm,cygnus-genpll-clk";
+			reg = <0x0301d000 0x2c>,
+				  <0x180AA024 0x4>,
+				  <0x0301C020 0x4>;
+			clocks = <&osc>;
+		};
+
+		axi21_clk: genpll_ch0@0301d000 {
+			#clock-cells = <0>;
+			compatible = "brcm,cygnus-genpll-ch";
+			reg = <0x0301d000 0x2c>;
+			clocks = <&genpll>;
+			channel = <0>;
+		};
+
+		pcie_clk: lcpll_ch0@0301d02c {
+			compatible = "brcm,cygnus-lcpll-ch";
+			reg = <0x0301d02c 0x1c>;
+			#clock-cells = <0>;
+			clocks = <&lcpll>;
+			channel = <0>;
+		};
+
+		axi41_clk: axi41_clk {
+			reg = <0x0301d000 0x2c>;
+			#clock-cells = <0>;
+			compatible = "brcm,cygnus-pll-derived";
+			clocks = <&axi21_clk>;
+			div = <2>;
+		};
+
+		keypad_clk: keypad_clk@0301D048 {
+			compatible = "brcm,cygnus-osc-derived";
+			reg = <0x0301D048 0x4>,
+				  <0x180AA024 0x4>;
+			#clock-cells = <0>;
+			clocks = <&osc>;
+			channel = <0>;
+			div = <392>;
+		};
+
+		mipipll: mipipll@180a9800 {
+			#clock-cells = <0>;
+			compatible = "brcm,cygnus-mipipll-clk";
+			reg = <0x180a9800 0x2c>,
+				  top_clk_gating_ctrl: <0x180AA024 0x4>,
+				  crmu_pll_aon_ctrl: <0x0301C020 0x4>;
+			clocks = <&osc>;
+		};
+
+		lcd_clk: mipipll_ch1@180a9800 {
+			#clock-cells = <0>;
+			compatible = "brcm,cygnus-mipipll-ch";
+			reg = <0x180a9800 0x2c>,
+				  <0x180AA024 0x4>;
+			clocks = <&mipipll>;
+			channel = <1>;
+		};
diff --git a/Documentation/devicetree/bindings/clock/clk-iproc.txt b/Documentation/devicetree/bindings/clock/clk-iproc.txt
new file mode 100644
index 0000000..b5d4f08
--- /dev/null
+++ b/Documentation/devicetree/bindings/clock/clk-iproc.txt
@@ -0,0 +1,48 @@
+Broadcom iProc Clock Controller
+
+This binding uses the common clock binding:
+Documentation/devicetree/bindings/clock/clock-bindings.txt
+
+The iProc clock controller manages clocks that are common to iProc chips.
+The controllers are split into a parent-child relationship where the parent is
+the PLL and the child controls the PLL's channels.
+
+The only PLL controlled is the ARM PLL which is derived from a 25MHz crystal.
+
+Required properties:
+- compatible: Must be one of the following:
+    "brcm,iproc-arm-a9pll" - Controls ARM PLL.
+    "brcm,iproc-arm-ch" -  Controls ARM PLL (parent) channels
+
+- reg: The base address of the PLL.
+
+- clocks: The input parent clock phandle for the clock. This is either a PLL,
+  or oscillator.
+
+- channel: The PLL channel that the clock belongs to. This is used for
+  "brcm,iproc-arm-ch" only.
+
+- #clock-cells: From common clock binding; shall be set to 0.
+
+Example:
+
+	osc: oscillator {
+		#clock-cells = <0>;
+		compatible = "fixed-clock";
+		clock-frequency = <25000000>;
+	};
+
+	a9pll: arm_clk@19000000 {
+		compatible = "brcm,iproc-arm-a9pll";
+		reg = <0x19000000 0x1000>;
+		#clock-cells = <0>;
+		clocks = <&osc>;
+	};
+
+	periph_clk: periph_clk@19000000 {
+		compatible = "brcm,iproc-arm-ch";
+		reg = <0x19000000 0x1000>;
+		#clock-cells = <0>;
+		clocks = <&a9pll>;
+		channel = <3>;
+	};
-- 
1.7.9.5


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

* [PATCH v2 4/6] ARM: dts: Enable Broadcom Cygnus SoC
  2014-09-23 21:17 ` [PATCH v2 " Jonathan Richardson
                     ` (2 preceding siblings ...)
  2014-09-23 21:17   ` [PATCH v2 3/6] dt-bindings: Document Broadcom Cygnus SoC and clock driver Jonathan Richardson
@ 2014-09-23 21:17   ` Jonathan Richardson
  2014-09-23 21:17   ` [PATCH v2 5/6] ARM: cygnus defconfig : Initial defconfig for " Jonathan Richardson
                     ` (2 subsequent siblings)
  6 siblings, 0 replies; 92+ messages in thread
From: Jonathan Richardson @ 2014-09-23 21:17 UTC (permalink / raw)
  To: Christian Daudt, Matt Porter, Russell King, Mike Turquette,
	Rob Herring, Pawel Moll, Mark Rutland, Ian Campbell, Kumar Gala,
	JD Zheng
  Cc: linux-arm-kernel, bcm-kernel-feedback-list, linux-kernel,
	devicetree, Scott Branden, Ray Jui, Jonathan Richardson

DT files to enable cygnus consisting of the enterprise phone board variant and
cygnus core configuration.

Reviewed-by: Ray Jui <rjui@broadcom.com>
Reviewed-by: Arun Parameswaran <aparames@broadcom.com>
Reviewed-by: Scott Branden <sbranden@broadcom.com>
Tested-by: Jonathan Richardson <jonathar@broadcom.com>
Reviewed-by: JD (Jiandong) Zheng <jdzheng@broadcom.com>
Signed-off-by: Jonathan Richardson <jonathar@broadcom.com>
---
 arch/arm/boot/dts/Makefile             |    1 +
 arch/arm/boot/dts/bcm-cygnus.dtsi      |  349 ++++++++++++++++++++++++++++++++
 arch/arm/boot/dts/bcm911360_entphn.dts |   22 ++
 3 files changed, 372 insertions(+)
 create mode 100644 arch/arm/boot/dts/bcm-cygnus.dtsi
 create mode 100644 arch/arm/boot/dts/bcm911360_entphn.dts

diff --git a/arch/arm/boot/dts/Makefile b/arch/arm/boot/dts/Makefile
index b8c5cd3..b95d41d 100644
--- a/arch/arm/boot/dts/Makefile
+++ b/arch/arm/boot/dts/Makefile
@@ -52,6 +52,7 @@ dtb-$(CONFIG_ARCH_AT91)	+= sama5d36ek.dtb
 dtb-$(CONFIG_ARCH_ATLAS6) += atlas6-evb.dtb
 dtb-$(CONFIG_ARCH_AXXIA) += axm5516-amarillo.dtb
 dtb-$(CONFIG_ARCH_BCM2835) += bcm2835-rpi-b.dtb
+dtb-$(CONFIG_ARCH_BCM_CYGNUS) += bcm911360_entphn.dtb
 dtb-$(CONFIG_ARCH_BCM_5301X) += bcm4708-netgear-r6250.dtb
 dtb-$(CONFIG_ARCH_BCM_MOBILE) += bcm28155-ap.dtb \
 	bcm21664-garnet.dtb
diff --git a/arch/arm/boot/dts/bcm-cygnus.dtsi b/arch/arm/boot/dts/bcm-cygnus.dtsi
new file mode 100644
index 0000000..81da0d8
--- /dev/null
+++ b/arch/arm/boot/dts/bcm-cygnus.dtsi
@@ -0,0 +1,349 @@
+/*
+ * Copyright 2014 Broadcom Corporation.  All rights reserved.
+ *
+ * Unless you and Broadcom execute a separate written software license
+ * agreement governing use of this software, this software is licensed to you
+ * under the terms of the GNU General Public License as
+ * published by the Free Software Foundation version 2.
+ *
+ * This program is distributed "as is" WITHOUT ANY WARRANTY of any
+ * kind, whether express or implied; without even the implied warranty
+ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <dt-bindings/interrupt-controller/arm-gic.h>
+#include <dt-bindings/interrupt-controller/irq.h>
+
+#include "skeleton.dtsi"
+
+/ {
+	compatible = "brcm,cygnus";
+	model = "Broadcom Cygnus SoC";
+	interrupt-parent = <&gic>;
+
+	aliases {
+		serial0 = &uart3;
+		serial1 = &uart0;
+	};
+
+	chosen {
+		bootargs = "console=ttyS0,115200 earlyprintk debug";
+	};
+
+	cpus {
+		#address-cells = <1>;
+		#size-cells = <0>;
+
+		cpu@0 {
+			device_type = "cpu";
+			compatible = "arm,cortex-a9";
+			next-level-cache = <&L2>;
+			reg = <0x0>;
+		};
+	};
+
+	clocks {
+		#address-cells = <1>;
+		#size-cells = <1>;
+		ranges;
+
+		osc: oscillator {
+			#clock-cells = <0>;
+			compatible = "fixed-clock";
+			clock-frequency = <25000000>;
+		};
+
+		lcpll: lcpll@0301d02c {
+			#clock-cells = <0>;
+			compatible = "brcm,cygnus-lcpll-clk";
+			reg = <0x0301d02c 0x1c>;
+			clocks = <&osc>;
+		};
+
+		genpll: genpll@0301d000 {
+			#clock-cells = <0>;
+			compatible = "brcm,cygnus-genpll-clk";
+			reg = <0x0301d000 0x2c>,
+				  <0x180AA024 0x4>,
+				  <0x0301C020 0x4>;
+			clocks = <&osc>;
+		};
+
+		axi21_clk: genpll_ch0@0301d000 {
+			#clock-cells = <0>;
+			compatible = "brcm,cygnus-genpll-ch";
+			reg = <0x0301d000 0x2c>;
+			clocks = <&genpll>;
+			channel = <0>;
+		};
+
+		clk_25MHz: genpll_ch1@0301d000 {
+			#clock-cells = <0>;
+			compatible = "brcm,cygnus-genpll-ch";
+			reg = <0x0301d000 0x2c>;
+			clocks = <&genpll>;
+			channel = <1>;
+		};
+
+		sys_clk: genpll_ch2@0301d000 {
+			#clock-cells = <0>;
+			compatible = "brcm,cygnus-genpll-ch";
+			reg = <0x0301d000 0x2c>;
+			clocks = <&genpll>;
+			channel = <2>;
+		};
+
+		ethernet_clk: genpll_ch3@0301d000 {
+			#clock-cells = <0>;
+			compatible = "brcm,cygnus-genpll-ch";
+			reg = <0x0301d000 0x2c>;
+			clocks = <&genpll>;
+			channel = <3>;
+		};
+
+		asiu_audio_clk: genpll_ch4@0301d000 {
+			#clock-cells = <0>;
+			compatible = "brcm,cygnus-genpll-ch";
+			reg = <0x0301d000 0x2c>;
+			clocks = <&genpll>;
+			channel = <4>;
+		};
+
+		asiu_can_clk: genpll_ch5@0301d000 {
+			#clock-cells = <0>;
+			compatible = "brcm,cygnus-genpll-ch";
+			reg = <0x0301d000 0x2c>;
+			clocks = <&genpll>;
+			channel = <5>;
+		};
+
+		pcie_clk: lcpll_ch0@0301d02c {
+			compatible = "brcm,cygnus-lcpll-ch";
+			reg = <0x0301d02c 0x1c>;
+			#clock-cells = <0>;
+			clocks = <&lcpll>;
+			channel = <0>;
+		};
+
+		ddr_clk: lcpll_ch1@0301d02c {
+			compatible = "brcm,cygnus-lcpll-ch";
+			reg = <0x0301d02c 0x1c>;
+			#clock-cells = <0>;
+			clocks = <&lcpll>;
+			channel = <1>;
+		};
+
+		sdio_clk: lcpll_ch2@0301d02c {
+			compatible = "brcm,cygnus-lcpll-ch";
+			reg = <0x0301d02c 0x1c>;
+			#clock-cells = <0>;
+			clocks = <&lcpll>;
+			channel = <2>;
+		};
+
+		usb_clk: lcpll_ch3@0301d02c {
+		    compatible = "brcm,cygnus-lcpll-ch";
+			reg = <0x0301d02c 0x1c>;
+			#clock-cells = <0>;
+			clocks = <&lcpll>;
+			channel = <3>;
+		};
+
+		smart_card_clk: lcpll_ch4@0301d02c {
+			compatible = "brcm,cygnus-lcpll-ch";
+			reg = <0x0301d02c 0x1c>;
+			#clock-cells = <0>;
+			clocks = <&lcpll>;
+			channel = <4>;
+		};
+
+		ch5_unknown_clk: lcpll_ch5@0301d02c {
+			compatible = "brcm,cygnus-lcpll-ch";
+			reg = <0x0301d02c 0x1c>;
+			#clock-cells = <0>;
+			clocks = <&lcpll>;
+			channel = <5>;
+		};
+
+		/*
+		 * There are 2 clocks derived from genpll ch0 (axi21) which are
+		 * divided internally by 2 and 4. If axi21 clock rate changes, these
+		 * derived clock rates scale accordingly.
+		 */
+
+		axi41_clk: axi41_clk {
+			reg = <0x0301d000 0x2c>;
+			#clock-cells = <0>;
+			compatible = "brcm,cygnus-pll-derived";
+			clocks = <&axi21_clk>;
+			div = <2>;
+		};
+
+		axi81_clk: axi81_clk {
+			reg = <0x0301d000 0x2c>;
+			#clock-cells = <0>;
+			compatible = "brcm,cygnus-pll-derived";
+			clocks = <&axi21_clk>;
+			div = <4>;
+		};
+
+		/*
+		 * The main output of the ARM PLL is arm_clk with several derived
+		 * child clocks:
+		 * 		periph_clk
+		 * 		apb_clk
+		 * 		arm_switch
+		 * 		apb0_free
+		 */
+		a9pll: arm_clk@19000000 {
+			compatible = "brcm,iproc-arm-a9pll";
+			reg = <0x19000000 0x1000>;
+			#clock-cells = <0>;
+			clocks = <&osc>;
+		};
+
+		periph_clk: periph_clk@19000000 {
+			compatible = "brcm,iproc-arm-ch";
+			reg = <0x19000000 0x1000>;
+			#clock-cells = <0>;
+			clocks = <&a9pll>;
+			channel = <3>;
+		};
+
+		apb0_free: apb0_free@19000000 {
+			compatible = "brcm,iproc-arm-ch";
+			reg = <0x19000000 0x1000>;
+			#clock-cells = <0>;
+			clocks = <&a9pll>;
+			channel = <0>;
+		};
+
+		arm_switch: arm_switch@19000000 {
+			compatible = "brcm,iproc-arm-ch";
+			reg = <0x19000000 0x1000>;
+			#clock-cells = <0>;
+			clocks = <&a9pll>;
+			channel = <1>;
+		};
+
+		apb_clk: apb_clk@19000000 {
+			compatible = "brcm,iproc-arm-ch";
+			reg = <0x19000000 0x1000>;
+			#clock-cells = <0>;
+			clocks = <&a9pll>;
+			channel = <2>;
+		};
+
+		/*
+		 * Clocks derived from oscillator.
+		 */
+		keypad_clk: keypad_clk@0301D048 {
+			compatible = "brcm,cygnus-osc-derived";
+			reg = <0x0301D048 0x4>,
+				  <0x180AA024 0x4>;
+			#clock-cells = <0>;
+			clocks = <&osc>;
+			channel = <0>;
+			div = <392>;
+		};
+
+		adc_clk: adc_clk@0301D04C {
+			compatible = "brcm,cygnus-osc-derived";
+			reg = <0x0301D04C 0x4>,
+				  <0x180AA024 0x4>;
+			#clock-cells = <0>;
+			clocks = <&osc>;
+			channel = <1>;
+		};
+
+		pwm_clk: pwm_clk@0301D050 {
+			compatible = "brcm,cygnus-osc-derived";
+			reg = <0x0301D050 0x4>,
+				  <0x180AA024 0x4>;
+			#clock-cells = <0>;
+			clocks = <&osc>;
+			channel = <2>;
+		};
+
+		mipipll: mipipll@180a9800 {
+			#clock-cells = <0>;
+			compatible = "brcm,cygnus-mipipll-clk";
+			reg = <0x180a9800 0x2c>,
+				  top_clk_gating_ctrl: <0x180AA024 0x4>,
+				  crmu_pll_aon_ctrl: <0x0301C020 0x4>;
+			clocks = <&osc>;
+		};
+
+		lcd_clk: mipipll_ch1@180a9800 {
+			#clock-cells = <0>;
+			compatible = "brcm,cygnus-mipipll-ch";
+			reg = <0x180a9800 0x2c>,
+				  <0x180AA024 0x4>;
+			clocks = <&mipipll>;
+			channel = <1>;
+		};
+	};
+
+	amba {
+		#address-cells = <1>;
+		#size-cells = <1>;
+		compatible = "arm,amba-bus", "simple-bus";
+		interrupt-parent = <&gic>;
+		ranges;
+
+		wdt@18009000 {
+			 compatible = "arm,sp805" , "arm,primecell";
+			 reg = <0x18009000 0x1000>;
+			 interrupts = <GIC_SPI 91 IRQ_TYPE_LEVEL_HIGH>;
+			 clocks = <&axi81_clk>;
+			 clock-names = "apb_pclk";
+		};
+	};
+
+	uart3: serial@18023000 {
+		compatible = "snps,dw-apb-uart";
+		reg = <0x18023000 0x100>;
+		reg-shift = <2>;
+		reg-io-width = <4>;
+		interrupts = <GIC_SPI 76 IRQ_TYPE_LEVEL_HIGH>;
+		clock-frequency = <100000000>;
+		clocks = <&axi81_clk>;
+		status = "okay";
+	};
+
+	uart0: serial@18020000 {
+		compatible = "snps,dw-apb-uart";
+		reg = <0x18020000 0x100>;
+		reg-shift = <2>;
+		reg-io-width = <4>;
+		interrupts = <GIC_SPI 73 IRQ_TYPE_LEVEL_HIGH>;
+		clocks = <&axi81_clk>;
+		clock-frequency = <100000000>;
+		status = "okay";
+	};
+
+	gic: interrupt-controller@19021000 {
+		compatible = "arm,cortex-a9-gic";
+		#interrupt-cells = <3>;
+		#address-cells = <0>;
+		interrupt-controller;
+		reg = <0x19021000 0x1000>,
+		      <0x19020100 0x100>;
+	};
+
+	L2: l2-cache {
+		compatible = "arm,pl310-cache";
+		reg = <0x19022000 0x1000>;
+		cache-unified;
+		cache-level = <2>;
+	};
+
+	timer@19020200 {
+		compatible = "arm,cortex-a9-global-timer";
+		reg = <0x19020200 0x100>;
+		interrupts = <GIC_PPI 11 IRQ_TYPE_LEVEL_HIGH>;
+		clocks = <&periph_clk>;
+	};
+
+};
diff --git a/arch/arm/boot/dts/bcm911360_entphn.dts b/arch/arm/boot/dts/bcm911360_entphn.dts
new file mode 100644
index 0000000..cee4aff
--- /dev/null
+++ b/arch/arm/boot/dts/bcm911360_entphn.dts
@@ -0,0 +1,22 @@
+/*
+ * Copyright 2014 Broadcom Corporation.  All rights reserved.
+ *
+ * Unless you and Broadcom execute a separate written software license
+ * agreement governing use of this software, this software is licensed to you
+ * under the terms of the GNU General Public License as
+ * published by the Free Software Foundation version 2.
+ *
+ * This program is distributed "as is" WITHOUT ANY WARRANTY of any
+ * kind, whether express or implied; without even the implied warranty
+ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+/dts-v1/;
+
+#include "bcm-cygnus.dtsi"
+
+/ {
+	model = "Cygnus Enterprise Phone (BCM911360_ENTPHN)";
+	compatible = "brcm,bcm911360_entphn", "brcm,cygnus";
+};
-- 
1.7.9.5


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

* [PATCH v2 5/6] ARM: cygnus defconfig : Initial defconfig for Broadcom Cygnus SoC
  2014-09-23 21:17 ` [PATCH v2 " Jonathan Richardson
                     ` (3 preceding siblings ...)
  2014-09-23 21:17   ` [PATCH v2 4/6] ARM: dts: Enable Broadcom Cygnus SoC Jonathan Richardson
@ 2014-09-23 21:17   ` Jonathan Richardson
  2014-09-23 21:17   ` [PATCH v2 6/6] MAINTAINERS: Entry for Cygnus/iproc arm architecture and clock drivers Jonathan Richardson
  2014-09-25 21:04   ` [PATCH v2 0/6] Add initial support for Broadcom Cygnus SoC Scott Branden
  6 siblings, 0 replies; 92+ messages in thread
From: Jonathan Richardson @ 2014-09-23 21:17 UTC (permalink / raw)
  To: Christian Daudt, Matt Porter, Russell King, Mike Turquette,
	Rob Herring, Pawel Moll, Mark Rutland, Ian Campbell, Kumar Gala,
	JD Zheng
  Cc: linux-arm-kernel, bcm-kernel-feedback-list, linux-kernel,
	devicetree, Scott Branden, Ray Jui, Jonathan Richardson

Tested-by: Jonathan Richardson <jonathar@broadcom.com>
Reviewed-by: JD (Jiandong) Zheng <jdzheng@broadcom.com>
Signed-off-by: Jonathan Richardson <jonathar@broadcom.com>
---
 arch/arm/configs/bcm_cygnus_defconfig |  223 +++++++++++++++++++++++++++++++++
 1 file changed, 223 insertions(+)
 create mode 100644 arch/arm/configs/bcm_cygnus_defconfig

diff --git a/arch/arm/configs/bcm_cygnus_defconfig b/arch/arm/configs/bcm_cygnus_defconfig
new file mode 100644
index 0000000..effed85
--- /dev/null
+++ b/arch/arm/configs/bcm_cygnus_defconfig
@@ -0,0 +1,223 @@
+CONFIG_KERNEL_XZ=y
+# CONFIG_SWAP is not set
+CONFIG_SYSVIPC=y
+CONFIG_IRQ_DOMAIN_DEBUG=y
+CONFIG_HIGH_RES_TIMERS=y
+CONFIG_BSD_PROCESS_ACCT=y
+CONFIG_BSD_PROCESS_ACCT_V3=y
+CONFIG_IKCONFIG=y
+CONFIG_IKCONFIG_PROC=y
+CONFIG_LOG_BUF_SHIFT=19
+CONFIG_CGROUPS=y
+CONFIG_CGROUP_FREEZER=y
+CONFIG_CGROUP_DEVICE=y
+CONFIG_CGROUP_CPUACCT=y
+CONFIG_RESOURCE_COUNTERS=y
+CONFIG_CGROUP_SCHED=y
+CONFIG_BLK_CGROUP=y
+CONFIG_NAMESPACES=y
+CONFIG_BLK_DEV_INITRD=y
+CONFIG_SYSCTL_SYSCALL=y
+CONFIG_EMBEDDED=y
+CONFIG_PERF_EVENTS=y
+# CONFIG_COMPAT_BRK is not set
+CONFIG_MODULES=y
+CONFIG_MODULE_UNLOAD=y
+# CONFIG_BLK_DEV_BSG is not set
+CONFIG_PARTITION_ADVANCED=y
+CONFIG_ARCH_BCM=y
+CONFIG_ARCH_BCM_IPROC=y
+CONFIG_ARCH_BCM_CYGNUS=y
+CONFIG_ARM_THUMBEE=y
+CONFIG_PREEMPT=y
+CONFIG_AEABI=y
+CONFIG_HIGHMEM=y
+# CONFIG_COMPACTION is not set
+# CONFIG_ATAGS is not set
+CONFIG_ZBOOT_ROM_TEXT=0x0
+CONFIG_ZBOOT_ROM_BSS=0x0
+CONFIG_ARM_APPENDED_DTB=y
+CONFIG_CPU_IDLE=y
+CONFIG_VFP=y
+CONFIG_NEON=y
+# CONFIG_SUSPEND is not set
+CONFIG_NET=y
+CONFIG_PACKET=y
+CONFIG_UNIX=y
+CONFIG_INET=y
+CONFIG_IP_MULTICAST=y
+CONFIG_IP_ADVANCED_ROUTER=y
+CONFIG_IP_MULTIPLE_TABLES=y
+CONFIG_IP_ROUTE_MULTIPATH=y
+CONFIG_IP_ROUTE_VERBOSE=y
+CONFIG_IP_PNP=y
+CONFIG_IP_PNP_DHCP=y
+CONFIG_IP_MROUTE=y
+CONFIG_IP_MROUTE_MULTIPLE_TABLES=y
+CONFIG_SYN_COOKIES=y
+# CONFIG_INET_XFRM_MODE_TRANSPORT is not set
+# CONFIG_INET_XFRM_MODE_TUNNEL is not set
+# CONFIG_INET_XFRM_MODE_BEET is not set
+# CONFIG_INET_LRO is not set
+# CONFIG_INET_DIAG is not set
+CONFIG_TCP_CONG_ADVANCED=y
+# CONFIG_TCP_CONG_BIC is not set
+# CONFIG_TCP_CONG_WESTWOOD is not set
+# CONFIG_TCP_CONG_HTCP is not set
+CONFIG_IPV6=y
+# CONFIG_INET6_XFRM_MODE_TRANSPORT is not set
+# CONFIG_INET6_XFRM_MODE_TUNNEL is not set
+# CONFIG_INET6_XFRM_MODE_BEET is not set
+# CONFIG_IPV6_SIT is not set
+CONFIG_IPV6_MULTIPLE_TABLES=y
+CONFIG_IPV6_SUBTREES=y
+CONFIG_IPV6_MROUTE=y
+CONFIG_NETFILTER=y
+# CONFIG_BRIDGE_NETFILTER is not set
+CONFIG_NF_CONNTRACK=y
+# CONFIG_NF_CONNTRACK_PROCFS is not set
+CONFIG_NF_CONNTRACK_FTP=y
+CONFIG_NF_CONNTRACK_IPV4=y
+CONFIG_IP_NF_IPTABLES=y
+CONFIG_IP_NF_FILTER=y
+CONFIG_IP_NF_TARGET_REJECT=y
+CONFIG_NF_NAT_IPV4=y
+CONFIG_IP_NF_TARGET_MASQUERADE=y
+CONFIG_IP_NF_TARGET_REDIRECT=y
+CONFIG_IP_NF_MANGLE=y
+CONFIG_IP_NF_RAW=y
+CONFIG_NF_CONNTRACK_IPV6=y
+CONFIG_IP6_NF_IPTABLES=y
+CONFIG_IP6_NF_MATCH_AH=y
+CONFIG_IP6_NF_MATCH_EUI64=y
+CONFIG_IP6_NF_MATCH_FRAG=y
+CONFIG_IP6_NF_MATCH_OPTS=y
+CONFIG_IP6_NF_MATCH_IPV6HEADER=y
+CONFIG_IP6_NF_MATCH_MH=y
+CONFIG_IP6_NF_MATCH_RT=y
+CONFIG_IP6_NF_FILTER=y
+CONFIG_IP6_NF_TARGET_REJECT=y
+CONFIG_IP6_NF_MANGLE=y
+CONFIG_IP6_NF_RAW=y
+CONFIG_BRIDGE=y
+# CONFIG_BRIDGE_IGMP_SNOOPING is not set
+CONFIG_VLAN_8021Q=y
+CONFIG_NET_SCHED=y
+CONFIG_NET_SCH_FQ_CODEL=y
+CONFIG_DEVTMPFS=y
+CONFIG_DEVTMPFS_MOUNT=y
+# CONFIG_FIRMWARE_IN_KERNEL is not set
+CONFIG_MTD=y
+CONFIG_MTD_CMDLINE_PARTS=y
+CONFIG_MTD_BLOCK=y
+CONFIG_MTD_NAND=y
+CONFIG_MTD_UBI=y
+# CONFIG_BLK_DEV is not set
+CONFIG_SCSI=y
+CONFIG_BLK_DEV_SD=y
+CONFIG_SCSI_MULTI_LUN=y
+CONFIG_NETDEVICES=y
+# CONFIG_NET_CADENCE is not set
+# CONFIG_NET_VENDOR_CIRRUS is not set
+# CONFIG_NET_VENDOR_FARADAY is not set
+# CONFIG_NET_VENDOR_INTEL is not set
+# CONFIG_NET_VENDOR_MARVELL is not set
+# CONFIG_NET_VENDOR_MICREL is not set
+# CONFIG_NET_VENDOR_NATSEMI is not set
+# CONFIG_NET_VENDOR_SEEQ is not set
+# CONFIG_NET_VENDOR_SMSC is not set
+# CONFIG_NET_VENDOR_STMICRO is not set
+# CONFIG_NET_VENDOR_WIZNET is not set
+CONFIG_PHYLIB=y
+CONFIG_BROADCOM_PHY=y
+# CONFIG_INPUT_MOUSEDEV is not set
+# CONFIG_KEYBOARD_ATKBD is not set
+# CONFIG_INPUT_MOUSE is not set
+# CONFIG_SERIO is not set
+# CONFIG_LEGACY_PTYS is not set
+CONFIG_SERIAL_8250=y
+# CONFIG_SERIAL_8250_DEPRECATED_OPTIONS is not set
+CONFIG_SERIAL_8250_CONSOLE=y
+CONFIG_SERIAL_8250_NR_UARTS=2
+CONFIG_SERIAL_8250_RUNTIME_UARTS=2
+CONFIG_SERIAL_8250_DW=y
+CONFIG_SERIAL_OF_PLATFORM=y
+# CONFIG_HW_RANDOM is not set
+CONFIG_I2C=y
+CONFIG_I2C_CHARDEV=y
+# CONFIG_I2C_HELPER_AUTO is not set
+CONFIG_I2C_SMBUS=y
+CONFIG_SPI=y
+CONFIG_SPI_PL022=y
+CONFIG_SPI_SPIDEV=y
+CONFIG_GPIO_SYSFS=y
+# CONFIG_HWMON is not set
+CONFIG_WATCHDOG=y
+CONFIG_ARM_SP805_WATCHDOG=y
+CONFIG_FB=y
+CONFIG_FB_ARMCLCD=y
+CONFIG_BACKLIGHT_LCD_SUPPORT=y
+# CONFIG_LCD_CLASS_DEVICE is not set
+CONFIG_BACKLIGHT_CLASS_DEVICE=y
+# CONFIG_BACKLIGHT_GENERIC is not set
+CONFIG_BACKLIGHT_PWM=y
+CONFIG_SOUND=y
+CONFIG_SND=y
+CONFIG_SND_DYNAMIC_MINORS=y
+CONFIG_SND_VERBOSE_PRINTK=y
+CONFIG_SND_DEBUG=y
+CONFIG_SND_USB_AUDIO=y
+CONFIG_SND_SOC=y
+CONFIG_USB=y
+CONFIG_USB_ANNOUNCE_NEW_DEVICES=y
+CONFIG_USB_EHCI_HCD=y
+CONFIG_USB_EHCI_ROOT_HUB_TT=y
+CONFIG_USB_EHCI_HCD_PLATFORM=y
+CONFIG_USB_STORAGE=y
+CONFIG_MMC=y
+CONFIG_MMC_SDHCI=y
+CONFIG_MMC_SDHCI_PLTFM=y
+CONFIG_PWM=y
+CONFIG_EXT4_FS=y
+CONFIG_MSDOS_FS=y
+CONFIG_VFAT_FS=y
+CONFIG_NTFS_FS=y
+CONFIG_TMPFS=y
+CONFIG_TMPFS_POSIX_ACL=y
+CONFIG_UBIFS_FS=y
+CONFIG_NFS_FS=y
+CONFIG_ROOT_NFS=y
+CONFIG_NLS_CODEPAGE_437=y
+CONFIG_NLS_ISO8859_1=y
+CONFIG_NLS_UTF8=y
+CONFIG_DYNAMIC_DEBUG=y
+CONFIG_DEBUG_INFO=y
+CONFIG_DEBUG_INFO_REDUCED=y
+CONFIG_STRIP_ASM_SYMS=y
+CONFIG_DEBUG_FS=y
+CONFIG_MAGIC_SYSRQ=y
+CONFIG_DEBUG_OBJECTS=y
+CONFIG_DEBUG_OBJECTS_RCU_HEAD=y
+CONFIG_SLUB_DEBUG_ON=y
+CONFIG_DEBUG_MEMORY_INIT=y
+CONFIG_DEBUG_SHIRQ=y
+CONFIG_DETECT_HUNG_TASK=y
+CONFIG_DEFAULT_HUNG_TASK_TIMEOUT=110
+CONFIG_BOOTPARAM_HUNG_TASK_PANIC=y
+# CONFIG_SCHED_DEBUG is not set
+CONFIG_SCHEDSTATS=y
+CONFIG_DEBUG_RT_MUTEXES=y
+CONFIG_PROVE_LOCKING=y
+CONFIG_DEBUG_ATOMIC_SLEEP=y
+# CONFIG_DEBUG_BUGVERBOSE is not set
+CONFIG_DEBUG_SG=y
+CONFIG_DEBUG_NOTIFIERS=y
+CONFIG_DEBUG_CREDENTIALS=y
+CONFIG_PROVE_RCU=y
+CONFIG_DEBUG_USER=y
+CONFIG_DEBUG_LL=y
+CONFIG_DEBUG_LL_UART_8250=y
+CONFIG_DEBUG_UART_PHYS=0x18023000
+CONFIG_DEBUG_UART_VIRT=0xf1023000
+CONFIG_EARLY_PRINTK=y
+# CONFIG_CRYPTO_ANSI_CPRNG is not set
-- 
1.7.9.5


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

* [PATCH v2 6/6] MAINTAINERS: Entry for Cygnus/iproc arm architecture and clock drivers
  2014-09-23 21:17 ` [PATCH v2 " Jonathan Richardson
                     ` (4 preceding siblings ...)
  2014-09-23 21:17   ` [PATCH v2 5/6] ARM: cygnus defconfig : Initial defconfig for " Jonathan Richardson
@ 2014-09-23 21:17   ` Jonathan Richardson
  2014-09-25 21:04   ` [PATCH v2 0/6] Add initial support for Broadcom Cygnus SoC Scott Branden
  6 siblings, 0 replies; 92+ messages in thread
From: Jonathan Richardson @ 2014-09-23 21:17 UTC (permalink / raw)
  To: Christian Daudt, Matt Porter, Russell King, Mike Turquette,
	Rob Herring, Pawel Moll, Mark Rutland, Ian Campbell, Kumar Gala,
	JD Zheng
  Cc: linux-arm-kernel, bcm-kernel-feedback-list, linux-kernel,
	devicetree, Scott Branden, Ray Jui, Jonathan Richardson

Tested-by: Jonathan Richardson <jonathar@broadcom.com>
Reviewed-by: Scott Branden <sbranden@broadcom.com>
Signed-off-by: Jonathan Richardson <jonathar@broadcom.com>
---
 MAINTAINERS |   21 +++++++++++++++++++++
 1 file changed, 21 insertions(+)

diff --git a/MAINTAINERS b/MAINTAINERS
index 670b3dc..beb3e06 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -2070,6 +2070,27 @@ L:	linux-scsi@vger.kernel.org
 S:	Supported
 F:	drivers/scsi/bnx2i/
 
+BROADCOM CYGNUS/IPROC ARM ARCHITECTURE
+M:	Jonathan Richardson <jonathar@broadcom.com>
+M:	Scott Branden <sbranden@broadcom.com>
+L:	linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
+S:	Maintained
+F:	Documentation/devicetree/bindings/arm/cygnus.txt
+F:	arch/arm/boot/dts/bcm-cygnus.dtsi
+F:	arch/arm/boot/dts/bcm911360_entphn.dts
+F:	arch/arm/configs/bcm_cygnus_defconfig
+F:	arch/arm/mach-bcm/board_bcm_cygnus.c
+
+BROADCOM CYGNUS/IPROC CLOCK DRIVERS
+M:	Jonathan Richardson <jonathar@broadcom.com>
+M:	Scott Branden <sbranden@broadcom.com>
+L:	linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
+S:	Maintained
+F:	Documentation/devicetree/bindings/clock/clk-cygnus.txt
+F:	Documentation/devicetree/bindings/clock/clk-iproc.txt
+F:	drivers/clk/bcm/clk-cygnus.c
+F:	drivers/clk/bcm/clk-iproc.c
+
 BROADCOM KONA GPIO DRIVER
 M:	Ray Jui <rjui@broadcom.com>
 L:	bcm-kernel-feedback-list@broadcom.com
-- 
1.7.9.5


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

* Re: [PATCH v2 0/6] Add initial support for Broadcom Cygnus SoC
  2014-09-23 21:17 ` [PATCH v2 " Jonathan Richardson
                     ` (5 preceding siblings ...)
  2014-09-23 21:17   ` [PATCH v2 6/6] MAINTAINERS: Entry for Cygnus/iproc arm architecture and clock drivers Jonathan Richardson
@ 2014-09-25 21:04   ` Scott Branden
  2014-09-25 21:22     ` Florian Fainelli
  6 siblings, 1 reply; 92+ messages in thread
From: Scott Branden @ 2014-09-25 21:04 UTC (permalink / raw)
  To: Jonathan Richardson, Christian Daudt, Matt Porter, Russell King,
	Mike Turquette, Rob Herring, Pawel Moll, Mark Rutland,
	Ian Campbell, Kumar Gala, JD Zheng
  Cc: linux-arm-kernel, bcm-kernel-feedback-list, linux-kernel,
	devicetree, Ray Jui

Hi Matt/Christian (and others),

We would like to move forward in getting our base Cygnus support into 
the mainline kernel.  From there we will be able to contribute 
additional drivers.

Is somebody willing to accept this pull request to get this patchset 
accepted by the open source community?

Regards,
  Scott


On 14-09-23 02:17 PM, Jonathan Richardson wrote:
> Hi,
>
> This patchset contains initial support for Broadcom's Cygnus SoC based on our
> iProc architecture. Initial support is minimal and includes just the mach
> platform code, clock driver, and a basic device tree configuration. Peripheral
> drivers will be submitted soon, as will device tree configurations for other
> Cygnus board variants.
>
> Changes from v1:
>   - Address code review comments as per previous responses.
>   - Copyright headers updated to remove Broadcom URL.
>   - mach platform code still contains hard coded adresses. These address are
>     the same for all Cygnus variants. Could you please provide guidance on where
>     they should go if you would still like them changed.
>
> Thanks,
> Jon
>
> Jonathan Richardson (6):
>    ARM: cygnus: Initial support for Broadcom Cygnus SoC
>    clk: Clock driver support for Broadcom Cygnus SoC
>    dt-bindings: Document Broadcom Cygnus SoC and clock driver
>    ARM: dts: Enable Broadcom Cygnus SoC
>    ARM: cygnus defconfig : Initial defconfig for Broadcom Cygnus SoC
>    MAINTAINERS: Entry for Cygnus/iproc arm architecture and clock
>      drivers
>
>   Documentation/devicetree/bindings/arm/cygnus.txt   |   12 +
>   .../devicetree/bindings/clock/clk-cygnus.txt       |  121 ++
>   .../devicetree/bindings/clock/clk-iproc.txt        |   48 +
>   MAINTAINERS                                        |   21 +
>   arch/arm/boot/dts/Makefile                         |    1 +
>   arch/arm/boot/dts/bcm-cygnus.dtsi                  |  349 ++++++
>   arch/arm/boot/dts/bcm911360_entphn.dts             |   22 +
>   arch/arm/configs/bcm_cygnus_defconfig              |  223 ++++
>   arch/arm/mach-bcm/Kconfig                          |   31 +
>   arch/arm/mach-bcm/Makefile                         |    3 +
>   arch/arm/mach-bcm/bcm_cygnus.c                     |  166 +++
>   drivers/clk/Makefile                               |    1 +
>   drivers/clk/bcm/Makefile                           |    2 +
>   drivers/clk/bcm/clk-cygnus.c                       | 1186 ++++++++++++++++++++
>   drivers/clk/bcm/clk-iproc.c                        |  451 ++++++++
>   15 files changed, 2637 insertions(+)
>   create mode 100644 Documentation/devicetree/bindings/arm/cygnus.txt
>   create mode 100644 Documentation/devicetree/bindings/clock/clk-cygnus.txt
>   create mode 100644 Documentation/devicetree/bindings/clock/clk-iproc.txt
>   create mode 100644 arch/arm/boot/dts/bcm-cygnus.dtsi
>   create mode 100644 arch/arm/boot/dts/bcm911360_entphn.dts
>   create mode 100644 arch/arm/configs/bcm_cygnus_defconfig
>   create mode 100644 arch/arm/mach-bcm/bcm_cygnus.c
>   create mode 100644 drivers/clk/bcm/clk-cygnus.c
>   create mode 100644 drivers/clk/bcm/clk-iproc.c
>


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

* Re: [PATCH v2 0/6] Add initial support for Broadcom Cygnus SoC
  2014-09-25 21:04   ` [PATCH v2 0/6] Add initial support for Broadcom Cygnus SoC Scott Branden
@ 2014-09-25 21:22     ` Florian Fainelli
  2014-09-26  0:14       ` Florian Fainelli
  0 siblings, 1 reply; 92+ messages in thread
From: Florian Fainelli @ 2014-09-25 21:22 UTC (permalink / raw)
  To: Scott Branden, Jonathan Richardson, Christian Daudt, Matt Porter,
	Russell King, Mike Turquette, Rob Herring, Pawel Moll,
	Mark Rutland, Ian Campbell, Kumar Gala, JD Zheng
  Cc: devicetree, bcm-kernel-feedback-list, linux-kernel,
	linux-arm-kernel, Ray Jui

Hi Scott,

On 09/25/2014 02:04 PM, Scott Branden wrote:
> Hi Matt/Christian (and others),
> 
> We would like to move forward in getting our base Cygnus support into
> the mainline kernel.  From there we will be able to contribute
> additional drivers.
> 
> Is somebody willing to accept this pull request to get this patchset
> accepted by the open source community?

I am fine with taking the ARM patches and putting them at
http://github/brcm/linux.git, with C code in cygnus/board and the Device
Tree files in cygnus/dt for instance?

The clock driver patch will have to go through Mike Turquette's tree
unless he wants to delegate that one.

> 
> Regards,
>  Scott
> 
> 
> On 14-09-23 02:17 PM, Jonathan Richardson wrote:
>> Hi,
>>
>> This patchset contains initial support for Broadcom's Cygnus SoC based
>> on our
>> iProc architecture. Initial support is minimal and includes just the mach
>> platform code, clock driver, and a basic device tree configuration.
>> Peripheral
>> drivers will be submitted soon, as will device tree configurations for
>> other
>> Cygnus board variants.
>>
>> Changes from v1:
>>   - Address code review comments as per previous responses.
>>   - Copyright headers updated to remove Broadcom URL.
>>   - mach platform code still contains hard coded adresses. These
>> address are
>>     the same for all Cygnus variants. Could you please provide
>> guidance on where
>>     they should go if you would still like them changed.
>>
>> Thanks,
>> Jon
>>
>> Jonathan Richardson (6):
>>    ARM: cygnus: Initial support for Broadcom Cygnus SoC
>>    clk: Clock driver support for Broadcom Cygnus SoC
>>    dt-bindings: Document Broadcom Cygnus SoC and clock driver
>>    ARM: dts: Enable Broadcom Cygnus SoC
>>    ARM: cygnus defconfig : Initial defconfig for Broadcom Cygnus SoC
>>    MAINTAINERS: Entry for Cygnus/iproc arm architecture and clock
>>      drivers
>>
>>   Documentation/devicetree/bindings/arm/cygnus.txt   |   12 +
>>   .../devicetree/bindings/clock/clk-cygnus.txt       |  121 ++
>>   .../devicetree/bindings/clock/clk-iproc.txt        |   48 +
>>   MAINTAINERS                                        |   21 +
>>   arch/arm/boot/dts/Makefile                         |    1 +
>>   arch/arm/boot/dts/bcm-cygnus.dtsi                  |  349 ++++++
>>   arch/arm/boot/dts/bcm911360_entphn.dts             |   22 +
>>   arch/arm/configs/bcm_cygnus_defconfig              |  223 ++++
>>   arch/arm/mach-bcm/Kconfig                          |   31 +
>>   arch/arm/mach-bcm/Makefile                         |    3 +
>>   arch/arm/mach-bcm/bcm_cygnus.c                     |  166 +++
>>   drivers/clk/Makefile                               |    1 +
>>   drivers/clk/bcm/Makefile                           |    2 +
>>   drivers/clk/bcm/clk-cygnus.c                       | 1186
>> ++++++++++++++++++++
>>   drivers/clk/bcm/clk-iproc.c                        |  451 ++++++++
>>   15 files changed, 2637 insertions(+)
>>   create mode 100644 Documentation/devicetree/bindings/arm/cygnus.txt
>>   create mode 100644
>> Documentation/devicetree/bindings/clock/clk-cygnus.txt
>>   create mode 100644
>> Documentation/devicetree/bindings/clock/clk-iproc.txt
>>   create mode 100644 arch/arm/boot/dts/bcm-cygnus.dtsi
>>   create mode 100644 arch/arm/boot/dts/bcm911360_entphn.dts
>>   create mode 100644 arch/arm/configs/bcm_cygnus_defconfig
>>   create mode 100644 arch/arm/mach-bcm/bcm_cygnus.c
>>   create mode 100644 drivers/clk/bcm/clk-cygnus.c
>>   create mode 100644 drivers/clk/bcm/clk-iproc.c
>>
> 
> 
> _______________________________________________
> linux-arm-kernel mailing list
> linux-arm-kernel@lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/linux-arm-kernel


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

* Re: [PATCH v2 0/6] Add initial support for Broadcom Cygnus SoC
  2014-09-25 21:22     ` Florian Fainelli
@ 2014-09-26  0:14       ` Florian Fainelli
  2014-09-26  0:28         ` Jonathan Richardson
  0 siblings, 1 reply; 92+ messages in thread
From: Florian Fainelli @ 2014-09-26  0:14 UTC (permalink / raw)
  To: Scott Branden, Jonathan Richardson, Christian Daudt, Matt Porter,
	Russell King, Mike Turquette, Rob Herring, Pawel Moll,
	Mark Rutland, Ian Campbell, Kumar Gala, JD Zheng
  Cc: devicetree, bcm-kernel-feedback-list, linux-kernel,
	linux-arm-kernel, Ray Jui, Mike Turquette

Scott, Jonathan,

On 09/25/2014 02:22 PM, Florian Fainelli wrote:
> Hi Scott,
> 
> On 09/25/2014 02:04 PM, Scott Branden wrote:
>> Hi Matt/Christian (and others),
>>
>> We would like to move forward in getting our base Cygnus support into
>> the mainline kernel.  From there we will be able to contribute
>> additional drivers.
>>
>> Is somebody willing to accept this pull request to get this patchset
>> accepted by the open source community?
> 
> I am fine with taking the ARM patches and putting them at
> http://github/brcm/linux.git, with C code in cygnus/board and the Device
> Tree files in cygnus/dt for instance?
> 
> The clock driver patch will have to go through Mike Turquette's tree
> unless he wants to delegate that one.

Could you resend patch 3 without the clock binding, patch 4 without the
clocks node, and patch 6 without the drivers/clk changes? Once you do
that, I can assemble these patches quickly and send a pull request which
does only contain ARM SoC and DTS changes, and you can get the clock
driver to be reviewed separately by its maintainer?

Thanks!

> 
>>
>> Regards,
>>  Scott
>>
>>
>> On 14-09-23 02:17 PM, Jonathan Richardson wrote:
>>> Hi,
>>>
>>> This patchset contains initial support for Broadcom's Cygnus SoC based
>>> on our
>>> iProc architecture. Initial support is minimal and includes just the mach
>>> platform code, clock driver, and a basic device tree configuration.
>>> Peripheral
>>> drivers will be submitted soon, as will device tree configurations for
>>> other
>>> Cygnus board variants.
>>>
>>> Changes from v1:
>>>   - Address code review comments as per previous responses.
>>>   - Copyright headers updated to remove Broadcom URL.
>>>   - mach platform code still contains hard coded adresses. These
>>> address are
>>>     the same for all Cygnus variants. Could you please provide
>>> guidance on where
>>>     they should go if you would still like them changed.
>>>
>>> Thanks,
>>> Jon
>>>
>>> Jonathan Richardson (6):
>>>    ARM: cygnus: Initial support for Broadcom Cygnus SoC
>>>    clk: Clock driver support for Broadcom Cygnus SoC
>>>    dt-bindings: Document Broadcom Cygnus SoC and clock driver
>>>    ARM: dts: Enable Broadcom Cygnus SoC
>>>    ARM: cygnus defconfig : Initial defconfig for Broadcom Cygnus SoC
>>>    MAINTAINERS: Entry for Cygnus/iproc arm architecture and clock
>>>      drivers
>>>
>>>   Documentation/devicetree/bindings/arm/cygnus.txt   |   12 +
>>>   .../devicetree/bindings/clock/clk-cygnus.txt       |  121 ++
>>>   .../devicetree/bindings/clock/clk-iproc.txt        |   48 +
>>>   MAINTAINERS                                        |   21 +
>>>   arch/arm/boot/dts/Makefile                         |    1 +
>>>   arch/arm/boot/dts/bcm-cygnus.dtsi                  |  349 ++++++
>>>   arch/arm/boot/dts/bcm911360_entphn.dts             |   22 +
>>>   arch/arm/configs/bcm_cygnus_defconfig              |  223 ++++
>>>   arch/arm/mach-bcm/Kconfig                          |   31 +
>>>   arch/arm/mach-bcm/Makefile                         |    3 +
>>>   arch/arm/mach-bcm/bcm_cygnus.c                     |  166 +++
>>>   drivers/clk/Makefile                               |    1 +
>>>   drivers/clk/bcm/Makefile                           |    2 +
>>>   drivers/clk/bcm/clk-cygnus.c                       | 1186
>>> ++++++++++++++++++++
>>>   drivers/clk/bcm/clk-iproc.c                        |  451 ++++++++
>>>   15 files changed, 2637 insertions(+)
>>>   create mode 100644 Documentation/devicetree/bindings/arm/cygnus.txt
>>>   create mode 100644
>>> Documentation/devicetree/bindings/clock/clk-cygnus.txt
>>>   create mode 100644
>>> Documentation/devicetree/bindings/clock/clk-iproc.txt
>>>   create mode 100644 arch/arm/boot/dts/bcm-cygnus.dtsi
>>>   create mode 100644 arch/arm/boot/dts/bcm911360_entphn.dts
>>>   create mode 100644 arch/arm/configs/bcm_cygnus_defconfig
>>>   create mode 100644 arch/arm/mach-bcm/bcm_cygnus.c
>>>   create mode 100644 drivers/clk/bcm/clk-cygnus.c
>>>   create mode 100644 drivers/clk/bcm/clk-iproc.c
>>>
>>
>>
>> _______________________________________________
>> linux-arm-kernel mailing list
>> linux-arm-kernel@lists.infradead.org
>> http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
> 


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

* Re: [PATCH v2 0/6] Add initial support for Broadcom Cygnus SoC
  2014-09-26  0:14       ` Florian Fainelli
@ 2014-09-26  0:28         ` Jonathan Richardson
  2014-09-26  0:34           ` Florian Fainelli
  0 siblings, 1 reply; 92+ messages in thread
From: Jonathan Richardson @ 2014-09-26  0:28 UTC (permalink / raw)
  To: Florian Fainelli
  Cc: Scott Branden, Christian Daudt, Matt Porter, Russell King,
	Mike Turquette, Rob Herring, Pawel Moll, Mark Rutland,
	Ian Campbell, Kumar Gala, JD Zheng, devicetree,
	bcm-kernel-feedback-list, linux-kernel, linux-arm-kernel,
	Ray Jui

On 14-09-25 05:14 PM, Florian Fainelli wrote:
> Scott, Jonathan,
> 
> On 09/25/2014 02:22 PM, Florian Fainelli wrote:
>> Hi Scott,
>>
>> On 09/25/2014 02:04 PM, Scott Branden wrote:
>>> Hi Matt/Christian (and others),
>>>
>>> We would like to move forward in getting our base Cygnus support into
>>> the mainline kernel.  From there we will be able to contribute
>>> additional drivers.
>>>
>>> Is somebody willing to accept this pull request to get this patchset
>>> accepted by the open source community?
>>
>> I am fine with taking the ARM patches and putting them at
>> http://github/brcm/linux.git, with C code in cygnus/board and the Device
>> Tree files in cygnus/dt for instance?
>>
>> The clock driver patch will have to go through Mike Turquette's tree
>> unless he wants to delegate that one.
> 
> Could you resend patch 3 without the clock binding, patch 4 without the
> clocks node, and patch 6 without the drivers/clk changes? Once you do
> that, I can assemble these patches quickly and send a pull request which
> does only contain ARM SoC and DTS changes, and you can get the clock
> driver to be reviewed separately by its maintainer?

The serial driver needs a clock so probably better not to pull out the
clock nodes. It's part of the core functionality we'd like in the
initial Cygnus support. I didn't hear from Mike (cc'd), though Mark
reviewed it.

Thanks.

> 
> Thanks!
> 
>>
>>>
>>> Regards,
>>>  Scott
>>>
>>>
>>> On 14-09-23 02:17 PM, Jonathan Richardson wrote:
>>>> Hi,
>>>>
>>>> This patchset contains initial support for Broadcom's Cygnus SoC based
>>>> on our
>>>> iProc architecture. Initial support is minimal and includes just the mach
>>>> platform code, clock driver, and a basic device tree configuration.
>>>> Peripheral
>>>> drivers will be submitted soon, as will device tree configurations for
>>>> other
>>>> Cygnus board variants.
>>>>
>>>> Changes from v1:
>>>>   - Address code review comments as per previous responses.
>>>>   - Copyright headers updated to remove Broadcom URL.
>>>>   - mach platform code still contains hard coded adresses. These
>>>> address are
>>>>     the same for all Cygnus variants. Could you please provide
>>>> guidance on where
>>>>     they should go if you would still like them changed.
>>>>
>>>> Thanks,
>>>> Jon
>>>>
>>>> Jonathan Richardson (6):
>>>>    ARM: cygnus: Initial support for Broadcom Cygnus SoC
>>>>    clk: Clock driver support for Broadcom Cygnus SoC
>>>>    dt-bindings: Document Broadcom Cygnus SoC and clock driver
>>>>    ARM: dts: Enable Broadcom Cygnus SoC
>>>>    ARM: cygnus defconfig : Initial defconfig for Broadcom Cygnus SoC
>>>>    MAINTAINERS: Entry for Cygnus/iproc arm architecture and clock
>>>>      drivers
>>>>
>>>>   Documentation/devicetree/bindings/arm/cygnus.txt   |   12 +
>>>>   .../devicetree/bindings/clock/clk-cygnus.txt       |  121 ++
>>>>   .../devicetree/bindings/clock/clk-iproc.txt        |   48 +
>>>>   MAINTAINERS                                        |   21 +
>>>>   arch/arm/boot/dts/Makefile                         |    1 +
>>>>   arch/arm/boot/dts/bcm-cygnus.dtsi                  |  349 ++++++
>>>>   arch/arm/boot/dts/bcm911360_entphn.dts             |   22 +
>>>>   arch/arm/configs/bcm_cygnus_defconfig              |  223 ++++
>>>>   arch/arm/mach-bcm/Kconfig                          |   31 +
>>>>   arch/arm/mach-bcm/Makefile                         |    3 +
>>>>   arch/arm/mach-bcm/bcm_cygnus.c                     |  166 +++
>>>>   drivers/clk/Makefile                               |    1 +
>>>>   drivers/clk/bcm/Makefile                           |    2 +
>>>>   drivers/clk/bcm/clk-cygnus.c                       | 1186
>>>> ++++++++++++++++++++
>>>>   drivers/clk/bcm/clk-iproc.c                        |  451 ++++++++
>>>>   15 files changed, 2637 insertions(+)
>>>>   create mode 100644 Documentation/devicetree/bindings/arm/cygnus.txt
>>>>   create mode 100644
>>>> Documentation/devicetree/bindings/clock/clk-cygnus.txt
>>>>   create mode 100644
>>>> Documentation/devicetree/bindings/clock/clk-iproc.txt
>>>>   create mode 100644 arch/arm/boot/dts/bcm-cygnus.dtsi
>>>>   create mode 100644 arch/arm/boot/dts/bcm911360_entphn.dts
>>>>   create mode 100644 arch/arm/configs/bcm_cygnus_defconfig
>>>>   create mode 100644 arch/arm/mach-bcm/bcm_cygnus.c
>>>>   create mode 100644 drivers/clk/bcm/clk-cygnus.c
>>>>   create mode 100644 drivers/clk/bcm/clk-iproc.c
>>>>
>>>
>>>
>>> _______________________________________________
>>> linux-arm-kernel mailing list
>>> linux-arm-kernel@lists.infradead.org
>>> http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
>>
> 


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

* Re: [PATCH v2 0/6] Add initial support for Broadcom Cygnus SoC
  2014-09-26  0:28         ` Jonathan Richardson
@ 2014-09-26  0:34           ` Florian Fainelli
  0 siblings, 0 replies; 92+ messages in thread
From: Florian Fainelli @ 2014-09-26  0:34 UTC (permalink / raw)
  To: Jonathan Richardson
  Cc: Scott Branden, Christian Daudt, Matt Porter, Russell King,
	Mike Turquette, Rob Herring, Pawel Moll, Mark Rutland,
	Ian Campbell, Kumar Gala, JD Zheng, devicetree,
	bcm-kernel-feedback-list, linux-kernel, linux-arm-kernel,
	Ray Jui

On 09/25/2014 05:28 PM, Jonathan Richardson wrote:
> On 14-09-25 05:14 PM, Florian Fainelli wrote:
>> Scott, Jonathan,
>>
>> On 09/25/2014 02:22 PM, Florian Fainelli wrote:
>>> Hi Scott,
>>>
>>> On 09/25/2014 02:04 PM, Scott Branden wrote:
>>>> Hi Matt/Christian (and others),
>>>>
>>>> We would like to move forward in getting our base Cygnus support into
>>>> the mainline kernel.  From there we will be able to contribute
>>>> additional drivers.
>>>>
>>>> Is somebody willing to accept this pull request to get this patchset
>>>> accepted by the open source community?
>>>
>>> I am fine with taking the ARM patches and putting them at
>>> http://github/brcm/linux.git, with C code in cygnus/board and the Device
>>> Tree files in cygnus/dt for instance?
>>>
>>> The clock driver patch will have to go through Mike Turquette's tree
>>> unless he wants to delegate that one.
>>
>> Could you resend patch 3 without the clock binding, patch 4 without the
>> clocks node, and patch 6 without the drivers/clk changes? Once you do
>> that, I can assemble these patches quickly and send a pull request which
>> does only contain ARM SoC and DTS changes, and you can get the clock
>> driver to be reviewed separately by its maintainer?
> 
> The serial driver needs a clock so probably better not to pull out the
> clock nodes. It's part of the core functionality we'd like in the
> initial Cygnus support. I didn't hear from Mike (cc'd), though Mark
> reviewed it.

I just sent out the pull request, we'll see how it goes from there. Thanks!
--
Florian

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

* [PATCH v2 1/2]     pwm: kona: Fix incorrect enable, config, and disable procedures
       [not found] <Jonathan Richardson <jonathar@broadcom.com>
  2014-09-16 19:58 ` [PATCH 0/6] Add initial support for Broadcom Cygnus SoC Jonathan Richardson
  2014-09-23 21:17 ` [PATCH v2 " Jonathan Richardson
@ 2014-12-11  1:07 ` Jonathan Richardson
  2014-12-11  1:07   ` [PATCH v2 2/2] pwm: kona: Remove setting default smooth type and polarity for all channels Jonathan Richardson
  2014-12-15  7:18   ` [PATCH v2 1/2] pwm: kona: Fix incorrect enable, config, and disable procedures Tim Kryger
  2014-12-17 18:46 ` [PATCH v3 " Jonathan Richardson
                   ` (10 subsequent siblings)
  13 siblings, 2 replies; 92+ messages in thread
From: Jonathan Richardson @ 2014-12-11  1:07 UTC (permalink / raw)
  To: Tim Kryger
  Cc: Scott Branden, Arun Ramamurthy, Thierry Reding, Ray Jui,
	bcm-kernel-feedback-list, linux-kernel, linux-pwm,
	Jonathan Richardson

    The config procedure doesn't follow the spec which periodically results
    in failing to enable the output signal. This happens one in ten or
    twenty attempts. Following the spec and adding a 400ns delay in the
    appropriate locations resolves this problem. It also ensures that the
    signal transition is smooth.

    If config is called when the pwm is disabled and there is nothing to do,
    the while loop to calculate duty cycle and period doesn't need to be
    done. The function now just returns if the pwm state is disabled.

    The disable procedure now also follows the spec to ensure a smooth
    transition. Not following the spec can cause non-smooth transitions.

    The enable procedure now clears the enabled bit if enabling failed.
    Enabling can fail if an invalid duty cycle and period is set. This
    prevents the sysfs interface from reporting the pwm is enabled after a
    failed call to enable.

Reviewed-by: Arun Ramamurthy <arunrama@broadcom.com>
Reviewed-by: Scott Branden <sbranden@broadcom.com>
Tested-by: Scott Branden <sbranden@broadcom.com>
Signed-off-by: Jonathan Richardson <jonathar@broadcom.com>
---
 drivers/pwm/pwm-bcm-kona.c |   91 ++++++++++++++++++++++++++++++++------------
 1 file changed, 67 insertions(+), 24 deletions(-)

diff --git a/drivers/pwm/pwm-bcm-kona.c b/drivers/pwm/pwm-bcm-kona.c
index 02bc048..6d92026 100644
--- a/drivers/pwm/pwm-bcm-kona.c
+++ b/drivers/pwm/pwm-bcm-kona.c
@@ -80,15 +80,19 @@ static void kona_pwmc_apply_settings(struct kona_pwmc *kp, unsigned int chan)
 {
 	unsigned int value = readl(kp->base + PWM_CONTROL_OFFSET);
 
-	/* Clear trigger bit but set smooth bit to maintain old output */
-	value |= 1 << PWM_CONTROL_SMOOTH_SHIFT(chan);
-	value &= ~(1 << PWM_CONTROL_TRIGGER_SHIFT(chan));
-	writel(value, kp->base + PWM_CONTROL_OFFSET);
+	/*
+	 * There must be a min 400ns delay between clearing enable and setting
+	 * it. Failing to do this may result in no PWM signal.
+	 */
+	ndelay(400);
 
 	/* Set trigger bit and clear smooth bit to apply new settings */
 	value &= ~(1 << PWM_CONTROL_SMOOTH_SHIFT(chan));
 	value |= 1 << PWM_CONTROL_TRIGGER_SHIFT(chan);
 	writel(value, kp->base + PWM_CONTROL_OFFSET);
+
+	/* PWMOUT_ENABLE must be held high for at least 400 ns. */
+	ndelay(400);
 }
 
 static int kona_pwmc_config(struct pwm_chip *chip, struct pwm_device *pwm,
@@ -99,6 +103,9 @@ static int kona_pwmc_config(struct pwm_chip *chip, struct pwm_device *pwm,
 	unsigned long prescale = PRESCALE_MIN, pc, dc;
 	unsigned int value, chan = pwm->hwpwm;
 
+	if (!test_bit(PWMF_ENABLED, &pwm->flags))
+		return 0;
+
 	/*
 	 * Find period count, duty count and prescale to suit duty_ns and
 	 * period_ns. This is done according to formulas described below:
@@ -121,31 +128,60 @@ static int kona_pwmc_config(struct pwm_chip *chip, struct pwm_device *pwm,
 		dc = div64_u64(val, div);
 
 		/* If duty_ns or period_ns are not achievable then return */
-		if (pc < PERIOD_COUNT_MIN || dc < DUTY_CYCLE_HIGH_MIN)
+		if (pc < PERIOD_COUNT_MIN) {
+			dev_warn(chip->dev,
+				"%s: pwm[%d]: period=%d is not achievable, pc=%lu, prescale=%lu\n",
+				__func__, chan, period_ns, pc, prescale);
 			return -EINVAL;
+		}
+
+		/* If duty_ns is not achievable then return */
+		if (dc < DUTY_CYCLE_HIGH_MIN) {
+			if (0 != duty_ns) {
+				dev_warn(chip->dev,
+					"%s: pwm[%d]: duty cycle=%d is not achievable, dc=%lu, prescale=%lu\n",
+					__func__, chan, duty_ns, dc, prescale);
+			}
+			return -EINVAL;
+		}
 
 		/* If pc and dc are in bounds, the calculation is done */
 		if (pc <= PERIOD_COUNT_MAX && dc <= DUTY_CYCLE_HIGH_MAX)
 			break;
 
 		/* Otherwise, increase prescale and recalculate pc and dc */
-		if (++prescale > PRESCALE_MAX)
+		if (++prescale > PRESCALE_MAX) {
+			dev_warn(chip->dev,
+				"%s: pwm[%d]: Prescale (=%lu) within max (=%d) for period=%d and duty cycle=%d is not achievable\n",
+				__func__, chan, prescale, PRESCALE_MAX,
+				period_ns, duty_ns);
 			return -EINVAL;
+		}
 	}
 
-	/* If the PWM channel is enabled, write the settings to the HW */
-	if (test_bit(PWMF_ENABLED, &pwm->flags)) {
-		value = readl(kp->base + PRESCALE_OFFSET);
-		value &= ~PRESCALE_MASK(chan);
-		value |= prescale << PRESCALE_SHIFT(chan);
-		writel(value, kp->base + PRESCALE_OFFSET);
+	dev_dbg(chip->dev, "pwm[%d]: period=%lu, duty_high=%lu, prescale=%lu\n",
+		chan, pc, dc, prescale);
 
-		writel(pc, kp->base + PERIOD_COUNT_OFFSET(chan));
+	value = readl(kp->base + PWM_CONTROL_OFFSET);
 
-		writel(dc, kp->base + DUTY_CYCLE_HIGH_OFFSET(chan));
+	/*
+	 * Clear trigger bit but set smooth bit to maintain old
+	 * output.
+	 */
+	value |= 1 << PWM_CONTROL_SMOOTH_SHIFT(chan);
+	value &= ~(1 << PWM_CONTROL_TRIGGER_SHIFT(chan));
+	writel(value, kp->base + PWM_CONTROL_OFFSET);
 
-		kona_pwmc_apply_settings(kp, chan);
-	}
+	value = readl(kp->base + PRESCALE_OFFSET);
+	value &= ~PRESCALE_MASK(chan);
+	value |= prescale << PRESCALE_SHIFT(chan);
+	writel(value, kp->base + PRESCALE_OFFSET);
+
+	writel(pc, kp->base + PERIOD_COUNT_OFFSET(chan));
+
+	writel(dc, kp->base + DUTY_CYCLE_HIGH_OFFSET(chan));
+
+	kona_pwmc_apply_settings(kp, chan);
 
 	return 0;
 }
@@ -173,11 +209,6 @@ static int kona_pwmc_set_polarity(struct pwm_chip *chip, struct pwm_device *pwm,
 
 	writel(value, kp->base + PWM_CONTROL_OFFSET);
 
-	kona_pwmc_apply_settings(kp, chan);
-
-	/* Wait for waveform to settle before gating off the clock */
-	ndelay(400);
-
 	clk_disable_unprepare(kp->clk);
 
 	return 0;
@@ -190,12 +221,14 @@ static int kona_pwmc_enable(struct pwm_chip *chip, struct pwm_device *pwm)
 
 	ret = clk_prepare_enable(kp->clk);
 	if (ret < 0) {
+		clear_bit(PWMF_ENABLED, &pwm->flags);
 		dev_err(chip->dev, "failed to enable clock: %d\n", ret);
 		return ret;
 	}
 
 	ret = kona_pwmc_config(chip, pwm, pwm->duty_cycle, pwm->period);
 	if (ret < 0) {
+		clear_bit(PWMF_ENABLED, &pwm->flags);
 		clk_disable_unprepare(kp->clk);
 		return ret;
 	}
@@ -207,13 +240,23 @@ static void kona_pwmc_disable(struct pwm_chip *chip, struct pwm_device *pwm)
 {
 	struct kona_pwmc *kp = to_kona_pwmc(chip);
 	unsigned int chan = pwm->hwpwm;
+	unsigned int value = readl(kp->base + PWM_CONTROL_OFFSET);
+
+	/* Set smooth type to 0 and disable */
+	value &= ~(1 << PWM_CONTROL_SMOOTH_SHIFT(chan));
+	value &= ~(1 << PWM_CONTROL_TRIGGER_SHIFT(chan));
+	writel(value, kp->base + PWM_CONTROL_OFFSET);
 
 	/* Simulate a disable by configuring for zero duty */
 	writel(0, kp->base + DUTY_CYCLE_HIGH_OFFSET(chan));
-	kona_pwmc_apply_settings(kp, chan);
+	writel(0, kp->base + PERIOD_COUNT_OFFSET(chan));
 
-	/* Wait for waveform to settle before gating off the clock */
-	ndelay(400);
+	/* Set prescale to 0 for this channel */
+	value = readl(kp->base + PRESCALE_OFFSET);
+	value &= ~PRESCALE_MASK(chan);
+	writel(value, kp->base + PRESCALE_OFFSET);
+
+	kona_pwmc_apply_settings(kp, chan);
 
 	clk_disable_unprepare(kp->clk);
 }
-- 
1.7.9.5


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

* [PATCH v2 2/2] pwm: kona: Remove setting default smooth type and polarity for all channels
  2014-12-11  1:07 ` [PATCH v2 1/2] pwm: kona: Fix incorrect enable, config, and disable procedures Jonathan Richardson
@ 2014-12-11  1:07   ` Jonathan Richardson
  2014-12-15  7:18   ` [PATCH v2 1/2] pwm: kona: Fix incorrect enable, config, and disable procedures Tim Kryger
  1 sibling, 0 replies; 92+ messages in thread
From: Jonathan Richardson @ 2014-12-11  1:07 UTC (permalink / raw)
  To: Tim Kryger
  Cc: Scott Branden, Arun Ramamurthy, Thierry Reding, Ray Jui,
	bcm-kernel-feedback-list, linux-kernel, linux-pwm,
	Jonathan Richardson

Setting the default polarity in probe to normal for all channels caused
the speaker pwm channel to click. The polarity does need to be set to
normal because the hw default is inversed whereas the pwm framework
defaults to normal. If a channel is enabled without setting the polarity
then the signal would be inversed while linux reports normal. A check
is now done prior to enabling the channel to ensure that the hw polarity
matches the desired polarity and is changed if there is a discrepency. This
prevents unnecessary settings being applied to unused channels but still
ensures the correct polarity to be set.

Reviewed-by: Scott Branden <sbranden@broadcom.com>
Tested-by: Scott Branden <sbranden@broadcom.com>
Signed-off-by: Jonathan Richardson <jonathar@broadcom.com>
---
 drivers/pwm/pwm-bcm-kona.c |   38 ++++++++++++++++++++++++++++++++++----
 1 file changed, 34 insertions(+), 4 deletions(-)

diff --git a/drivers/pwm/pwm-bcm-kona.c b/drivers/pwm/pwm-bcm-kona.c
index 6d92026..46a3da5 100644
--- a/drivers/pwm/pwm-bcm-kona.c
+++ b/drivers/pwm/pwm-bcm-kona.c
@@ -95,6 +95,32 @@ static void kona_pwmc_apply_settings(struct kona_pwmc *kp, unsigned int chan)
 	ndelay(400);
 }
 
+static void kona_pwmc_check_set_polarity(struct pwm_chip *chip,
+	struct pwm_device *pwm)
+{
+	struct kona_pwmc *kp = to_kona_pwmc(chip);
+	unsigned int chan = pwm->hwpwm;
+	enum pwm_polarity polarity = pwm->polarity;
+	unsigned int hw_pol;
+	unsigned int value = 0;
+
+	value = hw_pol = readl(kp->base + PWM_CONTROL_OFFSET);
+	hw_pol = (hw_pol >> PWM_CONTROL_POLARITY_SHIFT(chan)) & 0x1;
+
+	/*
+	 * If current polarity not the same as h/w then set polarity so that
+	 * they match.
+	 */
+	if (!hw_pol != polarity) {
+		if (polarity == PWM_POLARITY_NORMAL)
+			value |= 1 << PWM_CONTROL_POLARITY_SHIFT(chan);
+		else
+			value &= ~(1 << PWM_CONTROL_POLARITY_SHIFT(chan));
+
+		writel(value, kp->base + PWM_CONTROL_OFFSET);
+	}
+}
+
 static int kona_pwmc_config(struct pwm_chip *chip, struct pwm_device *pwm,
 			    int duty_ns, int period_ns)
 {
@@ -162,6 +188,13 @@ static int kona_pwmc_config(struct pwm_chip *chip, struct pwm_device *pwm,
 	dev_dbg(chip->dev, "pwm[%d]: period=%lu, duty_high=%lu, prescale=%lu\n",
 		chan, pc, dc, prescale);
 
+	/*
+	 * Ensure polarity is set properly. The default value for h/w and the
+	 * PWM framework are different. If a channel is enabled without setting
+	 * the polarity, the default value would be inconsistent to the signal.
+	 */
+	kona_pwmc_check_set_polarity(chip, pwm);
+
 	value = readl(kp->base + PWM_CONTROL_OFFSET);
 
 	/*
@@ -310,11 +343,8 @@ static int kona_pwmc_probe(struct platform_device *pdev)
 	}
 
 	/* Set smooth mode, push/pull, and normal polarity for all channels */
-	for (chan = 0; chan < kp->chip.npwm; chan++) {
-		value |= (1 << PWM_CONTROL_SMOOTH_SHIFT(chan));
+	for (chan = 0; chan < kp->chip.npwm; chan++)
 		value |= (1 << PWM_CONTROL_TYPE_SHIFT(chan));
-		value |= (1 << PWM_CONTROL_POLARITY_SHIFT(chan));
-	}
 
 	writel(value, kp->base + PWM_CONTROL_OFFSET);
 
-- 
1.7.9.5


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

* Re: [PATCH v2 1/2] pwm: kona: Fix incorrect enable, config, and disable procedures
  2014-12-11  1:07 ` [PATCH v2 1/2] pwm: kona: Fix incorrect enable, config, and disable procedures Jonathan Richardson
  2014-12-11  1:07   ` [PATCH v2 2/2] pwm: kona: Remove setting default smooth type and polarity for all channels Jonathan Richardson
@ 2014-12-15  7:18   ` Tim Kryger
  2014-12-16 19:36     ` Jonathan Richardson
  1 sibling, 1 reply; 92+ messages in thread
From: Tim Kryger @ 2014-12-15  7:18 UTC (permalink / raw)
  To: Jonathan Richardson
  Cc: Scott Branden, Arun Ramamurthy, Thierry Reding, Ray Jui,
	bcm-kernel-feedback-list, Linux Kernel Mailing List, linux-pwm

On Wed, Dec 10, 2014 at 5:07 PM, Jonathan Richardson
<jonathar@broadcom.com> wrote:

>     If config is called when the pwm is disabled and there is nothing to do,
>     the while loop to calculate duty cycle and period doesn't need to be
>     done. The function now just returns if the pwm state is disabled.

It doesn't take long to figure out whether the duty and period are achievable.

If the caller specifies bad settings, why not return an error immediately?

> @@ -207,13 +240,23 @@ static void kona_pwmc_disable(struct pwm_chip *chip, struct pwm_device *pwm)
>  {
>         struct kona_pwmc *kp = to_kona_pwmc(chip);
>         unsigned int chan = pwm->hwpwm;
> +       unsigned int value = readl(kp->base + PWM_CONTROL_OFFSET);
> +
> +       /* Set smooth type to 0 and disable */
> +       value &= ~(1 << PWM_CONTROL_SMOOTH_SHIFT(chan));
> +       value &= ~(1 << PWM_CONTROL_TRIGGER_SHIFT(chan));
> +       writel(value, kp->base + PWM_CONTROL_OFFSET);
>
>         /* Simulate a disable by configuring for zero duty */
>         writel(0, kp->base + DUTY_CYCLE_HIGH_OFFSET(chan));
> -       kona_pwmc_apply_settings(kp, chan);
> +       writel(0, kp->base + PERIOD_COUNT_OFFSET(chan));
>
> -       /* Wait for waveform to settle before gating off the clock */
> -       ndelay(400);
> +       /* Set prescale to 0 for this channel */
> +       value = readl(kp->base + PRESCALE_OFFSET);
> +       value &= ~PRESCALE_MASK(chan);
> +       writel(value, kp->base + PRESCALE_OFFSET);
> +
> +       kona_pwmc_apply_settings(kp, chan);
>
>         clk_disable_unprepare(kp->clk);
>  }

I've mentioned this before but I will say it again, when the smooth
and trigger bit are both low, the output is constant high.

If you look at the PWM output on a scope you will see it go high for
400 ns during your disable even if the duty prior to the disable was
zero.

How are you testing your proposed changes?

Thanks,
Tim Kryger

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

* Re: [PATCH v2 1/2] pwm: kona: Fix incorrect enable, config, and disable procedures
  2014-12-15  7:18   ` [PATCH v2 1/2] pwm: kona: Fix incorrect enable, config, and disable procedures Tim Kryger
@ 2014-12-16 19:36     ` Jonathan Richardson
  0 siblings, 0 replies; 92+ messages in thread
From: Jonathan Richardson @ 2014-12-16 19:36 UTC (permalink / raw)
  To: Tim Kryger
  Cc: Scott Branden, Arun Ramamurthy, Thierry Reding, Ray Jui,
	bcm-kernel-feedback-list, Linux Kernel Mailing List, linux-pwm

On 14-12-14 11:18 PM, Tim Kryger wrote:
> On Wed, Dec 10, 2014 at 5:07 PM, Jonathan Richardson
> <jonathar@broadcom.com> wrote:
> 
>>     If config is called when the pwm is disabled and there is nothing to do,
>>     the while loop to calculate duty cycle and period doesn't need to be
>>     done. The function now just returns if the pwm state is disabled.
> 
> It doesn't take long to figure out whether the duty and period are achievable.
> 
> If the caller specifies bad settings, why not return an error immediately?

Sorry, not sure what you're suggesting here. It's returning as soon as
it can isn't it? Nothing changed in the way the period and duty cycle
were calculated and checked in the while loop.

> 
>> @@ -207,13 +240,23 @@ static void kona_pwmc_disable(struct pwm_chip *chip, struct pwm_device *pwm)
>>  {
>>         struct kona_pwmc *kp = to_kona_pwmc(chip);
>>         unsigned int chan = pwm->hwpwm;
>> +       unsigned int value = readl(kp->base + PWM_CONTROL_OFFSET);
>> +
>> +       /* Set smooth type to 0 and disable */
>> +       value &= ~(1 << PWM_CONTROL_SMOOTH_SHIFT(chan));
>> +       value &= ~(1 << PWM_CONTROL_TRIGGER_SHIFT(chan));
>> +       writel(value, kp->base + PWM_CONTROL_OFFSET);
>>
>>         /* Simulate a disable by configuring for zero duty */
>>         writel(0, kp->base + DUTY_CYCLE_HIGH_OFFSET(chan));
>> -       kona_pwmc_apply_settings(kp, chan);
>> +       writel(0, kp->base + PERIOD_COUNT_OFFSET(chan));
>>
>> -       /* Wait for waveform to settle before gating off the clock */
>> -       ndelay(400);
>> +       /* Set prescale to 0 for this channel */
>> +       value = readl(kp->base + PRESCALE_OFFSET);
>> +       value &= ~PRESCALE_MASK(chan);
>> +       writel(value, kp->base + PRESCALE_OFFSET);
>> +
>> +       kona_pwmc_apply_settings(kp, chan);
>>
>>         clk_disable_unprepare(kp->clk);
>>  }
> 
> I've mentioned this before but I will say it again, when the smooth
> and trigger bit are both low, the output is constant high.
> 
> If you look at the PWM output on a scope you will see it go high for
> 400 ns during your disable even if the duty prior to the disable was
> zero.
> 
> How are you testing your proposed changes?
> 

I see what you mean now and verified it. For a smooth transition even on
disable the smooth bit should be set high, not low. It's the same
procedure as in config. Setting the bit high instead of low gets rid of
the 400ns transition high. I can make this change.

> Thanks,
> Tim Kryger
> 


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

* [PATCH v3 1/2]     pwm: kona: Fix incorrect enable, config, and disable procedures
       [not found] <Jonathan Richardson <jonathar@broadcom.com>
                   ` (2 preceding siblings ...)
  2014-12-11  1:07 ` [PATCH v2 1/2] pwm: kona: Fix incorrect enable, config, and disable procedures Jonathan Richardson
@ 2014-12-17 18:46 ` Jonathan Richardson
  2014-12-17 18:46   ` [PATCH v3 2/2] pwm: kona: Remove setting default smooth type and polarity for all channels Jonathan Richardson
  2014-12-20 22:38   ` [PATCH v3 1/2] pwm: kona: Fix incorrect enable, config, and disable procedures Tim Kryger
  2014-12-18  1:59 ` [PATCH 0/2] Add support for Broadcom iProc touchscreen Jonathan Richardson
                   ` (9 subsequent siblings)
  13 siblings, 2 replies; 92+ messages in thread
From: Jonathan Richardson @ 2014-12-17 18:46 UTC (permalink / raw)
  To: Tim Kryger
  Cc: Scott Branden, Arun Ramamurthy, Thierry Reding, Ray Jui,
	bcm-kernel-feedback-list, linux-kernel, linux-pwm,
	Jonathan Richardson

    The config procedure doesn't follow the spec which periodically results
    in failing to enable the output signal. This happens one in ten or
    twenty attempts. Following the spec and adding a 400ns delay in the
    appropriate locations resolves this problem. It also ensures that the
    signal transition is smooth.

    If config is called when the pwm is disabled and there is nothing to do,
    the while loop to calculate duty cycle and period doesn't need to be
    done. The function now just returns if the pwm state is disabled.

    The disable procedure now also follows the spec to ensure a smooth
    transition. Not following the spec can cause non-smooth transitions.

    The enable procedure now clears the enabled bit if enabling failed.
    Enabling can fail if an invalid duty cycle and period is set. This
    prevents the sysfs interface from reporting the pwm is enabled after a
    failed call to enable.

Reviewed-by: Arun Ramamurthy <arunrama@broadcom.com>
Reviewed-by: Scott Branden <sbranden@broadcom.com>
Tested-by: Scott Branden <sbranden@broadcom.com>
Signed-off-by: Jonathan Richardson <jonathar@broadcom.com>
---
 drivers/pwm/pwm-bcm-kona.c |   91 ++++++++++++++++++++++++++++++++------------
 1 file changed, 67 insertions(+), 24 deletions(-)

diff --git a/drivers/pwm/pwm-bcm-kona.c b/drivers/pwm/pwm-bcm-kona.c
index 02bc048..a831bb2 100644
--- a/drivers/pwm/pwm-bcm-kona.c
+++ b/drivers/pwm/pwm-bcm-kona.c
@@ -80,15 +80,19 @@ static void kona_pwmc_apply_settings(struct kona_pwmc *kp, unsigned int chan)
 {
 	unsigned int value = readl(kp->base + PWM_CONTROL_OFFSET);
 
-	/* Clear trigger bit but set smooth bit to maintain old output */
-	value |= 1 << PWM_CONTROL_SMOOTH_SHIFT(chan);
-	value &= ~(1 << PWM_CONTROL_TRIGGER_SHIFT(chan));
-	writel(value, kp->base + PWM_CONTROL_OFFSET);
+	/*
+	 * There must be a min 400ns delay between clearing enable and setting
+	 * it. Failing to do this may result in no PWM signal.
+	 */
+	ndelay(400);
 
 	/* Set trigger bit and clear smooth bit to apply new settings */
 	value &= ~(1 << PWM_CONTROL_SMOOTH_SHIFT(chan));
 	value |= 1 << PWM_CONTROL_TRIGGER_SHIFT(chan);
 	writel(value, kp->base + PWM_CONTROL_OFFSET);
+
+	/* PWMOUT_ENABLE must be held high for at least 400 ns. */
+	ndelay(400);
 }
 
 static int kona_pwmc_config(struct pwm_chip *chip, struct pwm_device *pwm,
@@ -99,6 +103,9 @@ static int kona_pwmc_config(struct pwm_chip *chip, struct pwm_device *pwm,
 	unsigned long prescale = PRESCALE_MIN, pc, dc;
 	unsigned int value, chan = pwm->hwpwm;
 
+	if (!test_bit(PWMF_ENABLED, &pwm->flags))
+		return 0;
+
 	/*
 	 * Find period count, duty count and prescale to suit duty_ns and
 	 * period_ns. This is done according to formulas described below:
@@ -121,31 +128,60 @@ static int kona_pwmc_config(struct pwm_chip *chip, struct pwm_device *pwm,
 		dc = div64_u64(val, div);
 
 		/* If duty_ns or period_ns are not achievable then return */
-		if (pc < PERIOD_COUNT_MIN || dc < DUTY_CYCLE_HIGH_MIN)
+		if (pc < PERIOD_COUNT_MIN) {
+			dev_warn(chip->dev,
+				"%s: pwm[%d]: period=%d is not achievable, pc=%lu, prescale=%lu\n",
+				__func__, chan, period_ns, pc, prescale);
 			return -EINVAL;
+		}
+
+		/* If duty_ns is not achievable then return */
+		if (dc < DUTY_CYCLE_HIGH_MIN) {
+			if (0 != duty_ns) {
+				dev_warn(chip->dev,
+					"%s: pwm[%d]: duty cycle=%d is not achievable, dc=%lu, prescale=%lu\n",
+					__func__, chan, duty_ns, dc, prescale);
+			}
+			return -EINVAL;
+		}
 
 		/* If pc and dc are in bounds, the calculation is done */
 		if (pc <= PERIOD_COUNT_MAX && dc <= DUTY_CYCLE_HIGH_MAX)
 			break;
 
 		/* Otherwise, increase prescale and recalculate pc and dc */
-		if (++prescale > PRESCALE_MAX)
+		if (++prescale > PRESCALE_MAX) {
+			dev_warn(chip->dev,
+				"%s: pwm[%d]: Prescale (=%lu) within max (=%d) for period=%d and duty cycle=%d is not achievable\n",
+				__func__, chan, prescale, PRESCALE_MAX,
+				period_ns, duty_ns);
 			return -EINVAL;
+		}
 	}
 
-	/* If the PWM channel is enabled, write the settings to the HW */
-	if (test_bit(PWMF_ENABLED, &pwm->flags)) {
-		value = readl(kp->base + PRESCALE_OFFSET);
-		value &= ~PRESCALE_MASK(chan);
-		value |= prescale << PRESCALE_SHIFT(chan);
-		writel(value, kp->base + PRESCALE_OFFSET);
+	dev_dbg(chip->dev, "pwm[%d]: period=%lu, duty_high=%lu, prescale=%lu\n",
+		chan, pc, dc, prescale);
 
-		writel(pc, kp->base + PERIOD_COUNT_OFFSET(chan));
+	value = readl(kp->base + PWM_CONTROL_OFFSET);
 
-		writel(dc, kp->base + DUTY_CYCLE_HIGH_OFFSET(chan));
+	/*
+	 * Clear trigger bit but set smooth bit to maintain old
+	 * output.
+	 */
+	value |= 1 << PWM_CONTROL_SMOOTH_SHIFT(chan);
+	value &= ~(1 << PWM_CONTROL_TRIGGER_SHIFT(chan));
+	writel(value, kp->base + PWM_CONTROL_OFFSET);
 
-		kona_pwmc_apply_settings(kp, chan);
-	}
+	value = readl(kp->base + PRESCALE_OFFSET);
+	value &= ~PRESCALE_MASK(chan);
+	value |= prescale << PRESCALE_SHIFT(chan);
+	writel(value, kp->base + PRESCALE_OFFSET);
+
+	writel(pc, kp->base + PERIOD_COUNT_OFFSET(chan));
+
+	writel(dc, kp->base + DUTY_CYCLE_HIGH_OFFSET(chan));
+
+	kona_pwmc_apply_settings(kp, chan);
 
 	return 0;
 }
@@ -173,11 +209,6 @@ static int kona_pwmc_set_polarity(struct pwm_chip *chip, struct pwm_device *pwm,
 
 	writel(value, kp->base + PWM_CONTROL_OFFSET);
 
-	kona_pwmc_apply_settings(kp, chan);
-
-	/* Wait for waveform to settle before gating off the clock */
-	ndelay(400);
-
 	clk_disable_unprepare(kp->clk);
 
 	return 0;
@@ -190,12 +221,14 @@ static int kona_pwmc_enable(struct pwm_chip *chip, struct pwm_device *pwm)
 
 	ret = clk_prepare_enable(kp->clk);
 	if (ret < 0) {
+		clear_bit(PWMF_ENABLED, &pwm->flags);
 		dev_err(chip->dev, "failed to enable clock: %d\n", ret);
 		return ret;
 	}
 
 	ret = kona_pwmc_config(chip, pwm, pwm->duty_cycle, pwm->period);
 	if (ret < 0) {
+		clear_bit(PWMF_ENABLED, &pwm->flags);
 		clk_disable_unprepare(kp->clk);
 		return ret;
 	}
@@ -207,13 +240,23 @@ static void kona_pwmc_disable(struct pwm_chip *chip, struct pwm_device *pwm)
 {
 	struct kona_pwmc *kp = to_kona_pwmc(chip);
 	unsigned int chan = pwm->hwpwm;
+	unsigned int value = readl(kp->base + PWM_CONTROL_OFFSET);
+
+	/* Set smooth type to 1 and disable */
+	value |= 1 << PWM_CONTROL_SMOOTH_SHIFT(chan);
+	value &= ~(1 << PWM_CONTROL_TRIGGER_SHIFT(chan));
+	writel(value, kp->base + PWM_CONTROL_OFFSET);
 
 	/* Simulate a disable by configuring for zero duty */
 	writel(0, kp->base + DUTY_CYCLE_HIGH_OFFSET(chan));
-	kona_pwmc_apply_settings(kp, chan);
+	writel(0, kp->base + PERIOD_COUNT_OFFSET(chan));
 
-	/* Wait for waveform to settle before gating off the clock */
-	ndelay(400);
+	/* Set prescale to 0 for this channel */
+	value = readl(kp->base + PRESCALE_OFFSET);
+	value &= ~PRESCALE_MASK(chan);
+	writel(value, kp->base + PRESCALE_OFFSET);
+
+	kona_pwmc_apply_settings(kp, chan);
 
 	clk_disable_unprepare(kp->clk);
 }
-- 
1.7.9.5


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

* [PATCH v3 2/2] pwm: kona: Remove setting default smooth type and polarity for all channels
  2014-12-17 18:46 ` [PATCH v3 " Jonathan Richardson
@ 2014-12-17 18:46   ` Jonathan Richardson
  2014-12-20 22:38   ` [PATCH v3 1/2] pwm: kona: Fix incorrect enable, config, and disable procedures Tim Kryger
  1 sibling, 0 replies; 92+ messages in thread
From: Jonathan Richardson @ 2014-12-17 18:46 UTC (permalink / raw)
  To: Tim Kryger
  Cc: Scott Branden, Arun Ramamurthy, Thierry Reding, Ray Jui,
	bcm-kernel-feedback-list, linux-kernel, linux-pwm,
	Jonathan Richardson

Setting the default polarity in probe to normal for all channels caused
the speaker pwm channel to click. The polarity does need to be set to
normal because the hw default is inversed whereas the pwm framework
defaults to normal. If a channel is enabled without setting the polarity
then the signal would be inversed while linux reports normal. A check
is now done prior to enabling the channel to ensure that the hw polarity
matches the desired polarity and is changed if there is a discrepency. This
prevents unnecessary settings being applied to unused channels but still
ensures the correct polarity to be set.

Reviewed-by: Scott Branden <sbranden@broadcom.com>
Tested-by: Scott Branden <sbranden@broadcom.com>
Signed-off-by: Jonathan Richardson <jonathar@broadcom.com>
---
 drivers/pwm/pwm-bcm-kona.c |   38 ++++++++++++++++++++++++++++++++++----
 1 file changed, 34 insertions(+), 4 deletions(-)

diff --git a/drivers/pwm/pwm-bcm-kona.c b/drivers/pwm/pwm-bcm-kona.c
index a831bb2..101137d 100644
--- a/drivers/pwm/pwm-bcm-kona.c
+++ b/drivers/pwm/pwm-bcm-kona.c
@@ -95,6 +95,32 @@ static void kona_pwmc_apply_settings(struct kona_pwmc *kp, unsigned int chan)
 	ndelay(400);
 }
 
+static void kona_pwmc_check_set_polarity(struct pwm_chip *chip,
+	struct pwm_device *pwm)
+{
+	struct kona_pwmc *kp = to_kona_pwmc(chip);
+	unsigned int chan = pwm->hwpwm;
+	enum pwm_polarity polarity = pwm->polarity;
+	unsigned int hw_pol;
+	unsigned int value = 0;
+
+	value = hw_pol = readl(kp->base + PWM_CONTROL_OFFSET);
+	hw_pol = (hw_pol >> PWM_CONTROL_POLARITY_SHIFT(chan)) & 0x1;
+
+	/*
+	 * If current polarity not the same as h/w then set polarity so that
+	 * they match.
+	 */
+	if (!hw_pol != polarity) {
+		if (polarity == PWM_POLARITY_NORMAL)
+			value |= 1 << PWM_CONTROL_POLARITY_SHIFT(chan);
+		else
+			value &= ~(1 << PWM_CONTROL_POLARITY_SHIFT(chan));
+
+		writel(value, kp->base + PWM_CONTROL_OFFSET);
+	}
+}
+
 static int kona_pwmc_config(struct pwm_chip *chip, struct pwm_device *pwm,
 			    int duty_ns, int period_ns)
 {
@@ -162,6 +188,13 @@ static int kona_pwmc_config(struct pwm_chip *chip, struct pwm_device *pwm,
 	dev_dbg(chip->dev, "pwm[%d]: period=%lu, duty_high=%lu, prescale=%lu\n",
 		chan, pc, dc, prescale);
 
+	/*
+	 * Ensure polarity is set properly. The default value for h/w and the
+	 * PWM framework are different. If a channel is enabled without setting
+	 * the polarity, the default value would be inconsistent to the signal.
+	 */
+	kona_pwmc_check_set_polarity(chip, pwm);
+
 	value = readl(kp->base + PWM_CONTROL_OFFSET);
 
 	/*
@@ -310,11 +343,8 @@ static int kona_pwmc_probe(struct platform_device *pdev)
 	}
 
 	/* Set smooth mode, push/pull, and normal polarity for all channels */
-	for (chan = 0; chan < kp->chip.npwm; chan++) {
-		value |= (1 << PWM_CONTROL_SMOOTH_SHIFT(chan));
+	for (chan = 0; chan < kp->chip.npwm; chan++)
 		value |= (1 << PWM_CONTROL_TYPE_SHIFT(chan));
-		value |= (1 << PWM_CONTROL_POLARITY_SHIFT(chan));
-	}
 
 	writel(value, kp->base + PWM_CONTROL_OFFSET);
 
-- 
1.7.9.5


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

* [PATCH 0/2]  Add support for Broadcom iProc touchscreen
       [not found] <Jonathan Richardson <jonathar@broadcom.com>
                   ` (3 preceding siblings ...)
  2014-12-17 18:46 ` [PATCH v3 " Jonathan Richardson
@ 2014-12-18  1:59 ` Jonathan Richardson
  2014-12-18  1:59   ` [PATCH 1/2] Input: touchscreen-iproc: Add Broadcom iProc touchscreen driver Jonathan Richardson
  2014-12-18  1:59   ` [PATCH 2/2] Input: touchscreen-iproc: add device tree bindings Jonathan Richardson
  2014-12-19 22:17 ` [PATCH v2 0/2] Add support for Broadcom iProc touchscreen Jonathan Richardson
                   ` (8 subsequent siblings)
  13 siblings, 2 replies; 92+ messages in thread
From: Jonathan Richardson @ 2014-12-18  1:59 UTC (permalink / raw)
  To: Dmitry Torokhov, Grant Likely, Rob Herring
  Cc: Ray Jui, Jonathan Richardson, linux-kernel, linux-input,
	linux-arm-kernel, bcm-kernel-feedback-list, devicetree

This patchset contains initial support for the touchscreen on the Broadcom
iProc family of SoCs. This driver has been validated with Cygnus and is expected
to work on other iProc family of SoCs that use the same touchscreen controller.

Jonathan Richardson (2):
  Input: touchscreen-iproc: Add Broadcom iProc touchscreen driver
  Input: touchscreen-iproc: add device tree bindings

 .../input/touchscreen/brcm,iproc-touchscreen.txt   |   70 +++
 drivers/input/touchscreen/Kconfig                  |   11 +
 drivers/input/touchscreen/Makefile                 |    1 +
 drivers/input/touchscreen/bcm_iproc_tsc.c          |  559 ++++++++++++++++++++
 4 files changed, 641 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/input/touchscreen/brcm,iproc-touchscreen.txt
 create mode 100644 drivers/input/touchscreen/bcm_iproc_tsc.c

-- 
1.7.9.5


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

* [PATCH 1/2] Input: touchscreen-iproc: Add Broadcom iProc touchscreen driver
  2014-12-18  1:59 ` [PATCH 0/2] Add support for Broadcom iProc touchscreen Jonathan Richardson
@ 2014-12-18  1:59   ` Jonathan Richardson
  2014-12-18  2:14     ` Joe Perches
  2014-12-18  1:59   ` [PATCH 2/2] Input: touchscreen-iproc: add device tree bindings Jonathan Richardson
  1 sibling, 1 reply; 92+ messages in thread
From: Jonathan Richardson @ 2014-12-18  1:59 UTC (permalink / raw)
  To: Dmitry Torokhov, Grant Likely, Rob Herring
  Cc: Ray Jui, Jonathan Richardson, linux-kernel, linux-input,
	linux-arm-kernel, bcm-kernel-feedback-list, devicetree

Add initial version of the Broadcom touchscreen driver.

Reviewed-by: Ray Jui <rjui@broadcom.com>
Reviewed-by: Scott Branden <sbranden@broadcom.com>
Tested-by: Scott Branden <sbranden@broadcom.com>
Signed-off-by: Jonathan Richardson <jonathar@broadcom.com>
---
 drivers/input/touchscreen/Kconfig         |   11 +
 drivers/input/touchscreen/Makefile        |    1 +
 drivers/input/touchscreen/bcm_iproc_tsc.c |  559 +++++++++++++++++++++++++++++
 3 files changed, 571 insertions(+)
 create mode 100644 drivers/input/touchscreen/bcm_iproc_tsc.c

diff --git a/drivers/input/touchscreen/Kconfig b/drivers/input/touchscreen/Kconfig
index e1d8003..77ff531 100644
--- a/drivers/input/touchscreen/Kconfig
+++ b/drivers/input/touchscreen/Kconfig
@@ -310,6 +310,17 @@ config TOUCHSCREEN_ILI210X
 	  To compile this driver as a module, choose M here: the
 	  module will be called ili210x.
 
+config TOUCHSCREEN_IPROC
+	tristate "IPROC touch panel driver support"
+	help
+	  Say Y here if you want to add support for the IPROC touch
+	  controller to your system.
+
+	  If unsure, say N.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called iproc-ts.
+
 config TOUCHSCREEN_S3C2410
 	tristate "Samsung S3C2410/generic touchscreen input driver"
 	depends on ARCH_S3C24XX || SAMSUNG_DEV_TS
diff --git a/drivers/input/touchscreen/Makefile b/drivers/input/touchscreen/Makefile
index 090e61c..f7e6de9 100644
--- a/drivers/input/touchscreen/Makefile
+++ b/drivers/input/touchscreen/Makefile
@@ -37,6 +37,7 @@ obj-$(CONFIG_TOUCHSCREEN_FUJITSU)	+= fujitsu_ts.o
 obj-$(CONFIG_TOUCHSCREEN_ILI210X)	+= ili210x.o
 obj-$(CONFIG_TOUCHSCREEN_INEXIO)	+= inexio.o
 obj-$(CONFIG_TOUCHSCREEN_INTEL_MID)	+= intel-mid-touch.o
+obj-$(CONFIG_TOUCHSCREEN_IPROC)		+= bcm_iproc_tsc.o
 obj-$(CONFIG_TOUCHSCREEN_LPC32XX)	+= lpc32xx_ts.o
 obj-$(CONFIG_TOUCHSCREEN_MAX11801)	+= max11801_ts.o
 obj-$(CONFIG_TOUCHSCREEN_MC13783)	+= mc13783_ts.o
diff --git a/drivers/input/touchscreen/bcm_iproc_tsc.c b/drivers/input/touchscreen/bcm_iproc_tsc.c
new file mode 100644
index 0000000..6f0fa71
--- /dev/null
+++ b/drivers/input/touchscreen/bcm_iproc_tsc.c
@@ -0,0 +1,559 @@
+/*
+* Copyright (C) 2014 Broadcom Corporation
+*
+* This program is free software; you can redistribute it and/or
+* modify it under the terms of the GNU General Public License as
+* published by the Free Software Foundation version 2.
+*
+* This program is distributed "as is" WITHOUT ANY WARRANTY of any
+* kind, whether express or implied; without even the implied warranty
+* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*/
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/input.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/keyboard.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/of.h>
+#include <asm/irq.h>
+#include <linux/io.h>
+#include <linux/clk.h>
+#include <linux/serio.h>
+
+#define IPROC_TS_NAME "iproc-ts"
+
+#define PEN_DOWN_STATUS     1
+#define PEN_UP_STATUS       0
+
+#define X_MIN               0
+#define Y_MIN               0
+#define X_MAX               0xFFF
+#define Y_MAX               0xFFF
+
+/* Value given by controller for invalid coordinate. */
+#define INVALID_COORD       0xFFFFFFFF
+
+/* Register offsets */
+#define REGCTL1             0x00
+#define REGCTL2             0x04
+#define INTERRUPT_THRES     0x08
+#define INTERRUPT_MASK      0x0c
+
+#define INTERRUPT_STATUS    0x10
+#define CONTROLLER_STATUS   0x14
+#define FIFO_DATA           0x18
+#define FIFO_DATA_X_Y_MASK  0xFFFF
+#define ANALOG_CONTROL      0x1c
+
+#define AUX_DATA            0x20
+#define DEBOUNCE_CNTR_STAT  0x24
+#define SCAN_CNTR_STAT      0x28
+#define REM_CNTR_STAT       0x2c
+
+#define SETTLING_TIMER_STAT 0x30
+#define SPARE_REG           0x34
+#define SOFT_BYPASS_CONTROL 0x38
+#define SOFT_BYPASS_DATA    0x3c
+
+
+/* Bit values for INTERRUPT_MASK and INTERRUPT_STATUS regs */
+#define TS_PEN_INTR_MASK        (1<<0)
+#define TS_FIFO_INTR_MASK       (1<<2)
+
+/* Bit values for CONTROLLER_STATUS reg1 */
+#define TS_PEN_DOWN             (1<<0)
+
+/* Shift values for control reg1 */
+#define SCANNING_PERIOD_SHIFT   24
+#define DEBOUNCE_TIMEOUT_SHIFT  16
+#define SETTLING_TIMEOUT_SHIFT  8
+#define TOUCH_TIMEOUT_SHIFT     0
+
+/* Shift values for coordinates from fifo */
+#define X_COORD_SHIFT  0
+#define Y_COORD_SHIFT  16
+
+/* Bit values for REGCTL2 */
+#define TS_CONTROLLER_EN_BIT    (1 << 16)
+#define TS_CONTROLLER_AVGDATA_SHIFT 8
+#define TS_CONTROLLER_AVGDATA_MASK (0x7 << TS_CONTROLLER_AVGDATA_SHIFT)
+#define TS_CONTROLLER_PWR_LDO   (1<<5)
+#define TS_CONTROLLER_PWR_ADC   (1<<4)
+#define TS_CONTROLLER_PWR_BGP   (1<<3)
+#define TS_CONTROLLER_PWR_TS    (1<<2)
+#define TS_WIRE_MODE_BIT        (1<<1)
+
+/*
+ * Touch screen mount angles w.r.t LCD panel left side top corner
+ * TS (x_min,y_min) placed at LCD (x_min,y_min) rotation angle is 0
+ * TS (x_min,y_max) placed at LCD (x_min,y_min) rotation angle is 90
+ * TS (x_max,y_max) placed at LCD (x_min,y_min) rotation angle is 180
+ * TS (x_max,y_min) placed at LCD (x_min,y_min) rotation angle is 270
+ */
+enum ts_rotation_angles {
+	TS_ROTATION_0,
+	TS_ROTATION_90,
+	TS_ROTATION_180,
+	TS_ROTATION_270,
+};
+
+struct tsc_param {
+	/* Each step is 1024 us.  Valid 1-256 */
+	u32 scanning_period;
+
+	/*  Each step is 512 us.  Valid 0-255 */
+	u32 debounce_timeout;
+
+	/*
+	 * The settling duration (in ms) is the amount of time the tsc
+	 * waits to allow the voltage to settle after turning on the
+	 * drivers in detection mode. Valid values: 0-11
+	 *   0 =  0.008 ms
+	 *   1 =  0.01 ms
+	 *   2 =  0.02 ms
+	 *   3 =  0.04 ms
+	 *   4 =  0.08 ms
+	 *   5 =  0.16 ms
+	 *   6 =  0.32 ms
+	 *   7 =  0.64 ms
+	 *   8 =  1.28 ms
+	 *   9 =  2.56 ms
+	 *   10 = 5.12 ms
+	 *   11 = 10.24 ms
+	 */
+	u32 settling_timeout;
+
+	/* touch timeout in sample counts */
+	u32 touch_timeout;
+
+	/*
+	 * Number of data samples which are averaged before a final data point
+	 * is placed into the FIFO
+	 */
+	u32 average_data;
+
+	/* FIFO threshold */
+	u32 fifo_threshold;
+};
+
+struct iproc_ts_priv {
+	struct platform_device *pdev;
+	struct input_dev *idev;
+
+	void __iomem *regs;
+	struct clk *tsc_clk;
+
+	int  pen_status;
+	int  ts_rotation;
+	struct tsc_param cfg_params;
+};
+
+/*
+ * Set default values the same as hardware reset values
+ * except for fifo_threshold with is set to 1.
+ */
+static struct tsc_param default_config = {
+	.scanning_period  = 0x5,  /* 1 to 256 */
+	.debounce_timeout = 0x28, /* 0 to 255 */
+	.settling_timeout = 0x7,  /* 0 to 11 */
+	.touch_timeout    = 0xa,  /* 0 to 255 */
+	.average_data     = 5,    /* entry 5 = 32 pts */
+	.fifo_threshold   = 1,    /* 0 to 31 */
+};
+
+static void ts_reg_dump(struct iproc_ts_priv *priv)
+{
+	struct device *dev = &priv->pdev->dev;
+
+	dev_dbg(dev, "regCtl1             = 0x%08x\n",
+				readl(priv->regs + REGCTL1));
+	dev_dbg(dev, "regCtl2             = 0x%08x\n",
+				readl(priv->regs + REGCTL2));
+	dev_dbg(dev, "interrupt_Thres     = 0x%08x\n",
+				readl(priv->regs + INTERRUPT_THRES));
+	dev_dbg(dev, "interrupt_Mask      = 0x%08x\n",
+				readl(priv->regs + INTERRUPT_MASK));
+	dev_dbg(dev, "interrupt_Status    = 0x%08x\n",
+				readl(priv->regs + INTERRUPT_STATUS));
+	dev_dbg(dev, "controller_Status   = 0x%08x\n",
+				readl(priv->regs + CONTROLLER_STATUS));
+	dev_dbg(dev, "FIFO_Data           = 0x%08x\n",
+				readl(priv->regs + FIFO_DATA));
+	dev_dbg(dev, "analog_Control      = 0x%08x\n",
+				readl(priv->regs + ANALOG_CONTROL));
+	dev_dbg(dev, "aux_Data            = 0x%08x\n",
+				readl(priv->regs + AUX_DATA));
+	dev_dbg(dev, "debounce_Cntr_Stat  = 0x%08x\n",
+				readl(priv->regs + DEBOUNCE_CNTR_STAT));
+	dev_dbg(dev, "scan_Cntr_Stat      = 0x%08x\n",
+				readl(priv->regs + SCAN_CNTR_STAT));
+	dev_dbg(dev, "rem_Cntr_Stat       = 0x%08x\n",
+				readl(priv->regs + REM_CNTR_STAT));
+	dev_dbg(dev, "settling_Timer_Stat = 0x%08x\n",
+				readl(priv->regs + SETTLING_TIMER_STAT));
+	dev_dbg(dev, "spare_Reg           = 0x%08x\n",
+				readl(priv->regs + SPARE_REG));
+	dev_dbg(dev, "soft_Bypass_Control = 0x%08x\n",
+				readl(priv->regs + SOFT_BYPASS_CONTROL));
+	dev_dbg(dev, "soft_Bypass_Data    = 0x%08x\n",
+				readl(priv->regs + SOFT_BYPASS_DATA));
+}
+
+static irqreturn_t iproc_touchscreen_interrupt(int irq, void *data)
+{
+	struct platform_device *pdev = (struct platform_device *)data;
+	struct iproc_ts_priv *priv;
+	u32 intr_status = 0;
+	u32 raw_coordinate = 0;
+	u16 x = 0;
+	u16 y = 0;
+	int i;
+
+	priv = (struct iproc_ts_priv *)platform_get_drvdata(pdev);
+
+	intr_status = readl(priv->regs + INTERRUPT_STATUS);
+	intr_status &= (TS_PEN_INTR_MASK | TS_FIFO_INTR_MASK);
+	if (intr_status == 0)
+		return IRQ_NONE;
+
+	/* Clear all interrupt status bits, write-1-clear */
+	writel(intr_status, priv->regs + INTERRUPT_STATUS);
+
+	/* Pen up/down */
+	if (intr_status & TS_PEN_INTR_MASK) {
+		if (readl(priv->regs + CONTROLLER_STATUS) & TS_PEN_DOWN) {
+			priv->pen_status = PEN_DOWN_STATUS;
+			input_report_key(priv->idev, BTN_TOUCH,
+				priv->pen_status);
+		} else {
+			priv->pen_status = PEN_UP_STATUS;
+			input_report_key(priv->idev, BTN_TOUCH,
+				priv->pen_status);
+			input_sync(priv->idev);
+		}
+
+		dev_dbg(&priv->pdev->dev,
+			"pen up-down (%d)\n", priv->pen_status);
+	}
+
+	/* coordinates in FIFO exceed the theshold */
+	if (intr_status & TS_FIFO_INTR_MASK) {
+		for (i = 0; i < priv->cfg_params.fifo_threshold; i++) {
+			raw_coordinate = readl(priv->regs + FIFO_DATA);
+			if (raw_coordinate == INVALID_COORD)
+				continue;
+
+			/*
+			 * The x and y coordinate are 16 bits each
+			 * with the x in the lower 16 bits and y in the
+			 * upper 16 bits.
+			 */
+			x = (raw_coordinate >> X_COORD_SHIFT) &
+				FIFO_DATA_X_Y_MASK;
+			y = (raw_coordinate >> Y_COORD_SHIFT) &
+				FIFO_DATA_X_Y_MASK;
+
+			/* We only want to retain the 12 msb of the 16 */
+			x = (x >> 4) & 0x0FFF;
+			y = (y >> 4) & 0x0FFF;
+
+			/* adjust x y according to lcd tsc mount angle */
+			if (priv->ts_rotation == TS_ROTATION_90) {
+				y = Y_MAX - y;
+			} else if (priv->ts_rotation == TS_ROTATION_180) {
+				x = X_MAX - x;
+				y = Y_MAX - y;
+			} else if (priv->ts_rotation == TS_ROTATION_270) {
+				x = X_MAX - x;
+			}
+
+			input_report_abs(priv->idev, ABS_X, x);
+			input_report_abs(priv->idev, ABS_Y, y);
+			input_sync(priv->idev);
+
+			dev_dbg(&priv->pdev->dev, "xy (0x%x 0x%x)\n", x, y);
+		}
+	}
+
+	return IRQ_HANDLED;
+}
+
+static int iproc_ts_start(struct input_dev *idev)
+{
+	u32 val;
+	int ret;
+	struct iproc_ts_priv *priv;
+
+	priv = input_get_drvdata(idev);
+	if (priv == NULL)
+		return -ENODEV;
+
+	/* Enable clock */
+	ret = clk_prepare_enable(priv->tsc_clk);
+	if (ret) {
+		dev_err(&priv->pdev->dev, "%s clk_prepare_enable failed %d\n",
+			__func__, ret);
+		return ret;
+	}
+
+	/*
+	 * Interrupt is generated when:
+	 *  FIFO reaches the int_th value, and pen event(up/down)
+	 */
+	val = TS_PEN_INTR_MASK | TS_FIFO_INTR_MASK;
+	writel(val, priv->regs + INTERRUPT_MASK);
+
+	writel(priv->cfg_params.fifo_threshold, priv->regs + INTERRUPT_THRES);
+
+	/* Initialize control reg1 */
+	val = 0;
+	val |= (priv->cfg_params.scanning_period << SCANNING_PERIOD_SHIFT);
+	val |= (priv->cfg_params.debounce_timeout << DEBOUNCE_TIMEOUT_SHIFT);
+	val |= (priv->cfg_params.settling_timeout << SETTLING_TIMEOUT_SHIFT);
+	val |= (priv->cfg_params.touch_timeout << TOUCH_TIMEOUT_SHIFT);
+	writel(val, priv->regs + REGCTL1);
+
+	/* Try to clear all interrupt status */
+	val = readl(priv->regs + INTERRUPT_STATUS);
+	val |= (TS_FIFO_INTR_MASK | TS_PEN_INTR_MASK);
+	writel(val, priv->regs + INTERRUPT_STATUS);
+
+	/* Initialize control reg2 */
+	val = readl(priv->regs + REGCTL2);
+	val |= (TS_CONTROLLER_EN_BIT | TS_WIRE_MODE_BIT);
+
+	val &= ~(TS_CONTROLLER_AVGDATA_MASK);
+	val |= (priv->cfg_params.average_data << TS_CONTROLLER_AVGDATA_SHIFT);
+
+	val &= ~(TS_CONTROLLER_PWR_LDO |	/* PWR up LDO */
+		   TS_CONTROLLER_PWR_ADC |	/* PWR up ADC */
+		   TS_CONTROLLER_PWR_BGP |	/* PWR up BGP */
+		   TS_CONTROLLER_PWR_TS);	/* PWR up TS */
+
+	writel(val, priv->regs + REGCTL2);
+
+	ts_reg_dump(priv);
+
+	return 0;
+}
+
+static void iproc_ts_stop(struct input_dev *dev)
+{
+	u32 val;
+	struct iproc_ts_priv *priv;
+
+	priv = input_get_drvdata(dev);
+	if (priv == NULL)
+		return;
+
+	writel(0, priv->regs + INTERRUPT_MASK); /* Disable all interrupts */
+
+	/* Only power down touch screen controller */
+	val = readl(priv->regs + REGCTL2);
+	val |= TS_CONTROLLER_PWR_TS;
+	writel(val, priv->regs + REGCTL2);
+
+	clk_disable(priv->tsc_clk);
+}
+
+static int get_tsc_config(struct device_node *np, struct iproc_ts_priv *priv)
+{
+	int ret;
+	u32 val;
+	struct device *dev = &priv->pdev->dev;
+
+	priv->cfg_params = default_config;
+
+	ret = of_property_read_u32(np, "scanning_period", &val);
+	if (ret >= 0) {
+		if ((1 <= val) && (val <= 256))
+			priv->cfg_params.scanning_period = val;
+		else {
+			dev_err(dev, "scanning_period must be [1-256]");
+			return -EINVAL;
+		}
+	}
+
+	ret = of_property_read_u32(np, "debounce_timeout", &val);
+	if (ret >= 0) {
+		if ((0 <= val) && (val <= 255))
+			priv->cfg_params.debounce_timeout = val;
+		else {
+			dev_err(dev, "debounce_timeout must be [0-255]");
+			return -EINVAL;
+		}
+	}
+
+	ret = of_property_read_u32(np, "settling_timeout", &val);
+	if (ret >= 0) {
+		if ((0 <= val) && (val <= 11))
+			priv->cfg_params.settling_timeout = val;
+		else {
+			dev_err(dev, "settling_timeout must be [0-11]");
+			return -EINVAL;
+		}
+	}
+
+	ret = of_property_read_u32(np, "touch_timeout", &val);
+	if (ret >= 0) {
+		if ((0 <= val) && (val <= 255))
+			priv->cfg_params.touch_timeout = val;
+		else {
+			dev_err(dev, "touch_timeout must be [0-255]");
+			return -EINVAL;
+		}
+	}
+
+	ret = of_property_read_u32(np, "average_data", &val);
+	if (ret >= 0) {
+		if ((0 <= val) && (val <= 7))
+			priv->cfg_params.average_data = val;
+		else {
+			dev_err(dev, "average_data must be [0-8]");
+			return -EINVAL;
+		}
+	}
+
+	ret = of_property_read_u32(np, "fifo_threshold", &val);
+	if (ret >= 0) {
+		if ((0 <= val) && (val <= 31))
+			priv->cfg_params.fifo_threshold = val;
+		else {
+			dev_err(dev, "fifo_threshold must be [0-31]");
+			return -EINVAL;
+		}
+	}
+	priv->ts_rotation = TS_ROTATION_0;
+	ret = of_property_read_u32(np, "ts-rotation", &val);
+	if (ret >= 0) {
+		priv->ts_rotation = val;
+		dev_dbg(dev, "ts rotation [%d] degrees\n",
+			90 * priv->ts_rotation);
+	}
+
+	return 0;
+}
+
+static int iproc_ts_probe(struct platform_device *pdev)
+{
+	struct iproc_ts_priv *priv;
+	struct input_dev *idev;
+	struct resource *res;
+	int ret;
+	int irq;
+
+	priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
+	if (!priv)
+		return -ENOMEM;
+
+	/* touchscreen controller memory mapped regs */
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	priv->regs = devm_ioremap_resource(&pdev->dev, res);
+	if (IS_ERR(priv->regs)) {
+		dev_err(&pdev->dev, "unable to map I/O memory\n");
+		return PTR_ERR(priv->regs);
+	}
+
+	priv->tsc_clk = devm_clk_get(&pdev->dev, "tsc_clk");
+	if (IS_ERR(priv->tsc_clk)) {
+		dev_err(&pdev->dev,
+			"%s Failed getting clock tsc_clk\n", __func__);
+		return PTR_ERR(priv->tsc_clk);
+	}
+
+	ret = get_tsc_config(pdev->dev.of_node, priv);
+	if (ret != 0) {
+		dev_err(&pdev->dev, "%s get_tsc_config failed\n", __func__);
+		return ret;
+	}
+
+	idev = devm_input_allocate_device(&pdev->dev);
+	if (!idev) {
+		dev_err(&pdev->dev,
+			"%s Allocate input device failed\n", __func__);
+		return -ENOMEM;
+	}
+
+	priv->idev = idev;
+	priv->pdev = pdev;
+
+	priv->pen_status = PEN_UP_STATUS;
+
+	/* Set input device info  */
+	idev->name = IPROC_TS_NAME;
+	idev->dev.parent = &pdev->dev;
+
+	idev->id.bustype = BUS_HOST;
+	idev->id.vendor = SERIO_UNKNOWN;
+	idev->id.product = 0;
+	idev->id.version = 0;
+
+	idev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS);
+	set_bit(BTN_TOUCH, idev->keybit);
+
+	input_set_abs_params(idev, ABS_X, X_MIN, X_MAX, 0, 0);
+	input_set_abs_params(idev, ABS_Y, Y_MIN, Y_MAX, 0, 0);
+
+	idev->open = iproc_ts_start;
+	idev->close = iproc_ts_stop;
+
+	input_set_drvdata(idev, priv);
+	platform_set_drvdata(pdev, priv);
+
+	/* get interrupt */
+	irq = platform_get_irq(pdev, 0);
+	if (irq < 0) {
+		dev_err(&pdev->dev, "%s platform_get_irq failed\n", __func__);
+		return irq;
+	}
+
+	ret = devm_request_irq(&pdev->dev, irq,
+		iproc_touchscreen_interrupt,
+		IRQF_SHARED, IPROC_TS_NAME, pdev);
+	if (ret)
+		return ret;
+
+	ret = input_register_device(priv->idev);
+	if (ret) {
+		dev_err(&pdev->dev,
+			"%s register input device failed %d\n", __func__, ret);
+		return ret;
+	}
+
+	return 0;
+}
+
+static int iproc_ts_remove(struct platform_device *pdev)
+{
+	struct iproc_ts_priv *priv = platform_get_drvdata(pdev);
+
+	platform_set_drvdata(pdev, NULL);
+	input_unregister_device(priv->idev);
+
+	return 0;
+}
+
+static const struct of_device_id iproc_ts_of_match[] = {
+	{.compatible = "brcm,iproc-touchscreen", },
+	{ },
+};
+MODULE_DEVICE_TABLE(of, iproc_ts_of_match);
+
+static struct platform_driver iproc_ts_driver = {
+	.probe = iproc_ts_probe,
+	.remove = iproc_ts_remove,
+	.driver = {
+		.name	= IPROC_TS_NAME,
+		.of_match_table = of_match_ptr(iproc_ts_of_match),
+	},
+};
+
+module_platform_driver(iproc_ts_driver);
+
+MODULE_DESCRIPTION("IPROC Touchscreen driver");
+MODULE_AUTHOR("Broadcom");
+MODULE_LICENSE("GPL v2");
-- 
1.7.9.5


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

* [PATCH 2/2] Input: touchscreen-iproc: add device tree bindings
  2014-12-18  1:59 ` [PATCH 0/2] Add support for Broadcom iProc touchscreen Jonathan Richardson
  2014-12-18  1:59   ` [PATCH 1/2] Input: touchscreen-iproc: Add Broadcom iProc touchscreen driver Jonathan Richardson
@ 2014-12-18  1:59   ` Jonathan Richardson
  1 sibling, 0 replies; 92+ messages in thread
From: Jonathan Richardson @ 2014-12-18  1:59 UTC (permalink / raw)
  To: Dmitry Torokhov, Grant Likely, Rob Herring
  Cc: Ray Jui, Jonathan Richardson, linux-kernel, linux-input,
	linux-arm-kernel, bcm-kernel-feedback-list, devicetree

Documents the touchscreen device tree binding for Broadcom iProc family
of SoCs.

Reviewed-by: Scott Branden <sbranden@broadcom.com>
Tested-by: Scott Branden <sbranden@broadcom.com>
Signed-off-by: Jonathan Richardson <jonathar@broadcom.com>
---
 .../input/touchscreen/brcm,iproc-touchscreen.txt   |   70 ++++++++++++++++++++
 1 file changed, 70 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/input/touchscreen/brcm,iproc-touchscreen.txt

diff --git a/Documentation/devicetree/bindings/input/touchscreen/brcm,iproc-touchscreen.txt b/Documentation/devicetree/bindings/input/touchscreen/brcm,iproc-touchscreen.txt
new file mode 100644
index 0000000..eb28822
--- /dev/null
+++ b/Documentation/devicetree/bindings/input/touchscreen/brcm,iproc-touchscreen.txt
@@ -0,0 +1,70 @@
+* Broadcom's IPROC Touchscreen Controller
+
+Required properties:
+- compatible: must be "brcm,iproc-touchscreen"
+- reg: physical base address of the controller and length of memory mapped
+  region.
+- clocks:  The clock provided by the SOC to driver the tsc
+- clock-name:  name for the clock
+- interrupts: The touchscreen controller's interrupt
+
+Optional properties:
+- scanning_period: Time between scans. Each step is 1024 us.  Valid 1-256.
+- debounce_timeout: Each step is 512 us.  Valid 0-255
+- settling_timeout: The settling duration (in ms) is the amount of time
+                    the tsc waits to allow the voltage to settle after
+                    turning on the drivers in detection mode.
+                    Valid values: 0-11
+                    0 =  0.008 ms
+                    1 =  0.01 ms
+                    2 =  0.02 ms
+                    3 =  0.04 ms
+                    4 =  0.08 ms
+                    5 =  0.16 ms
+                    6 =  0.32 ms
+                    7 =  0.64 ms
+                    8 =  1.28 ms
+                    9 =  2.56 ms
+                   10 =  5.12 ms
+                   11 = 10.24 ms
+- touch_timeout: The continuous number of scan periods in which touch is
+                not detected before the controller returns to idle state.
+                Valid values 0-255.
+- average_data: Number of data samples which are averaged before a final
+                data point is placed into the FIFO
+                Valid values 0-7
+                0 =   1 sample
+                1 =   2 samples
+                2 =   4 samples
+                3 =   8 samples
+                4 =  16 samples
+                5 =  32 samples
+                6 =  64 samples
+                7 = 128 samples
+- fifo_threshold: Interrupt is generated whenever the number of fifo
+                entries exceeds this value
+                Valid values 0-31
+- ts-rotation: Touch screen controller and display panel orientation angle.
+		0 = Tsc x_min y_min placed at LCD x_min y_min. None
+		1 = Tsc x_min y_max placed at LCD x_min y_min. 90 degrees
+		2 = Tsc x_max y_max placed at LCD x_min y_min. 180 degrees
+		3 = Tsc x_max y_min placed at LCD x_min y_min. 270 degrees
+Example:
+
+	touchscreen: tsc@0x180A6000 {
+		compatible = "brcm,iproc-touchscreen";
+		#address-cells = <1>;
+		#size-cells = <1>;
+		reg = <0x180A6000 0x40>;
+		clocks = <&adc_clk>;
+		clock-names = "tsc_clk";
+		interrupts = <GIC_SPI 164 IRQ_TYPE_LEVEL_HIGH>;
+
+		scanning_period = <5>;
+		debounce_timeout = <40>;
+		settling_timeout = <7>;
+		touch_timeout = <10>;
+		average_data = <5>;
+		fifo_threshold = <1>;
+		ts-rotation = <2>;
+	};
-- 
1.7.9.5


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

* Re: [PATCH 1/2] Input: touchscreen-iproc: Add Broadcom iProc touchscreen driver
  2014-12-18  1:59   ` [PATCH 1/2] Input: touchscreen-iproc: Add Broadcom iProc touchscreen driver Jonathan Richardson
@ 2014-12-18  2:14     ` Joe Perches
  2014-12-19 19:51       ` Jonathan Richardson
  0 siblings, 1 reply; 92+ messages in thread
From: Joe Perches @ 2014-12-18  2:14 UTC (permalink / raw)
  To: Jonathan Richardson
  Cc: Dmitry Torokhov, Grant Likely, Rob Herring, Ray Jui,
	linux-kernel, linux-input, linux-arm-kernel,
	bcm-kernel-feedback-list, devicetree

On Wed, 2014-12-17 at 17:59 -0800, Jonathan Richardson wrote:
> Add initial version of the Broadcom touchscreen driver.

trivia:

> diff --git a/drivers/input/touchscreen/bcm_iproc_tsc.c b/drivers/input/touchscreen/bcm_iproc_tsc.c

> +/* Bit values for REGCTL2 */
> +#define TS_CONTROLLER_EN_BIT    (1 << 16)
> +#define TS_CONTROLLER_AVGDATA_SHIFT 8
> +#define TS_CONTROLLER_AVGDATA_MASK (0x7 << TS_CONTROLLER_AVGDATA_SHIFT)
> +#define TS_CONTROLLER_PWR_LDO   (1<<5)
> +#define TS_CONTROLLER_PWR_ADC   (1<<4)
> +#define TS_CONTROLLER_PWR_BGP   (1<<3)
> +#define TS_CONTROLLER_PWR_TS    (1<<2)
> +#define TS_WIRE_MODE_BIT        (1<<1)

Be nicer to use the same spacing around <<
or maybe use the BIT macro.

[]

> +static int get_tsc_config(struct device_node *np, struct iproc_ts_priv *priv)
> +{
> +	int ret;
> +	u32 val;
> +	struct device *dev = &priv->pdev->dev;
> +
> +	priv->cfg_params = default_config;
> +
> +	ret = of_property_read_u32(np, "scanning_period", &val);
> +	if (ret >= 0) {
> +		if ((1 <= val) && (val <= 256))
> +			priv->cfg_params.scanning_period = val;
> +		else {
> +			dev_err(dev, "scanning_period must be [1-256]");
> +			return -EINVAL;
> +		}

ret is never used so I'd probably remove it
from all these blocks.

It's probably be nicer to invert the logic ald
remove the else.

There's a missing terminating newline too.

Something like:

	if (of_property_read_u32(np, "scanning_period", &val) >= 0) {
		if (val < 1 || val > 256) {
			dev_err(dev, "scanning_period must be [1-256]\n");
			return -EINVAL;
		}
		priv->cfg_params.scanning_period = val;
	}

etc...



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

* Re: [PATCH 1/2] Input: touchscreen-iproc: Add Broadcom iProc touchscreen driver
  2014-12-18  2:14     ` Joe Perches
@ 2014-12-19 19:51       ` Jonathan Richardson
  2014-12-19 19:56         ` Dmitry Torokhov
  0 siblings, 1 reply; 92+ messages in thread
From: Jonathan Richardson @ 2014-12-19 19:51 UTC (permalink / raw)
  To: Joe Perches
  Cc: Dmitry Torokhov, Grant Likely, Rob Herring, Ray Jui,
	linux-kernel, linux-input, linux-arm-kernel,
	bcm-kernel-feedback-list, devicetree

Thanks Joe. I'll send out a new patch set with your suggestions/fixes
shortly.

On 14-12-17 06:14 PM, Joe Perches wrote:
> On Wed, 2014-12-17 at 17:59 -0800, Jonathan Richardson wrote:
>> Add initial version of the Broadcom touchscreen driver.
> 
> trivia:
> 
>> diff --git a/drivers/input/touchscreen/bcm_iproc_tsc.c b/drivers/input/touchscreen/bcm_iproc_tsc.c
> 
>> +/* Bit values for REGCTL2 */
>> +#define TS_CONTROLLER_EN_BIT    (1 << 16)
>> +#define TS_CONTROLLER_AVGDATA_SHIFT 8
>> +#define TS_CONTROLLER_AVGDATA_MASK (0x7 << TS_CONTROLLER_AVGDATA_SHIFT)
>> +#define TS_CONTROLLER_PWR_LDO   (1<<5)
>> +#define TS_CONTROLLER_PWR_ADC   (1<<4)
>> +#define TS_CONTROLLER_PWR_BGP   (1<<3)
>> +#define TS_CONTROLLER_PWR_TS    (1<<2)
>> +#define TS_WIRE_MODE_BIT        (1<<1)
> 
> Be nicer to use the same spacing around <<
> or maybe use the BIT macro.
> 
> []
> 
>> +static int get_tsc_config(struct device_node *np, struct iproc_ts_priv *priv)
>> +{
>> +	int ret;
>> +	u32 val;
>> +	struct device *dev = &priv->pdev->dev;
>> +
>> +	priv->cfg_params = default_config;
>> +
>> +	ret = of_property_read_u32(np, "scanning_period", &val);
>> +	if (ret >= 0) {
>> +		if ((1 <= val) && (val <= 256))
>> +			priv->cfg_params.scanning_period = val;
>> +		else {
>> +			dev_err(dev, "scanning_period must be [1-256]");
>> +			return -EINVAL;
>> +		}
> 
> ret is never used so I'd probably remove it
> from all these blocks.
> 
> It's probably be nicer to invert the logic ald
> remove the else.
> 
> There's a missing terminating newline too.
> 
> Something like:
> 
> 	if (of_property_read_u32(np, "scanning_period", &val) >= 0) {
> 		if (val < 1 || val > 256) {
> 			dev_err(dev, "scanning_period must be [1-256]\n");
> 			return -EINVAL;
> 		}
> 		priv->cfg_params.scanning_period = val;
> 	}
> 
> etc...
> 
> 
> --
> To unsubscribe from this list: send the line "unsubscribe devicetree" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
> 


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

* Re: [PATCH 1/2] Input: touchscreen-iproc: Add Broadcom iProc touchscreen driver
  2014-12-19 19:51       ` Jonathan Richardson
@ 2014-12-19 19:56         ` Dmitry Torokhov
  0 siblings, 0 replies; 92+ messages in thread
From: Dmitry Torokhov @ 2014-12-19 19:56 UTC (permalink / raw)
  To: Jonathan Richardson
  Cc: Joe Perches, Grant Likely, Rob Herring, Ray Jui, linux-kernel,
	linux-input, linux-arm-kernel, bcm-kernel-feedback-list,
	devicetree

On Friday, December 19, 2014 11:51:33 AM Jonathan Richardson wrote:
> Thanks Joe. I'll send out a new patch set with your suggestions/fixes
> shortly.

You can also drop the remove() code since we clear drvdata automatically and 
input device is managed so does not need to be unregistered explicitly.

Thanks.

-- 
Dmitry

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

* [PATCH v2 0/2] Add support for Broadcom iProc touchscreen
       [not found] <Jonathan Richardson <jonathar@broadcom.com>
                   ` (4 preceding siblings ...)
  2014-12-18  1:59 ` [PATCH 0/2] Add support for Broadcom iProc touchscreen Jonathan Richardson
@ 2014-12-19 22:17 ` Jonathan Richardson
  2014-12-19 22:17   ` [PATCH v2 1/2] Input: touchscreen-iproc: Add Broadcom iProc touchscreen driver Jonathan Richardson
  2014-12-19 22:17   ` [PATCH v2 2/2] Input: touchscreen-iproc: add device tree bindings Jonathan Richardson
  2014-12-30 22:43 ` [PATCH v4 0/3] Fix bugs in kona pwm driver and pwm core Jonathan Richardson
                   ` (7 subsequent siblings)
  13 siblings, 2 replies; 92+ messages in thread
From: Jonathan Richardson @ 2014-12-19 22:17 UTC (permalink / raw)
  To: Dmitry Torokhov, Grant Likely, Rob Herring
  Cc: Ray Jui, Jonathan Richardson, linux-kernel, linux-input,
	linux-arm-kernel, bcm-kernel-feedback-list, devicetree,
	Joe Perches

This patchset contains initial support for the touchscreen on the Broadcom
iProc family of SoCs. This driver has been validated with Cygnus and is expected
to work on other iProc family of SoCs that use the same touchscreen controller.

Changes from v1:
- Add missing newlines to debug messages
- Use BIT macro for defines
- Fix logic in get_tsc_config to improve readability
- Get rid of unnecessary remove() function

Jonathan Richardson (2):
  Input: touchscreen-iproc: Add Broadcom iProc touchscreen driver
  Input: touchscreen-iproc: add device tree bindings

 .../input/touchscreen/brcm,iproc-touchscreen.txt   |   70 +++
 drivers/input/touchscreen/Kconfig                  |   11 +
 drivers/input/touchscreen/Makefile                 |    1 +
 drivers/input/touchscreen/bcm_iproc_tsc.c          |  535 ++++++++++++++++++++
 4 files changed, 617 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/input/touchscreen/brcm,iproc-touchscreen.txt
 create mode 100644 drivers/input/touchscreen/bcm_iproc_tsc.c

-- 
1.7.9.5


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

* [PATCH v2 1/2] Input: touchscreen-iproc: Add Broadcom iProc touchscreen driver
  2014-12-19 22:17 ` [PATCH v2 0/2] Add support for Broadcom iProc touchscreen Jonathan Richardson
@ 2014-12-19 22:17   ` Jonathan Richardson
  2014-12-19 22:26     ` Joe Perches
                       ` (2 more replies)
  2014-12-19 22:17   ` [PATCH v2 2/2] Input: touchscreen-iproc: add device tree bindings Jonathan Richardson
  1 sibling, 3 replies; 92+ messages in thread
From: Jonathan Richardson @ 2014-12-19 22:17 UTC (permalink / raw)
  To: Dmitry Torokhov, Grant Likely, Rob Herring
  Cc: Ray Jui, Jonathan Richardson, linux-kernel, linux-input,
	linux-arm-kernel, bcm-kernel-feedback-list, devicetree,
	Joe Perches

Add initial version of the Broadcom touchscreen driver.

Reviewed-by: Ray Jui <rjui@broadcom.com>
Reviewed-by: Scott Branden <sbranden@broadcom.com>
Tested-by: Scott Branden <sbranden@broadcom.com>
Signed-off-by: Jonathan Richardson <jonathar@broadcom.com>
---
 drivers/input/touchscreen/Kconfig         |   11 +
 drivers/input/touchscreen/Makefile        |    1 +
 drivers/input/touchscreen/bcm_iproc_tsc.c |  535 +++++++++++++++++++++++++++++
 3 files changed, 547 insertions(+)
 create mode 100644 drivers/input/touchscreen/bcm_iproc_tsc.c

diff --git a/drivers/input/touchscreen/Kconfig b/drivers/input/touchscreen/Kconfig
index e1d8003..77ff531 100644
--- a/drivers/input/touchscreen/Kconfig
+++ b/drivers/input/touchscreen/Kconfig
@@ -310,6 +310,17 @@ config TOUCHSCREEN_ILI210X
 	  To compile this driver as a module, choose M here: the
 	  module will be called ili210x.
 
+config TOUCHSCREEN_IPROC
+	tristate "IPROC touch panel driver support"
+	help
+	  Say Y here if you want to add support for the IPROC touch
+	  controller to your system.
+
+	  If unsure, say N.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called iproc-ts.
+
 config TOUCHSCREEN_S3C2410
 	tristate "Samsung S3C2410/generic touchscreen input driver"
 	depends on ARCH_S3C24XX || SAMSUNG_DEV_TS
diff --git a/drivers/input/touchscreen/Makefile b/drivers/input/touchscreen/Makefile
index 090e61c..f7e6de9 100644
--- a/drivers/input/touchscreen/Makefile
+++ b/drivers/input/touchscreen/Makefile
@@ -37,6 +37,7 @@ obj-$(CONFIG_TOUCHSCREEN_FUJITSU)	+= fujitsu_ts.o
 obj-$(CONFIG_TOUCHSCREEN_ILI210X)	+= ili210x.o
 obj-$(CONFIG_TOUCHSCREEN_INEXIO)	+= inexio.o
 obj-$(CONFIG_TOUCHSCREEN_INTEL_MID)	+= intel-mid-touch.o
+obj-$(CONFIG_TOUCHSCREEN_IPROC)		+= bcm_iproc_tsc.o
 obj-$(CONFIG_TOUCHSCREEN_LPC32XX)	+= lpc32xx_ts.o
 obj-$(CONFIG_TOUCHSCREEN_MAX11801)	+= max11801_ts.o
 obj-$(CONFIG_TOUCHSCREEN_MC13783)	+= mc13783_ts.o
diff --git a/drivers/input/touchscreen/bcm_iproc_tsc.c b/drivers/input/touchscreen/bcm_iproc_tsc.c
new file mode 100644
index 0000000..bf6eb7f
--- /dev/null
+++ b/drivers/input/touchscreen/bcm_iproc_tsc.c
@@ -0,0 +1,535 @@
+/*
+* Copyright (C) 2014 Broadcom Corporation
+*
+* This program is free software; you can redistribute it and/or
+* modify it under the terms of the GNU General Public License as
+* published by the Free Software Foundation version 2.
+*
+* This program is distributed "as is" WITHOUT ANY WARRANTY of any
+* kind, whether express or implied; without even the implied warranty
+* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*/
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/input.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/keyboard.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/of.h>
+#include <asm/irq.h>
+#include <linux/io.h>
+#include <linux/clk.h>
+#include <linux/serio.h>
+
+#define IPROC_TS_NAME "iproc-ts"
+
+#define PEN_DOWN_STATUS     1
+#define PEN_UP_STATUS       0
+
+#define X_MIN               0
+#define Y_MIN               0
+#define X_MAX               0xFFF
+#define Y_MAX               0xFFF
+
+/* Value given by controller for invalid coordinate. */
+#define INVALID_COORD       0xFFFFFFFF
+
+/* Register offsets */
+#define REGCTL1             0x00
+#define REGCTL2             0x04
+#define INTERRUPT_THRES     0x08
+#define INTERRUPT_MASK      0x0c
+
+#define INTERRUPT_STATUS    0x10
+#define CONTROLLER_STATUS   0x14
+#define FIFO_DATA           0x18
+#define FIFO_DATA_X_Y_MASK  0xFFFF
+#define ANALOG_CONTROL      0x1c
+
+#define AUX_DATA            0x20
+#define DEBOUNCE_CNTR_STAT  0x24
+#define SCAN_CNTR_STAT      0x28
+#define REM_CNTR_STAT       0x2c
+
+#define SETTLING_TIMER_STAT 0x30
+#define SPARE_REG           0x34
+#define SOFT_BYPASS_CONTROL 0x38
+#define SOFT_BYPASS_DATA    0x3c
+
+
+/* Bit values for INTERRUPT_MASK and INTERRUPT_STATUS regs */
+#define TS_PEN_INTR_MASK        BIT(0)
+#define TS_FIFO_INTR_MASK       BIT(2)
+
+/* Bit values for CONTROLLER_STATUS reg1 */
+#define TS_PEN_DOWN             BIT(0)
+
+/* Shift values for control reg1 */
+#define SCANNING_PERIOD_SHIFT   24
+#define DEBOUNCE_TIMEOUT_SHIFT  16
+#define SETTLING_TIMEOUT_SHIFT  8
+#define TOUCH_TIMEOUT_SHIFT     0
+
+/* Shift values for coordinates from fifo */
+#define X_COORD_SHIFT  0
+#define Y_COORD_SHIFT  16
+
+/* Bit values for REGCTL2 */
+#define TS_CONTROLLER_EN_BIT    BIT(16)
+#define TS_CONTROLLER_AVGDATA_SHIFT 8
+#define TS_CONTROLLER_AVGDATA_MASK (0x7 << TS_CONTROLLER_AVGDATA_SHIFT)
+#define TS_CONTROLLER_PWR_LDO   BIT(5)
+#define TS_CONTROLLER_PWR_ADC   BIT(4)
+#define TS_CONTROLLER_PWR_BGP   BIT(3)
+#define TS_CONTROLLER_PWR_TS    BIT(2)
+#define TS_WIRE_MODE_BIT        BIT(1)
+
+/*
+ * Touch screen mount angles w.r.t LCD panel left side top corner
+ * TS (x_min,y_min) placed at LCD (x_min,y_min) rotation angle is 0
+ * TS (x_min,y_max) placed at LCD (x_min,y_min) rotation angle is 90
+ * TS (x_max,y_max) placed at LCD (x_min,y_min) rotation angle is 180
+ * TS (x_max,y_min) placed at LCD (x_min,y_min) rotation angle is 270
+ */
+enum ts_rotation_angles {
+	TS_ROTATION_0,
+	TS_ROTATION_90,
+	TS_ROTATION_180,
+	TS_ROTATION_270,
+};
+
+struct tsc_param {
+	/* Each step is 1024 us.  Valid 1-256 */
+	u32 scanning_period;
+
+	/*  Each step is 512 us.  Valid 0-255 */
+	u32 debounce_timeout;
+
+	/*
+	 * The settling duration (in ms) is the amount of time the tsc
+	 * waits to allow the voltage to settle after turning on the
+	 * drivers in detection mode. Valid values: 0-11
+	 *   0 =  0.008 ms
+	 *   1 =  0.01 ms
+	 *   2 =  0.02 ms
+	 *   3 =  0.04 ms
+	 *   4 =  0.08 ms
+	 *   5 =  0.16 ms
+	 *   6 =  0.32 ms
+	 *   7 =  0.64 ms
+	 *   8 =  1.28 ms
+	 *   9 =  2.56 ms
+	 *   10 = 5.12 ms
+	 *   11 = 10.24 ms
+	 */
+	u32 settling_timeout;
+
+	/* touch timeout in sample counts */
+	u32 touch_timeout;
+
+	/*
+	 * Number of data samples which are averaged before a final data point
+	 * is placed into the FIFO
+	 */
+	u32 average_data;
+
+	/* FIFO threshold */
+	u32 fifo_threshold;
+};
+
+struct iproc_ts_priv {
+	struct platform_device *pdev;
+	struct input_dev *idev;
+
+	void __iomem *regs;
+	struct clk *tsc_clk;
+
+	int  pen_status;
+	int  ts_rotation;
+	struct tsc_param cfg_params;
+};
+
+/*
+ * Set default values the same as hardware reset values
+ * except for fifo_threshold with is set to 1.
+ */
+static struct tsc_param default_config = {
+	.scanning_period  = 0x5,  /* 1 to 256 */
+	.debounce_timeout = 0x28, /* 0 to 255 */
+	.settling_timeout = 0x7,  /* 0 to 11 */
+	.touch_timeout    = 0xa,  /* 0 to 255 */
+	.average_data     = 5,    /* entry 5 = 32 pts */
+	.fifo_threshold   = 1,    /* 0 to 31 */
+};
+
+static void ts_reg_dump(struct iproc_ts_priv *priv)
+{
+	struct device *dev = &priv->pdev->dev;
+
+	dev_dbg(dev, "regCtl1             = 0x%08x\n",
+				readl(priv->regs + REGCTL1));
+	dev_dbg(dev, "regCtl2             = 0x%08x\n",
+				readl(priv->regs + REGCTL2));
+	dev_dbg(dev, "interrupt_Thres     = 0x%08x\n",
+				readl(priv->regs + INTERRUPT_THRES));
+	dev_dbg(dev, "interrupt_Mask      = 0x%08x\n",
+				readl(priv->regs + INTERRUPT_MASK));
+	dev_dbg(dev, "interrupt_Status    = 0x%08x\n",
+				readl(priv->regs + INTERRUPT_STATUS));
+	dev_dbg(dev, "controller_Status   = 0x%08x\n",
+				readl(priv->regs + CONTROLLER_STATUS));
+	dev_dbg(dev, "FIFO_Data           = 0x%08x\n",
+				readl(priv->regs + FIFO_DATA));
+	dev_dbg(dev, "analog_Control      = 0x%08x\n",
+				readl(priv->regs + ANALOG_CONTROL));
+	dev_dbg(dev, "aux_Data            = 0x%08x\n",
+				readl(priv->regs + AUX_DATA));
+	dev_dbg(dev, "debounce_Cntr_Stat  = 0x%08x\n",
+				readl(priv->regs + DEBOUNCE_CNTR_STAT));
+	dev_dbg(dev, "scan_Cntr_Stat      = 0x%08x\n",
+				readl(priv->regs + SCAN_CNTR_STAT));
+	dev_dbg(dev, "rem_Cntr_Stat       = 0x%08x\n",
+				readl(priv->regs + REM_CNTR_STAT));
+	dev_dbg(dev, "settling_Timer_Stat = 0x%08x\n",
+				readl(priv->regs + SETTLING_TIMER_STAT));
+	dev_dbg(dev, "spare_Reg           = 0x%08x\n",
+				readl(priv->regs + SPARE_REG));
+	dev_dbg(dev, "soft_Bypass_Control = 0x%08x\n",
+				readl(priv->regs + SOFT_BYPASS_CONTROL));
+	dev_dbg(dev, "soft_Bypass_Data    = 0x%08x\n",
+				readl(priv->regs + SOFT_BYPASS_DATA));
+}
+
+static irqreturn_t iproc_touchscreen_interrupt(int irq, void *data)
+{
+	struct platform_device *pdev = (struct platform_device *)data;
+	struct iproc_ts_priv *priv;
+	u32 intr_status = 0;
+	u32 raw_coordinate = 0;
+	u16 x = 0;
+	u16 y = 0;
+	int i;
+
+	priv = (struct iproc_ts_priv *)platform_get_drvdata(pdev);
+
+	intr_status = readl(priv->regs + INTERRUPT_STATUS);
+	intr_status &= (TS_PEN_INTR_MASK | TS_FIFO_INTR_MASK);
+	if (intr_status == 0)
+		return IRQ_NONE;
+
+	/* Clear all interrupt status bits, write-1-clear */
+	writel(intr_status, priv->regs + INTERRUPT_STATUS);
+
+	/* Pen up/down */
+	if (intr_status & TS_PEN_INTR_MASK) {
+		if (readl(priv->regs + CONTROLLER_STATUS) & TS_PEN_DOWN) {
+			priv->pen_status = PEN_DOWN_STATUS;
+			input_report_key(priv->idev, BTN_TOUCH,
+				priv->pen_status);
+		} else {
+			priv->pen_status = PEN_UP_STATUS;
+			input_report_key(priv->idev, BTN_TOUCH,
+				priv->pen_status);
+			input_sync(priv->idev);
+		}
+
+		dev_dbg(&priv->pdev->dev,
+			"pen up-down (%d)\n", priv->pen_status);
+	}
+
+	/* coordinates in FIFO exceed the theshold */
+	if (intr_status & TS_FIFO_INTR_MASK) {
+		for (i = 0; i < priv->cfg_params.fifo_threshold; i++) {
+			raw_coordinate = readl(priv->regs + FIFO_DATA);
+			if (raw_coordinate == INVALID_COORD)
+				continue;
+
+			/*
+			 * The x and y coordinate are 16 bits each
+			 * with the x in the lower 16 bits and y in the
+			 * upper 16 bits.
+			 */
+			x = (raw_coordinate >> X_COORD_SHIFT) &
+				FIFO_DATA_X_Y_MASK;
+			y = (raw_coordinate >> Y_COORD_SHIFT) &
+				FIFO_DATA_X_Y_MASK;
+
+			/* We only want to retain the 12 msb of the 16 */
+			x = (x >> 4) & 0x0FFF;
+			y = (y >> 4) & 0x0FFF;
+
+			/* adjust x y according to lcd tsc mount angle */
+			if (priv->ts_rotation == TS_ROTATION_90) {
+				y = Y_MAX - y;
+			} else if (priv->ts_rotation == TS_ROTATION_180) {
+				x = X_MAX - x;
+				y = Y_MAX - y;
+			} else if (priv->ts_rotation == TS_ROTATION_270) {
+				x = X_MAX - x;
+			}
+
+			input_report_abs(priv->idev, ABS_X, x);
+			input_report_abs(priv->idev, ABS_Y, y);
+			input_sync(priv->idev);
+
+			dev_dbg(&priv->pdev->dev, "xy (0x%x 0x%x)\n", x, y);
+		}
+	}
+
+	return IRQ_HANDLED;
+}
+
+static int iproc_ts_start(struct input_dev *idev)
+{
+	u32 val;
+	int ret;
+	struct iproc_ts_priv *priv;
+
+	priv = input_get_drvdata(idev);
+	if (priv == NULL)
+		return -ENODEV;
+
+	/* Enable clock */
+	ret = clk_prepare_enable(priv->tsc_clk);
+	if (ret) {
+		dev_err(&priv->pdev->dev, "%s clk_prepare_enable failed %d\n",
+			__func__, ret);
+		return ret;
+	}
+
+	/*
+	 * Interrupt is generated when:
+	 *  FIFO reaches the int_th value, and pen event(up/down)
+	 */
+	val = TS_PEN_INTR_MASK | TS_FIFO_INTR_MASK;
+	writel(val, priv->regs + INTERRUPT_MASK);
+
+	writel(priv->cfg_params.fifo_threshold, priv->regs + INTERRUPT_THRES);
+
+	/* Initialize control reg1 */
+	val = 0;
+	val |= (priv->cfg_params.scanning_period << SCANNING_PERIOD_SHIFT);
+	val |= (priv->cfg_params.debounce_timeout << DEBOUNCE_TIMEOUT_SHIFT);
+	val |= (priv->cfg_params.settling_timeout << SETTLING_TIMEOUT_SHIFT);
+	val |= (priv->cfg_params.touch_timeout << TOUCH_TIMEOUT_SHIFT);
+	writel(val, priv->regs + REGCTL1);
+
+	/* Try to clear all interrupt status */
+	val = readl(priv->regs + INTERRUPT_STATUS);
+	val |= (TS_FIFO_INTR_MASK | TS_PEN_INTR_MASK);
+	writel(val, priv->regs + INTERRUPT_STATUS);
+
+	/* Initialize control reg2 */
+	val = readl(priv->regs + REGCTL2);
+	val |= (TS_CONTROLLER_EN_BIT | TS_WIRE_MODE_BIT);
+
+	val &= ~(TS_CONTROLLER_AVGDATA_MASK);
+	val |= (priv->cfg_params.average_data << TS_CONTROLLER_AVGDATA_SHIFT);
+
+	val &= ~(TS_CONTROLLER_PWR_LDO |	/* PWR up LDO */
+		   TS_CONTROLLER_PWR_ADC |	/* PWR up ADC */
+		   TS_CONTROLLER_PWR_BGP |	/* PWR up BGP */
+		   TS_CONTROLLER_PWR_TS);	/* PWR up TS */
+
+	writel(val, priv->regs + REGCTL2);
+
+	ts_reg_dump(priv);
+
+	return 0;
+}
+
+static void iproc_ts_stop(struct input_dev *dev)
+{
+	u32 val;
+	struct iproc_ts_priv *priv;
+
+	priv = input_get_drvdata(dev);
+	if (priv == NULL)
+		return;
+
+	writel(0, priv->regs + INTERRUPT_MASK); /* Disable all interrupts */
+
+	/* Only power down touch screen controller */
+	val = readl(priv->regs + REGCTL2);
+	val |= TS_CONTROLLER_PWR_TS;
+	writel(val, priv->regs + REGCTL2);
+
+	clk_disable(priv->tsc_clk);
+}
+
+static int get_tsc_config(struct device_node *np, struct iproc_ts_priv *priv)
+{
+	u32 val;
+	struct device *dev = &priv->pdev->dev;
+
+	priv->cfg_params = default_config;
+
+	if (of_property_read_u32(np, "scanning_period", &val) >= 0) {
+		if (val < 1 || val > 256) {
+			dev_err(dev, "scanning_period must be [1-256]\n");
+			return -EINVAL;
+		}
+		priv->cfg_params.scanning_period = val;
+	}
+
+	if (of_property_read_u32(np, "debounce_timeout", &val) >= 0) {
+		if (val < 0 || val > 255) {
+			dev_err(dev, "debounce_timeout must be [0-255]\n");
+			return -EINVAL;
+		}
+		priv->cfg_params.debounce_timeout = val;
+	}
+
+	if (of_property_read_u32(np, "settling_timeout", &val) >= 0) {
+		if (val < 0 || val > 11) {
+			dev_err(dev, "settling_timeout must be [0-11]\n");
+			return -EINVAL;
+		}
+		priv->cfg_params.settling_timeout = val;
+	}
+
+	if (of_property_read_u32(np, "touch_timeout", &val) >= 0) {
+		if (val < 0 || val > 255) {
+			dev_err(dev, "touch_timeout must be [0-255]\n");
+			return -EINVAL;
+		}
+		priv->cfg_params.touch_timeout = val;
+	}
+
+	if (of_property_read_u32(np, "average_data", &val) >= 0) {
+		if (val < 0 || val > 8) {
+			dev_err(dev, "average_data must be [0-8]\n");
+			return -EINVAL;
+		}
+		priv->cfg_params.average_data = val;
+	}
+
+	if (of_property_read_u32(np, "fifo_threshold", &val) >= 0) {
+		if (val < 0 || val > 31) {
+			dev_err(dev, "fifo_threshold must be [0-31]\n");
+			return -EINVAL;
+		}
+		priv->cfg_params.fifo_threshold = val;
+	}
+
+	priv->ts_rotation = TS_ROTATION_0;
+	if (of_property_read_u32(np, "ts-rotation", &val) >= 0) {
+		priv->ts_rotation = val;
+		dev_dbg(dev, "ts rotation [%d] degrees\n",
+			90 * priv->ts_rotation);
+	}
+
+	return 0;
+}
+
+static int iproc_ts_probe(struct platform_device *pdev)
+{
+	struct iproc_ts_priv *priv;
+	struct input_dev *idev;
+	struct resource *res;
+	int ret;
+	int irq;
+
+	priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
+	if (!priv)
+		return -ENOMEM;
+
+	/* touchscreen controller memory mapped regs */
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	priv->regs = devm_ioremap_resource(&pdev->dev, res);
+	if (IS_ERR(priv->regs)) {
+		dev_err(&pdev->dev, "unable to map I/O memory\n");
+		return PTR_ERR(priv->regs);
+	}
+
+	priv->tsc_clk = devm_clk_get(&pdev->dev, "tsc_clk");
+	if (IS_ERR(priv->tsc_clk)) {
+		dev_err(&pdev->dev,
+			"%s Failed getting clock tsc_clk\n", __func__);
+		return PTR_ERR(priv->tsc_clk);
+	}
+
+	ret = get_tsc_config(pdev->dev.of_node, priv);
+	if (ret != 0) {
+		dev_err(&pdev->dev, "%s get_tsc_config failed\n", __func__);
+		return ret;
+	}
+
+	idev = devm_input_allocate_device(&pdev->dev);
+	if (!idev) {
+		dev_err(&pdev->dev,
+			"%s Allocate input device failed\n", __func__);
+		return -ENOMEM;
+	}
+
+	priv->idev = idev;
+	priv->pdev = pdev;
+
+	priv->pen_status = PEN_UP_STATUS;
+
+	/* Set input device info  */
+	idev->name = IPROC_TS_NAME;
+	idev->dev.parent = &pdev->dev;
+
+	idev->id.bustype = BUS_HOST;
+	idev->id.vendor = SERIO_UNKNOWN;
+	idev->id.product = 0;
+	idev->id.version = 0;
+
+	idev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS);
+	set_bit(BTN_TOUCH, idev->keybit);
+
+	input_set_abs_params(idev, ABS_X, X_MIN, X_MAX, 0, 0);
+	input_set_abs_params(idev, ABS_Y, Y_MIN, Y_MAX, 0, 0);
+
+	idev->open = iproc_ts_start;
+	idev->close = iproc_ts_stop;
+
+	input_set_drvdata(idev, priv);
+	platform_set_drvdata(pdev, priv);
+
+	/* get interrupt */
+	irq = platform_get_irq(pdev, 0);
+	if (irq < 0) {
+		dev_err(&pdev->dev, "%s platform_get_irq failed\n", __func__);
+		return irq;
+	}
+
+	ret = devm_request_irq(&pdev->dev, irq,
+		iproc_touchscreen_interrupt,
+		IRQF_SHARED, IPROC_TS_NAME, pdev);
+	if (ret)
+		return ret;
+
+	ret = input_register_device(priv->idev);
+	if (ret) {
+		dev_err(&pdev->dev,
+			"%s register input device failed %d\n", __func__, ret);
+		return ret;
+	}
+
+	return 0;
+}
+
+static const struct of_device_id iproc_ts_of_match[] = {
+	{.compatible = "brcm,iproc-touchscreen", },
+	{ },
+};
+MODULE_DEVICE_TABLE(of, iproc_ts_of_match);
+
+static struct platform_driver iproc_ts_driver = {
+	.probe = iproc_ts_probe,
+	.driver = {
+		.name	= IPROC_TS_NAME,
+		.of_match_table = of_match_ptr(iproc_ts_of_match),
+	},
+};
+
+module_platform_driver(iproc_ts_driver);
+
+MODULE_DESCRIPTION("IPROC Touchscreen driver");
+MODULE_AUTHOR("Broadcom");
+MODULE_LICENSE("GPL v2");
-- 
1.7.9.5


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

* [PATCH v2 2/2] Input: touchscreen-iproc: add device tree bindings
  2014-12-19 22:17 ` [PATCH v2 0/2] Add support for Broadcom iProc touchscreen Jonathan Richardson
  2014-12-19 22:17   ` [PATCH v2 1/2] Input: touchscreen-iproc: Add Broadcom iProc touchscreen driver Jonathan Richardson
@ 2014-12-19 22:17   ` Jonathan Richardson
  1 sibling, 0 replies; 92+ messages in thread
From: Jonathan Richardson @ 2014-12-19 22:17 UTC (permalink / raw)
  To: Dmitry Torokhov, Grant Likely, Rob Herring
  Cc: Ray Jui, Jonathan Richardson, linux-kernel, linux-input,
	linux-arm-kernel, bcm-kernel-feedback-list, devicetree,
	Joe Perches

Documents the touchscreen device tree binding for Broadcom iProc family
of SoCs.

Reviewed-by: Scott Branden <sbranden@broadcom.com>
Tested-by: Scott Branden <sbranden@broadcom.com>
Signed-off-by: Jonathan Richardson <jonathar@broadcom.com>
---
 .../input/touchscreen/brcm,iproc-touchscreen.txt   |   70 ++++++++++++++++++++
 1 file changed, 70 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/input/touchscreen/brcm,iproc-touchscreen.txt

diff --git a/Documentation/devicetree/bindings/input/touchscreen/brcm,iproc-touchscreen.txt b/Documentation/devicetree/bindings/input/touchscreen/brcm,iproc-touchscreen.txt
new file mode 100644
index 0000000..eb28822
--- /dev/null
+++ b/Documentation/devicetree/bindings/input/touchscreen/brcm,iproc-touchscreen.txt
@@ -0,0 +1,70 @@
+* Broadcom's IPROC Touchscreen Controller
+
+Required properties:
+- compatible: must be "brcm,iproc-touchscreen"
+- reg: physical base address of the controller and length of memory mapped
+  region.
+- clocks:  The clock provided by the SOC to driver the tsc
+- clock-name:  name for the clock
+- interrupts: The touchscreen controller's interrupt
+
+Optional properties:
+- scanning_period: Time between scans. Each step is 1024 us.  Valid 1-256.
+- debounce_timeout: Each step is 512 us.  Valid 0-255
+- settling_timeout: The settling duration (in ms) is the amount of time
+                    the tsc waits to allow the voltage to settle after
+                    turning on the drivers in detection mode.
+                    Valid values: 0-11
+                    0 =  0.008 ms
+                    1 =  0.01 ms
+                    2 =  0.02 ms
+                    3 =  0.04 ms
+                    4 =  0.08 ms
+                    5 =  0.16 ms
+                    6 =  0.32 ms
+                    7 =  0.64 ms
+                    8 =  1.28 ms
+                    9 =  2.56 ms
+                   10 =  5.12 ms
+                   11 = 10.24 ms
+- touch_timeout: The continuous number of scan periods in which touch is
+                not detected before the controller returns to idle state.
+                Valid values 0-255.
+- average_data: Number of data samples which are averaged before a final
+                data point is placed into the FIFO
+                Valid values 0-7
+                0 =   1 sample
+                1 =   2 samples
+                2 =   4 samples
+                3 =   8 samples
+                4 =  16 samples
+                5 =  32 samples
+                6 =  64 samples
+                7 = 128 samples
+- fifo_threshold: Interrupt is generated whenever the number of fifo
+                entries exceeds this value
+                Valid values 0-31
+- ts-rotation: Touch screen controller and display panel orientation angle.
+		0 = Tsc x_min y_min placed at LCD x_min y_min. None
+		1 = Tsc x_min y_max placed at LCD x_min y_min. 90 degrees
+		2 = Tsc x_max y_max placed at LCD x_min y_min. 180 degrees
+		3 = Tsc x_max y_min placed at LCD x_min y_min. 270 degrees
+Example:
+
+	touchscreen: tsc@0x180A6000 {
+		compatible = "brcm,iproc-touchscreen";
+		#address-cells = <1>;
+		#size-cells = <1>;
+		reg = <0x180A6000 0x40>;
+		clocks = <&adc_clk>;
+		clock-names = "tsc_clk";
+		interrupts = <GIC_SPI 164 IRQ_TYPE_LEVEL_HIGH>;
+
+		scanning_period = <5>;
+		debounce_timeout = <40>;
+		settling_timeout = <7>;
+		touch_timeout = <10>;
+		average_data = <5>;
+		fifo_threshold = <1>;
+		ts-rotation = <2>;
+	};
-- 
1.7.9.5


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

* Re: [PATCH v2 1/2] Input: touchscreen-iproc: Add Broadcom iProc touchscreen driver
  2014-12-19 22:17   ` [PATCH v2 1/2] Input: touchscreen-iproc: Add Broadcom iProc touchscreen driver Jonathan Richardson
@ 2014-12-19 22:26     ` Joe Perches
  2014-12-19 23:03       ` Jonathan Richardson
  2015-01-15  1:02     ` Dmitry Torokhov
  2015-02-24 23:29     ` Dmitry Torokhov
  2 siblings, 1 reply; 92+ messages in thread
From: Joe Perches @ 2014-12-19 22:26 UTC (permalink / raw)
  To: Jonathan Richardson
  Cc: Dmitry Torokhov, Grant Likely, Rob Herring, Ray Jui,
	linux-kernel, linux-input, linux-arm-kernel,
	bcm-kernel-feedback-list, devicetree

On Fri, 2014-12-19 at 14:17 -0800, Jonathan Richardson wrote:
> Add initial version of the Broadcom touchscreen driver.

more trivia:

> diff --git a/drivers/input/touchscreen/bcm_iproc_tsc.c b/drivers/input/touchscreen/bcm_iproc_tsc.c
[]
> +static int get_tsc_config(struct device_node *np, struct iproc_ts_priv *priv)
> +{
> +	u32 val;
[]
> +	if (of_property_read_u32(np, "debounce_timeout", &val) >= 0) {
> +		if (val < 0 || val > 255) {
> +			dev_err(dev, "debounce_timeout must be [0-255]\n");
> +			return -EINVAL;
> +		}
> +		priv->cfg_params.debounce_timeout = val;

Doesn't the compiler generate a warning message
about an impossible "unsigned < 0" test for all
of these "val < 0" uses?

> +	}
> +
> +	if (of_property_read_u32(np, "settling_timeout", &val) >= 0) {
> +		if (val < 0 || val > 11) {
[]
> +	if (of_property_read_u32(np, "touch_timeout", &val) >= 0) {
> +		if (val < 0 || val > 255) {
[]
> +	if (of_property_read_u32(np, "average_data", &val) >= 0) {
> +		if (val < 0 || val > 8) {
[]
> +	if (of_property_read_u32(np, "fifo_threshold", &val) >= 0) {
> +		if (val < 0 || val > 31) {



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

* Re: [PATCH v2 1/2] Input: touchscreen-iproc: Add Broadcom iProc touchscreen driver
  2014-12-19 22:26     ` Joe Perches
@ 2014-12-19 23:03       ` Jonathan Richardson
  2015-01-01  0:55         ` Jonathan Richardson
  2015-01-15  1:08         ` Florian Fainelli
  0 siblings, 2 replies; 92+ messages in thread
From: Jonathan Richardson @ 2014-12-19 23:03 UTC (permalink / raw)
  To: Joe Perches
  Cc: Dmitry Torokhov, Grant Likely, Rob Herring, Ray Jui,
	linux-kernel, linux-input, linux-arm-kernel,
	bcm-kernel-feedback-list, devicetree

On 14-12-19 02:26 PM, Joe Perches wrote:
> On Fri, 2014-12-19 at 14:17 -0800, Jonathan Richardson wrote:
>> Add initial version of the Broadcom touchscreen driver.
> 
> more trivia:
> 
>> diff --git a/drivers/input/touchscreen/bcm_iproc_tsc.c b/drivers/input/touchscreen/bcm_iproc_tsc.c
> []
>> +static int get_tsc_config(struct device_node *np, struct iproc_ts_priv *priv)
>> +{
>> +	u32 val;
> []
>> +	if (of_property_read_u32(np, "debounce_timeout", &val) >= 0) {
>> +		if (val < 0 || val > 255) {
>> +			dev_err(dev, "debounce_timeout must be [0-255]\n");
>> +			return -EINVAL;
>> +		}
>> +		priv->cfg_params.debounce_timeout = val;
> 
> Doesn't the compiler generate a warning message
> about an impossible "unsigned < 0" test for all
> of these "val < 0" uses?
> 

Actually no it doesn't. The gcc output shows that neither -Wtype-limits
nor -Wextra are used to compile that file. I assume this is because
there would be just too many warnings.


>> +	}
>> +
>> +	if (of_property_read_u32(np, "settling_timeout", &val) >= 0) {
>> +		if (val < 0 || val > 11) {
> []
>> +	if (of_property_read_u32(np, "touch_timeout", &val) >= 0) {
>> +		if (val < 0 || val > 255) {
> []
>> +	if (of_property_read_u32(np, "average_data", &val) >= 0) {
>> +		if (val < 0 || val > 8) {
> []
>> +	if (of_property_read_u32(np, "fifo_threshold", &val) >= 0) {
>> +		if (val < 0 || val > 31) {
> 
> 


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

* Re: [PATCH v3 1/2] pwm: kona: Fix incorrect enable, config, and disable procedures
  2014-12-17 18:46 ` [PATCH v3 " Jonathan Richardson
  2014-12-17 18:46   ` [PATCH v3 2/2] pwm: kona: Remove setting default smooth type and polarity for all channels Jonathan Richardson
@ 2014-12-20 22:38   ` Tim Kryger
  2014-12-22 22:49     ` Jonathan Richardson
  1 sibling, 1 reply; 92+ messages in thread
From: Tim Kryger @ 2014-12-20 22:38 UTC (permalink / raw)
  To: Jonathan Richardson
  Cc: Scott Branden, Arun Ramamurthy, Thierry Reding, Ray Jui,
	bcm-kernel-feedback-list, Linux Kernel Mailing List, linux-pwm

On Wed, Dec 17, 2014 at 10:46 AM, Jonathan Richardson
<jonathar@broadcom.com> wrote:
>     The config procedure doesn't follow the spec which periodically results
>     in failing to enable the output signal. This happens one in ten or
>     twenty attempts. Following the spec and adding a 400ns delay in the
>     appropriate locations resolves this problem. It also ensures that the
>     signal transition is smooth.

This patch does not result in smooth transitions.

Please ensure that your commit message reflects the code.

>
>     If config is called when the pwm is disabled and there is nothing to do,
>     the while loop to calculate duty cycle and period doesn't need to be
>     done. The function now just returns if the pwm state is disabled.
>
>     The disable procedure now also follows the spec to ensure a smooth
>     transition. Not following the spec can cause non-smooth transitions.
>
>     The enable procedure now clears the enabled bit if enabling failed.
>     Enabling can fail if an invalid duty cycle and period is set. This
>     prevents the sysfs interface from reporting the pwm is enabled after a
>     failed call to enable.
>
> Reviewed-by: Arun Ramamurthy <arunrama@broadcom.com>
> Reviewed-by: Scott Branden <sbranden@broadcom.com>
> Tested-by: Scott Branden <sbranden@broadcom.com>
> Signed-off-by: Jonathan Richardson <jonathar@broadcom.com>

Normally when people send a multi-part patch series they include a
cover letter that describes the overall purpose of the changes with a
description of changes introduced in each revision of the series.

Please follow this convention.

> ---
>  drivers/pwm/pwm-bcm-kona.c |   91 ++++++++++++++++++++++++++++++++------------
>  1 file changed, 67 insertions(+), 24 deletions(-)
>
> diff --git a/drivers/pwm/pwm-bcm-kona.c b/drivers/pwm/pwm-bcm-kona.c
> index 02bc048..a831bb2 100644
> --- a/drivers/pwm/pwm-bcm-kona.c
> +++ b/drivers/pwm/pwm-bcm-kona.c
> @@ -80,15 +80,19 @@ static void kona_pwmc_apply_settings(struct kona_pwmc *kp, unsigned int chan)
>  {
>         unsigned int value = readl(kp->base + PWM_CONTROL_OFFSET);
>
> -       /* Clear trigger bit but set smooth bit to maintain old output */
> -       value |= 1 << PWM_CONTROL_SMOOTH_SHIFT(chan);
> -       value &= ~(1 << PWM_CONTROL_TRIGGER_SHIFT(chan));
> -       writel(value, kp->base + PWM_CONTROL_OFFSET);
> +       /*
> +        * There must be a min 400ns delay between clearing enable and setting
> +        * it. Failing to do this may result in no PWM signal.
> +        */
> +       ndelay(400);
>
>         /* Set trigger bit and clear smooth bit to apply new settings */
>         value &= ~(1 << PWM_CONTROL_SMOOTH_SHIFT(chan));
>         value |= 1 << PWM_CONTROL_TRIGGER_SHIFT(chan);
>         writel(value, kp->base + PWM_CONTROL_OFFSET);
> +
> +       /* PWMOUT_ENABLE must be held high for at least 400 ns. */
> +       ndelay(400);
>  }
>

Can you try to get a better understanding of what these timing
requirements actually are?

When I wrote this driver, the documentation simply stated that if the
trigger bit didn't stay high for 400 ns then the new settings would
not get applied.

It wasn't essential that we wait 400 ns here because the only time
when the trigger bit would be lowered is when we were about to load
even newer settings which meant we didn't care if the previous
settings were lost.

>  static int kona_pwmc_config(struct pwm_chip *chip, struct pwm_device *pwm,
> @@ -99,6 +103,9 @@ static int kona_pwmc_config(struct pwm_chip *chip, struct pwm_device *pwm,
>         unsigned long prescale = PRESCALE_MIN, pc, dc;
>         unsigned int value, chan = pwm->hwpwm;
>
> +       if (!test_bit(PWMF_ENABLED, &pwm->flags))
> +               return 0;
> +
>         /*
>          * Find period count, duty count and prescale to suit duty_ns and
>          * period_ns. This is done according to formulas described below:

Like I said last time, this is wrong.  You need to sanity check the
requested period and duty cycle here.

You can't just return success immediately when the channel isn't enabled.

> @@ -121,31 +128,60 @@ static int kona_pwmc_config(struct pwm_chip *chip, struct pwm_device *pwm,
>                 dc = div64_u64(val, div);
>
>                 /* If duty_ns or period_ns are not achievable then return */
> -               if (pc < PERIOD_COUNT_MIN || dc < DUTY_CYCLE_HIGH_MIN)
> +               if (pc < PERIOD_COUNT_MIN) {
> +                       dev_warn(chip->dev,
> +                               "%s: pwm[%d]: period=%d is not achievable, pc=%lu, prescale=%lu\n",
> +                               __func__, chan, period_ns, pc, prescale);
>                         return -EINVAL;
> +               }
> +
> +               /* If duty_ns is not achievable then return */
> +               if (dc < DUTY_CYCLE_HIGH_MIN) {
> +                       if (0 != duty_ns) {
> +                               dev_warn(chip->dev,
> +                                       "%s: pwm[%d]: duty cycle=%d is not achievable, dc=%lu, prescale=%lu\n",
> +                                       __func__, chan, duty_ns, dc, prescale);
> +                       }
> +                       return -EINVAL;
> +               }
>
>                 /* If pc and dc are in bounds, the calculation is done */
>                 if (pc <= PERIOD_COUNT_MAX && dc <= DUTY_CYCLE_HIGH_MAX)
>                         break;
>
>                 /* Otherwise, increase prescale and recalculate pc and dc */
> -               if (++prescale > PRESCALE_MAX)
> +               if (++prescale > PRESCALE_MAX) {
> +                       dev_warn(chip->dev,
> +                               "%s: pwm[%d]: Prescale (=%lu) within max (=%d) for period=%d and duty cycle=%d is not achievable\n",
> +                               __func__, chan, prescale, PRESCALE_MAX,
> +                               period_ns, duty_ns);
>                         return -EINVAL;
> +               }
>         }
>
> -       /* If the PWM channel is enabled, write the settings to the HW */
> -       if (test_bit(PWMF_ENABLED, &pwm->flags)) {
> -               value = readl(kp->base + PRESCALE_OFFSET);
> -               value &= ~PRESCALE_MASK(chan);
> -               value |= prescale << PRESCALE_SHIFT(chan);
> -               writel(value, kp->base + PRESCALE_OFFSET);
> +       dev_dbg(chip->dev, "pwm[%d]: period=%lu, duty_high=%lu, prescale=%lu\n",
> +               chan, pc, dc, prescale);
>
> -               writel(pc, kp->base + PERIOD_COUNT_OFFSET(chan));
> +       value = readl(kp->base + PWM_CONTROL_OFFSET);
>
> -               writel(dc, kp->base + DUTY_CYCLE_HIGH_OFFSET(chan));
> +       /*
> +        * Clear trigger bit but set smooth bit to maintain old
> +        * output.
> +        */
> +       value |= 1 << PWM_CONTROL_SMOOTH_SHIFT(chan);
> +       value &= ~(1 << PWM_CONTROL_TRIGGER_SHIFT(chan));
> +       writel(value, kp->base + PWM_CONTROL_OFFSET);
>
> -               kona_pwmc_apply_settings(kp, chan);
> -       }
> +       value = readl(kp->base + PRESCALE_OFFSET);
> +       value &= ~PRESCALE_MASK(chan);
> +       value |= prescale << PRESCALE_SHIFT(chan);
> +       writel(value, kp->base + PRESCALE_OFFSET);
> +
> +       writel(pc, kp->base + PERIOD_COUNT_OFFSET(chan));
> +
> +       writel(dc, kp->base + DUTY_CYCLE_HIGH_OFFSET(chan));
> +
> +       kona_pwmc_apply_settings(kp, chan);
>
>         return 0;
>  }

There is no requirement to lower the trigger bit prior to writing the
period and duty registers.

This change is unnecessary.  The old sequence was fine.

> @@ -173,11 +209,6 @@ static int kona_pwmc_set_polarity(struct pwm_chip *chip, struct pwm_device *pwm,
>
>         writel(value, kp->base + PWM_CONTROL_OFFSET);
>
> -       kona_pwmc_apply_settings(kp, chan);
> -
> -       /* Wait for waveform to settle before gating off the clock */
> -       ndelay(400);
> -
>         clk_disable_unprepare(kp->clk);
>
>         return 0;

I'm not completely convinced that changing the polarity behavior is beneficial.

Please mention this change in your commit description and provide
appropriate justification.

> @@ -190,12 +221,14 @@ static int kona_pwmc_enable(struct pwm_chip *chip, struct pwm_device *pwm)
>
>         ret = clk_prepare_enable(kp->clk);
>         if (ret < 0) {
> +               clear_bit(PWMF_ENABLED, &pwm->flags);
>                 dev_err(chip->dev, "failed to enable clock: %d\n", ret);
>                 return ret;
>         }
>
>         ret = kona_pwmc_config(chip, pwm, pwm->duty_cycle, pwm->period);
>         if (ret < 0) {
> +               clear_bit(PWMF_ENABLED, &pwm->flags);
>                 clk_disable_unprepare(kp->clk);
>                 return ret;
>         }

Don't try to fix this in the Kona PWM driver, fix it in the PWM core.

> @@ -207,13 +240,23 @@ static void kona_pwmc_disable(struct pwm_chip *chip, struct pwm_device *pwm)
>  {
>         struct kona_pwmc *kp = to_kona_pwmc(chip);
>         unsigned int chan = pwm->hwpwm;
> +       unsigned int value = readl(kp->base + PWM_CONTROL_OFFSET);
> +
> +       /* Set smooth type to 1 and disable */
> +       value |= 1 << PWM_CONTROL_SMOOTH_SHIFT(chan);
> +       value &= ~(1 << PWM_CONTROL_TRIGGER_SHIFT(chan));
> +       writel(value, kp->base + PWM_CONTROL_OFFSET);
>
>         /* Simulate a disable by configuring for zero duty */
>         writel(0, kp->base + DUTY_CYCLE_HIGH_OFFSET(chan));
> -       kona_pwmc_apply_settings(kp, chan);
> +       writel(0, kp->base + PERIOD_COUNT_OFFSET(chan));
>
> -       /* Wait for waveform to settle before gating off the clock */
> -       ndelay(400);
> +       /* Set prescale to 0 for this channel */
> +       value = readl(kp->base + PRESCALE_OFFSET);
> +       value &= ~PRESCALE_MASK(chan);
> +       writel(value, kp->base + PRESCALE_OFFSET);

Can you explain why it is necessary to change the prescale here?

> +
> +       kona_pwmc_apply_settings(kp, chan);
>
>         clk_disable_unprepare(kp->clk);
>  }
> --
> 1.7.9.5
>

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

* Re: [PATCH v3 1/2] pwm: kona: Fix incorrect enable, config, and disable procedures
  2014-12-20 22:38   ` [PATCH v3 1/2] pwm: kona: Fix incorrect enable, config, and disable procedures Tim Kryger
@ 2014-12-22 22:49     ` Jonathan Richardson
  0 siblings, 0 replies; 92+ messages in thread
From: Jonathan Richardson @ 2014-12-22 22:49 UTC (permalink / raw)
  To: Tim Kryger
  Cc: Scott Branden, Arun Ramamurthy, Thierry Reding, Ray Jui,
	bcm-kernel-feedback-list, Linux Kernel Mailing List, linux-pwm

On 14-12-20 02:38 PM, Tim Kryger wrote:
> On Wed, Dec 17, 2014 at 10:46 AM, Jonathan Richardson
> <jonathar@broadcom.com> wrote:
>>     The config procedure doesn't follow the spec which periodically results
>>     in failing to enable the output signal. This happens one in ten or
>>     twenty attempts. Following the spec and adding a 400ns delay in the
>>     appropriate locations resolves this problem. It also ensures that the
>>     signal transition is smooth.
> 
> This patch does not result in smooth transitions.
> 
> Please ensure that your commit message reflects the code.

I'll remove the last sentence. I would have to re-verify that it's accurate.

> 
>>
>>     If config is called when the pwm is disabled and there is nothing to do,
>>     the while loop to calculate duty cycle and period doesn't need to be
>>     done. The function now just returns if the pwm state is disabled.
>>
>>     The disable procedure now also follows the spec to ensure a smooth
>>     transition. Not following the spec can cause non-smooth transitions.
>>
>>     The enable procedure now clears the enabled bit if enabling failed.
>>     Enabling can fail if an invalid duty cycle and period is set. This
>>     prevents the sysfs interface from reporting the pwm is enabled after a
>>     failed call to enable.
>>
>> Reviewed-by: Arun Ramamurthy <arunrama@broadcom.com>
>> Reviewed-by: Scott Branden <sbranden@broadcom.com>
>> Tested-by: Scott Branden <sbranden@broadcom.com>
>> Signed-off-by: Jonathan Richardson <jonathar@broadcom.com>
> 
> Normally when people send a multi-part patch series they include a
> cover letter that describes the overall purpose of the changes with a
> description of changes introduced in each revision of the series.
> 
> Please follow this convention.

Will do.

> 
>> ---
>>  drivers/pwm/pwm-bcm-kona.c |   91 ++++++++++++++++++++++++++++++++------------
>>  1 file changed, 67 insertions(+), 24 deletions(-)
>>
>> diff --git a/drivers/pwm/pwm-bcm-kona.c b/drivers/pwm/pwm-bcm-kona.c
>> index 02bc048..a831bb2 100644
>> --- a/drivers/pwm/pwm-bcm-kona.c
>> +++ b/drivers/pwm/pwm-bcm-kona.c
>> @@ -80,15 +80,19 @@ static void kona_pwmc_apply_settings(struct kona_pwmc *kp, unsigned int chan)
>>  {
>>         unsigned int value = readl(kp->base + PWM_CONTROL_OFFSET);
>>
>> -       /* Clear trigger bit but set smooth bit to maintain old output */
>> -       value |= 1 << PWM_CONTROL_SMOOTH_SHIFT(chan);
>> -       value &= ~(1 << PWM_CONTROL_TRIGGER_SHIFT(chan));
>> -       writel(value, kp->base + PWM_CONTROL_OFFSET);
>> +       /*
>> +        * There must be a min 400ns delay between clearing enable and setting
>> +        * it. Failing to do this may result in no PWM signal.
>> +        */
>> +       ndelay(400);
>>
>>         /* Set trigger bit and clear smooth bit to apply new settings */
>>         value &= ~(1 << PWM_CONTROL_SMOOTH_SHIFT(chan));
>>         value |= 1 << PWM_CONTROL_TRIGGER_SHIFT(chan);
>>         writel(value, kp->base + PWM_CONTROL_OFFSET);
>> +
>> +       /* PWMOUT_ENABLE must be held high for at least 400 ns. */
>> +       ndelay(400);
>>  }
>>
> 
> Can you try to get a better understanding of what these timing
> requirements actually are?
> 
> When I wrote this driver, the documentation simply stated that if the
> trigger bit didn't stay high for 400 ns then the new settings would
> not get applied.
> 
> It wasn't essential that we wait 400 ns here because the only time
> when the trigger bit would be lowered is when we were about to load
> even newer settings which meant we didn't care if the previous
> settings were lost.

I'm not spending any more time trying to understand exactly why these
delays are required. All I know is that they are required. Failing to
follow the updated documentation from the ASIC engineers sometimes
resulted in no output signal as stated in the commit message. The docs
you had at the time may have been inaccurate or incomplete.

> 
>>  static int kona_pwmc_config(struct pwm_chip *chip, struct pwm_device *pwm,
>> @@ -99,6 +103,9 @@ static int kona_pwmc_config(struct pwm_chip *chip, struct pwm_device *pwm,
>>         unsigned long prescale = PRESCALE_MIN, pc, dc;
>>         unsigned int value, chan = pwm->hwpwm;
>>
>> +       if (!test_bit(PWMF_ENABLED, &pwm->flags))
>> +               return 0;
>> +
>>         /*
>>          * Find period count, duty count and prescale to suit duty_ns and
>>          * period_ns. This is done according to formulas described below:
> 
> Like I said last time, this is wrong.  You need to sanity check the
> requested period and duty cycle here.

I don't agree. I actually like the code in its original form in this
case. The period and duty cycle are calculated as a function of the
prescale so the loop is responsible for figuring out what values are
correct or not as it iterates. Unless there is a more compelling reason
to change it, I'm going to leave it as is.

> 
> You can't just return success immediately when the channel isn't enabled.

I'll make it return an error.

> 
>> @@ -121,31 +128,60 @@ static int kona_pwmc_config(struct pwm_chip *chip, struct pwm_device *pwm,
>>                 dc = div64_u64(val, div);
>>
>>                 /* If duty_ns or period_ns are not achievable then return */
>> -               if (pc < PERIOD_COUNT_MIN || dc < DUTY_CYCLE_HIGH_MIN)
>> +               if (pc < PERIOD_COUNT_MIN) {
>> +                       dev_warn(chip->dev,
>> +                               "%s: pwm[%d]: period=%d is not achievable, pc=%lu, prescale=%lu\n",
>> +                               __func__, chan, period_ns, pc, prescale);
>>                         return -EINVAL;
>> +               }
>> +
>> +               /* If duty_ns is not achievable then return */
>> +               if (dc < DUTY_CYCLE_HIGH_MIN) {
>> +                       if (0 != duty_ns) {
>> +                               dev_warn(chip->dev,
>> +                                       "%s: pwm[%d]: duty cycle=%d is not achievable, dc=%lu, prescale=%lu\n",
>> +                                       __func__, chan, duty_ns, dc, prescale);
>> +                       }
>> +                       return -EINVAL;
>> +               }
>>
>>                 /* If pc and dc are in bounds, the calculation is done */
>>                 if (pc <= PERIOD_COUNT_MAX && dc <= DUTY_CYCLE_HIGH_MAX)
>>                         break;
>>
>>                 /* Otherwise, increase prescale and recalculate pc and dc */
>> -               if (++prescale > PRESCALE_MAX)
>> +               if (++prescale > PRESCALE_MAX) {
>> +                       dev_warn(chip->dev,
>> +                               "%s: pwm[%d]: Prescale (=%lu) within max (=%d) for period=%d and duty cycle=%d is not achievable\n",
>> +                               __func__, chan, prescale, PRESCALE_MAX,
>> +                               period_ns, duty_ns);
>>                         return -EINVAL;
>> +               }
>>         }
>>
>> -       /* If the PWM channel is enabled, write the settings to the HW */
>> -       if (test_bit(PWMF_ENABLED, &pwm->flags)) {
>> -               value = readl(kp->base + PRESCALE_OFFSET);
>> -               value &= ~PRESCALE_MASK(chan);
>> -               value |= prescale << PRESCALE_SHIFT(chan);
>> -               writel(value, kp->base + PRESCALE_OFFSET);
>> +       dev_dbg(chip->dev, "pwm[%d]: period=%lu, duty_high=%lu, prescale=%lu\n",
>> +               chan, pc, dc, prescale);
>>
>> -               writel(pc, kp->base + PERIOD_COUNT_OFFSET(chan));
>> +       value = readl(kp->base + PWM_CONTROL_OFFSET);
>>
>> -               writel(dc, kp->base + DUTY_CYCLE_HIGH_OFFSET(chan));
>> +       /*
>> +        * Clear trigger bit but set smooth bit to maintain old
>> +        * output.
>> +        */
>> +       value |= 1 << PWM_CONTROL_SMOOTH_SHIFT(chan);
>> +       value &= ~(1 << PWM_CONTROL_TRIGGER_SHIFT(chan));
>> +       writel(value, kp->base + PWM_CONTROL_OFFSET);
>>
>> -               kona_pwmc_apply_settings(kp, chan);
>> -       }
>> +       value = readl(kp->base + PRESCALE_OFFSET);
>> +       value &= ~PRESCALE_MASK(chan);
>> +       value |= prescale << PRESCALE_SHIFT(chan);
>> +       writel(value, kp->base + PRESCALE_OFFSET);
>> +
>> +       writel(pc, kp->base + PERIOD_COUNT_OFFSET(chan));
>> +
>> +       writel(dc, kp->base + DUTY_CYCLE_HIGH_OFFSET(chan));
>> +
>> +       kona_pwmc_apply_settings(kp, chan);
>>
>>         return 0;
>>  }
> 
> There is no requirement to lower the trigger bit prior to writing the
> period and duty registers.
> 
> This change is unnecessary.  The old sequence was fine.

Incorrect. The old sequence was flawed as already discussed. I'll refer
you the updated spec in previous discussion that was already sent to
you. Not following the spec really does occasionally result in no output
signal as the commit message states.

> 
>> @@ -173,11 +209,6 @@ static int kona_pwmc_set_polarity(struct pwm_chip *chip, struct pwm_device *pwm,
>>
>>         writel(value, kp->base + PWM_CONTROL_OFFSET);
>>
>> -       kona_pwmc_apply_settings(kp, chan);
>> -
>> -       /* Wait for waveform to settle before gating off the clock */
>> -       ndelay(400);
>> -
>>         clk_disable_unprepare(kp->clk);
>>
>>         return 0;
> 
> I'm not completely convinced that changing the polarity behavior is beneficial.
> 
> Please mention this change in your commit description and provide
> appropriate justification.

I'll update the commit message. You won't get any polarity change
without the added code. It doesn't work.

> 
>> @@ -190,12 +221,14 @@ static int kona_pwmc_enable(struct pwm_chip *chip, struct pwm_device *pwm)
>>
>>         ret = clk_prepare_enable(kp->clk);
>>         if (ret < 0) {
>> +               clear_bit(PWMF_ENABLED, &pwm->flags);
>>                 dev_err(chip->dev, "failed to enable clock: %d\n", ret);
>>                 return ret;
>>         }
>>
>>         ret = kona_pwmc_config(chip, pwm, pwm->duty_cycle, pwm->period);
>>         if (ret < 0) {
>> +               clear_bit(PWMF_ENABLED, &pwm->flags);
>>                 clk_disable_unprepare(kp->clk);
>>                 return ret;
>>         }
> 
> Don't try to fix this in the Kona PWM driver, fix it in the PWM core.

I agree that's where the fix should go. I wasn't sure I could make the
change or not. I'll make the change and put it in a different commit.

> 
>> @@ -207,13 +240,23 @@ static void kona_pwmc_disable(struct pwm_chip *chip, struct pwm_device *pwm)
>>  {
>>         struct kona_pwmc *kp = to_kona_pwmc(chip);
>>         unsigned int chan = pwm->hwpwm;
>> +       unsigned int value = readl(kp->base + PWM_CONTROL_OFFSET);
>> +
>> +       /* Set smooth type to 1 and disable */
>> +       value |= 1 << PWM_CONTROL_SMOOTH_SHIFT(chan);
>> +       value &= ~(1 << PWM_CONTROL_TRIGGER_SHIFT(chan));
>> +       writel(value, kp->base + PWM_CONTROL_OFFSET);
>>
>>         /* Simulate a disable by configuring for zero duty */
>>         writel(0, kp->base + DUTY_CYCLE_HIGH_OFFSET(chan));
>> -       kona_pwmc_apply_settings(kp, chan);
>> +       writel(0, kp->base + PERIOD_COUNT_OFFSET(chan));
>>
>> -       /* Wait for waveform to settle before gating off the clock */
>> -       ndelay(400);
>> +       /* Set prescale to 0 for this channel */
>> +       value = readl(kp->base + PRESCALE_OFFSET);
>> +       value &= ~PRESCALE_MASK(chan);
>> +       writel(value, kp->base + PRESCALE_OFFSET);
> 
> Can you explain why it is necessary to change the prescale here?

Spec recommendation and it's cleaner. We'd like the code to match the
spec now that we have more detailed documentation. There is nothing
dysfunctional about setting the prescale to the default value on disable
that I can see.

> 
>> +
>> +       kona_pwmc_apply_settings(kp, chan);
>>
>>         clk_disable_unprepare(kp->clk);
>>  }
>> --
>> 1.7.9.5
>>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
> Please read the FAQ at  http://www.tux.org/lkml/
> 


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

* [PATCH v4 0/3] Fix bugs in kona pwm driver and pwm core
       [not found] <Jonathan Richardson <jonathar@broadcom.com>
                   ` (5 preceding siblings ...)
  2014-12-19 22:17 ` [PATCH v2 0/2] Add support for Broadcom iProc touchscreen Jonathan Richardson
@ 2014-12-30 22:43 ` Jonathan Richardson
  2014-12-30 22:43   ` [PATCH v4 1/3] pwm: kona: Fix incorrect config, disable, and polarity procedures Jonathan Richardson
                     ` (2 more replies)
  2015-01-07 19:42 ` [PATCH v5 0/2] Fix bugs in kona pwm driver and pwm core Jonathan Richardson
                   ` (6 subsequent siblings)
  13 siblings, 3 replies; 92+ messages in thread
From: Jonathan Richardson @ 2014-12-30 22:43 UTC (permalink / raw)
  To: Tim Kryger
  Cc: Scott Branden, Arun Ramamurthy, Thierry Reding, Ray Jui,
	bcm-kernel-feedback-list, linux-kernel, linux-pwm,
	Jonathan Richardson

This patchset fixes a number of bugs in the Broadcom Kona pwm driver. It also 
fixes a bug in the pwm core where the state was incorrect on failed calls to
enable.

Changes from v3:
- Removed setting the pwm set to disabled if enable fails. This is now
  done in the pwm core.
- Removed previous change in kona_pwmc_config() that returned right away if
  the state was disabled. The loop needs to execute to ensure that the period
  and duty cycle are valid. Delaying this check to when the pwm is enabled is 
  incorrect.
- Added comments to clarify code.
- Changed commit messages to more accurately reflect the code changes.

Jonathan Richardson (3):
  pwm: kona: Fix incorrect config, disable, and polarity procedures
  pwm: kona: Remove setting default smooth type and polarity for all
    channels
  pwm: core: Set enable state properly on failed call to enable

 drivers/pwm/core.c         |   10 +++-
 drivers/pwm/pwm-bcm-kona.c |  116 ++++++++++++++++++++++++++++++++++++--------
 2 files changed, 104 insertions(+), 22 deletions(-)

-- 
1.7.9.5


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

* [PATCH v4 1/3] pwm: kona: Fix incorrect config, disable, and polarity procedures
  2014-12-30 22:43 ` [PATCH v4 0/3] Fix bugs in kona pwm driver and pwm core Jonathan Richardson
@ 2014-12-30 22:43   ` Jonathan Richardson
  2014-12-30 22:43   ` [PATCH v4 2/3] pwm: kona: Remove setting default smooth type and polarity for all channels Jonathan Richardson
  2014-12-30 22:43   ` [PATCH v4 3/3] pwm: core: Set enable state properly on failed call to enable Jonathan Richardson
  2 siblings, 0 replies; 92+ messages in thread
From: Jonathan Richardson @ 2014-12-30 22:43 UTC (permalink / raw)
  To: Tim Kryger
  Cc: Scott Branden, Arun Ramamurthy, Thierry Reding, Ray Jui,
	bcm-kernel-feedback-list, linux-kernel, linux-pwm,
	Jonathan Richardson

The config procedure didn't follow the spec which periodically resulted
in failing to enable the output signal. This happened one in ten or
twenty attempts. Following the spec and adding a 400ns delay in the
appropriate locations resolves this problem.

The disable procedure now also follows the spec. The old disable
procedure would result in no change in signal when called.

The polarity procedure no longer applies the settings to change the
output signal because it can't be called when the pwm is enabled anyway.
The polarity is only updated in the control register. The correct
polarity will be applied on enable. The old method of applying changes
would result in no signal when the polarity was changed. The new
apply_settings function would fix this problem but it isn't required
anyway.

Reviewed-by: Arun Ramamurthy <arunrama@broadcom.com>
Reviewed-by: Scott Branden <sbranden@broadcom.com>
Tested-by: Scott Branden <sbranden@broadcom.com>
Signed-off-by: Jonathan Richardson <jonathar@broadcom.com>
---
 drivers/pwm/pwm-bcm-kona.c |   75 +++++++++++++++++++++++++++++++++++---------
 1 file changed, 60 insertions(+), 15 deletions(-)

diff --git a/drivers/pwm/pwm-bcm-kona.c b/drivers/pwm/pwm-bcm-kona.c
index 02bc048..5ae4bf7 100644
--- a/drivers/pwm/pwm-bcm-kona.c
+++ b/drivers/pwm/pwm-bcm-kona.c
@@ -80,15 +80,19 @@ static void kona_pwmc_apply_settings(struct kona_pwmc *kp, unsigned int chan)
 {
 	unsigned int value = readl(kp->base + PWM_CONTROL_OFFSET);
 
-	/* Clear trigger bit but set smooth bit to maintain old output */
-	value |= 1 << PWM_CONTROL_SMOOTH_SHIFT(chan);
-	value &= ~(1 << PWM_CONTROL_TRIGGER_SHIFT(chan));
-	writel(value, kp->base + PWM_CONTROL_OFFSET);
+	/*
+	 * There must be a min 400ns delay between clearing enable and setting
+	 * it. Failing to do this may result in no PWM signal.
+	 */
+	ndelay(400);
 
 	/* Set trigger bit and clear smooth bit to apply new settings */
 	value &= ~(1 << PWM_CONTROL_SMOOTH_SHIFT(chan));
 	value |= 1 << PWM_CONTROL_TRIGGER_SHIFT(chan);
 	writel(value, kp->base + PWM_CONTROL_OFFSET);
+
+	/* PWMOUT_ENABLE must be held high for at least 400 ns. */
+	ndelay(400);
 }
 
 static int kona_pwmc_config(struct pwm_chip *chip, struct pwm_device *pwm,
@@ -121,20 +125,56 @@ static int kona_pwmc_config(struct pwm_chip *chip, struct pwm_device *pwm,
 		dc = div64_u64(val, div);
 
 		/* If duty_ns or period_ns are not achievable then return */
-		if (pc < PERIOD_COUNT_MIN || dc < DUTY_CYCLE_HIGH_MIN)
+		if (pc < PERIOD_COUNT_MIN) {
+			dev_warn(chip->dev,
+				"%s: pwm[%d]: period=%d is not achievable, pc=%lu, prescale=%lu\n",
+				__func__, chan, period_ns, pc, prescale);
+			return -EINVAL;
+		}
+
+		/* If duty_ns is not achievable then return */
+		if (dc < DUTY_CYCLE_HIGH_MIN) {
+			if (0 != duty_ns) {
+				dev_warn(chip->dev,
+					"%s: pwm[%d]: duty cycle=%d is not achievable, dc=%lu, prescale=%lu\n",
+					__func__, chan, duty_ns, dc, prescale);
+			}
 			return -EINVAL;
+		}
 
 		/* If pc and dc are in bounds, the calculation is done */
 		if (pc <= PERIOD_COUNT_MAX && dc <= DUTY_CYCLE_HIGH_MAX)
 			break;
 
 		/* Otherwise, increase prescale and recalculate pc and dc */
-		if (++prescale > PRESCALE_MAX)
+		if (++prescale > PRESCALE_MAX) {
+			dev_warn(chip->dev,
+				"%s: pwm[%d]: Prescale (=%lu) within max (=%d) for period=%d and duty cycle=%d is not achievable\n",
+				__func__, chan, prescale, PRESCALE_MAX,
+				period_ns, duty_ns);
 			return -EINVAL;
+		}
 	}
 
-	/* If the PWM channel is enabled, write the settings to the HW */
+	dev_dbg(chip->dev, "pwm[%d]: period=%lu, duty_high=%lu, prescale=%lu\n",
+		chan, pc, dc, prescale);
+
+	/*
+	 * Don't apply settings if disabled. The period and duty cycle are
+	 * always calculated above to ensure the new values are
+	 * validated immediately instead of on enable.
+	 */
 	if (test_bit(PWMF_ENABLED, &pwm->flags)) {
+		value = readl(kp->base + PWM_CONTROL_OFFSET);
+
+		/*
+		 * Clear trigger bit but set smooth bit to maintain old
+		 * output.
+		 */
+		value |= 1 << PWM_CONTROL_SMOOTH_SHIFT(chan);
+		value &= ~(1 << PWM_CONTROL_TRIGGER_SHIFT(chan));
+		writel(value, kp->base + PWM_CONTROL_OFFSET);
+
 		value = readl(kp->base + PRESCALE_OFFSET);
 		value &= ~PRESCALE_MASK(chan);
 		value |= prescale << PRESCALE_SHIFT(chan);
@@ -173,11 +213,6 @@ static int kona_pwmc_set_polarity(struct pwm_chip *chip, struct pwm_device *pwm,
 
 	writel(value, kp->base + PWM_CONTROL_OFFSET);
 
-	kona_pwmc_apply_settings(kp, chan);
-
-	/* Wait for waveform to settle before gating off the clock */
-	ndelay(400);
-
 	clk_disable_unprepare(kp->clk);
 
 	return 0;
@@ -207,13 +242,23 @@ static void kona_pwmc_disable(struct pwm_chip *chip, struct pwm_device *pwm)
 {
 	struct kona_pwmc *kp = to_kona_pwmc(chip);
 	unsigned int chan = pwm->hwpwm;
+	unsigned int value = readl(kp->base + PWM_CONTROL_OFFSET);
+
+	/* Set smooth type to 1 and disable */
+	value |= 1 << PWM_CONTROL_SMOOTH_SHIFT(chan);
+	value &= ~(1 << PWM_CONTROL_TRIGGER_SHIFT(chan));
+	writel(value, kp->base + PWM_CONTROL_OFFSET);
 
 	/* Simulate a disable by configuring for zero duty */
 	writel(0, kp->base + DUTY_CYCLE_HIGH_OFFSET(chan));
-	kona_pwmc_apply_settings(kp, chan);
+	writel(0, kp->base + PERIOD_COUNT_OFFSET(chan));
 
-	/* Wait for waveform to settle before gating off the clock */
-	ndelay(400);
+	/* Set prescale to 0 for this channel */
+	value = readl(kp->base + PRESCALE_OFFSET);
+	value &= ~PRESCALE_MASK(chan);
+	writel(value, kp->base + PRESCALE_OFFSET);
+
+	kona_pwmc_apply_settings(kp, chan);
 
 	clk_disable_unprepare(kp->clk);
 }
-- 
1.7.9.5


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

* [PATCH v4 2/3] pwm: kona: Remove setting default smooth type and polarity for all channels
  2014-12-30 22:43 ` [PATCH v4 0/3] Fix bugs in kona pwm driver and pwm core Jonathan Richardson
  2014-12-30 22:43   ` [PATCH v4 1/3] pwm: kona: Fix incorrect config, disable, and polarity procedures Jonathan Richardson
@ 2014-12-30 22:43   ` Jonathan Richardson
  2015-01-05  1:12     ` Tim Kryger
  2014-12-30 22:43   ` [PATCH v4 3/3] pwm: core: Set enable state properly on failed call to enable Jonathan Richardson
  2 siblings, 1 reply; 92+ messages in thread
From: Jonathan Richardson @ 2014-12-30 22:43 UTC (permalink / raw)
  To: Tim Kryger
  Cc: Scott Branden, Arun Ramamurthy, Thierry Reding, Ray Jui,
	bcm-kernel-feedback-list, linux-kernel, linux-pwm,
	Jonathan Richardson

Setting the default polarity in probe to normal for all channels caused
the speaker pwm channel to click. The polarity does need to be set to
normal because the hw default is inversed whereas the pwm framework
defaults to normal. If a channel is enabled without setting the polarity
then the signal would be inversed while linux reports normal. A check
is now done prior to enabling the channel to ensure that the hw polarity
matches the desired polarity and is changed if there is a discrepency. This
prevents unnecessary settings being applied to unused channels but still
ensures the correct polarity to be set.

Reviewed-by: Scott Branden <sbranden@broadcom.com>
Tested-by: Scott Branden <sbranden@broadcom.com>
Signed-off-by: Jonathan Richardson <jonathar@broadcom.com>
---
 drivers/pwm/pwm-bcm-kona.c |   41 ++++++++++++++++++++++++++++++++++++-----
 1 file changed, 36 insertions(+), 5 deletions(-)

diff --git a/drivers/pwm/pwm-bcm-kona.c b/drivers/pwm/pwm-bcm-kona.c
index 5ae4bf7..34d434a 100644
--- a/drivers/pwm/pwm-bcm-kona.c
+++ b/drivers/pwm/pwm-bcm-kona.c
@@ -95,6 +95,32 @@ static void kona_pwmc_apply_settings(struct kona_pwmc *kp, unsigned int chan)
 	ndelay(400);
 }
 
+static void kona_pwmc_check_set_polarity(struct pwm_chip *chip,
+	struct pwm_device *pwm)
+{
+	struct kona_pwmc *kp = to_kona_pwmc(chip);
+	unsigned int chan = pwm->hwpwm;
+	enum pwm_polarity polarity = pwm->polarity;
+	unsigned int hw_pol;
+	unsigned int value = 0;
+
+	value = hw_pol = readl(kp->base + PWM_CONTROL_OFFSET);
+	hw_pol = (hw_pol >> PWM_CONTROL_POLARITY_SHIFT(chan)) & 0x1;
+
+	/*
+	 * If current polarity not the same as h/w then set polarity so that
+	 * they match.
+	 */
+	if (!hw_pol != polarity) {
+		if (polarity == PWM_POLARITY_NORMAL)
+			value |= 1 << PWM_CONTROL_POLARITY_SHIFT(chan);
+		else
+			value &= ~(1 << PWM_CONTROL_POLARITY_SHIFT(chan));
+
+		writel(value, kp->base + PWM_CONTROL_OFFSET);
+	}
+}
+
 static int kona_pwmc_config(struct pwm_chip *chip, struct pwm_device *pwm,
 			    int duty_ns, int period_ns)
 {
@@ -165,6 +191,14 @@ static int kona_pwmc_config(struct pwm_chip *chip, struct pwm_device *pwm,
 	 * validated immediately instead of on enable.
 	 */
 	if (test_bit(PWMF_ENABLED, &pwm->flags)) {
+		/*
+		 * Ensure polarity is set properly. The default value
+		 * for h/w and the PWM framework are different. If a
+		 * channel is enabled without setting the polarity, the
+		 * default value would be inconsistent to the signal.
+		 */
+		kona_pwmc_check_set_polarity(chip, pwm);
+
 		value = readl(kp->base + PWM_CONTROL_OFFSET);
 
 		/*
@@ -311,12 +345,9 @@ static int kona_pwmc_probe(struct platform_device *pdev)
 		return ret;
 	}
 
-	/* Set smooth mode, push/pull, and normal polarity for all channels */
-	for (chan = 0; chan < kp->chip.npwm; chan++) {
-		value |= (1 << PWM_CONTROL_SMOOTH_SHIFT(chan));
+	/* Set push/pull for all channels */
+	for (chan = 0; chan < kp->chip.npwm; chan++)
 		value |= (1 << PWM_CONTROL_TYPE_SHIFT(chan));
-		value |= (1 << PWM_CONTROL_POLARITY_SHIFT(chan));
-	}
 
 	writel(value, kp->base + PWM_CONTROL_OFFSET);
 
-- 
1.7.9.5


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

* [PATCH v4 3/3] pwm: core: Set enable state properly on failed call to enable
  2014-12-30 22:43 ` [PATCH v4 0/3] Fix bugs in kona pwm driver and pwm core Jonathan Richardson
  2014-12-30 22:43   ` [PATCH v4 1/3] pwm: kona: Fix incorrect config, disable, and polarity procedures Jonathan Richardson
  2014-12-30 22:43   ` [PATCH v4 2/3] pwm: kona: Remove setting default smooth type and polarity for all channels Jonathan Richardson
@ 2014-12-30 22:43   ` Jonathan Richardson
  2 siblings, 0 replies; 92+ messages in thread
From: Jonathan Richardson @ 2014-12-30 22:43 UTC (permalink / raw)
  To: Tim Kryger
  Cc: Scott Branden, Arun Ramamurthy, Thierry Reding, Ray Jui,
	bcm-kernel-feedback-list, linux-kernel, linux-pwm,
	Jonathan Richardson

The pwm_enable function didn't clear the enabled bit if a call to a
clients enable function returned an error. The result was that the state
of the pwm core was wrong. Clearing the bit when enable returns an error
ensures the state is properly set.

Signed-off-by: Jonathan Richardson <jonathar@broadcom.com>
---
 drivers/pwm/core.c |   10 ++++++++--
 1 file changed, 8 insertions(+), 2 deletions(-)

diff --git a/drivers/pwm/core.c b/drivers/pwm/core.c
index 966497d..641f6ec 100644
--- a/drivers/pwm/core.c
+++ b/drivers/pwm/core.c
@@ -457,8 +457,14 @@ EXPORT_SYMBOL_GPL(pwm_set_polarity);
  */
 int pwm_enable(struct pwm_device *pwm)
 {
-	if (pwm && !test_and_set_bit(PWMF_ENABLED, &pwm->flags))
-		return pwm->chip->ops->enable(pwm->chip, pwm);
+	int err;
+
+	if (pwm && !test_and_set_bit(PWMF_ENABLED, &pwm->flags)) {
+		err = pwm->chip->ops->enable(pwm->chip, pwm);
+		if (err)
+			clear_bit(PWMF_ENABLED, &pwm->flags);
+		return err;
+	}
 
 	return pwm ? 0 : -EINVAL;
 }
-- 
1.7.9.5


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

* Re: [PATCH v2 1/2] Input: touchscreen-iproc: Add Broadcom iProc touchscreen driver
  2014-12-19 23:03       ` Jonathan Richardson
@ 2015-01-01  0:55         ` Jonathan Richardson
  2015-01-15  1:08         ` Florian Fainelli
  1 sibling, 0 replies; 92+ messages in thread
From: Jonathan Richardson @ 2015-01-01  0:55 UTC (permalink / raw)
  To: Joe Perches
  Cc: Dmitry Torokhov, Grant Likely, Rob Herring, Ray Jui,
	linux-kernel, linux-input, linux-arm-kernel,
	bcm-kernel-feedback-list, devicetree

Hi,

Would anyone be able to look at this to help us move forward? Thanks.

On 14-12-19 03:03 PM, Jonathan Richardson wrote:
> On 14-12-19 02:26 PM, Joe Perches wrote:
>> On Fri, 2014-12-19 at 14:17 -0800, Jonathan Richardson wrote:
>>> Add initial version of the Broadcom touchscreen driver.
>>
>> more trivia:
>>
>>> diff --git a/drivers/input/touchscreen/bcm_iproc_tsc.c b/drivers/input/touchscreen/bcm_iproc_tsc.c
>> []
>>> +static int get_tsc_config(struct device_node *np, struct iproc_ts_priv *priv)
>>> +{
>>> +	u32 val;
>> []
>>> +	if (of_property_read_u32(np, "debounce_timeout", &val) >= 0) {
>>> +		if (val < 0 || val > 255) {
>>> +			dev_err(dev, "debounce_timeout must be [0-255]\n");
>>> +			return -EINVAL;
>>> +		}
>>> +		priv->cfg_params.debounce_timeout = val;
>>
>> Doesn't the compiler generate a warning message
>> about an impossible "unsigned < 0" test for all
>> of these "val < 0" uses?
>>
> 
> Actually no it doesn't. The gcc output shows that neither -Wtype-limits
> nor -Wextra are used to compile that file. I assume this is because
> there would be just too many warnings.
> 
> 
>>> +	}
>>> +
>>> +	if (of_property_read_u32(np, "settling_timeout", &val) >= 0) {
>>> +		if (val < 0 || val > 11) {
>> []
>>> +	if (of_property_read_u32(np, "touch_timeout", &val) >= 0) {
>>> +		if (val < 0 || val > 255) {
>> []
>>> +	if (of_property_read_u32(np, "average_data", &val) >= 0) {
>>> +		if (val < 0 || val > 8) {
>> []
>>> +	if (of_property_read_u32(np, "fifo_threshold", &val) >= 0) {
>>> +		if (val < 0 || val > 31) {
>>
>>
> 


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

* Re: [PATCH v4 2/3] pwm: kona: Remove setting default smooth type and polarity for all channels
  2014-12-30 22:43   ` [PATCH v4 2/3] pwm: kona: Remove setting default smooth type and polarity for all channels Jonathan Richardson
@ 2015-01-05  1:12     ` Tim Kryger
  2015-01-05  1:33       ` Tim Kryger
  0 siblings, 1 reply; 92+ messages in thread
From: Tim Kryger @ 2015-01-05  1:12 UTC (permalink / raw)
  To: Jonathan Richardson
  Cc: Scott Branden, Arun Ramamurthy, Thierry Reding, Ray Jui,
	bcm-kernel-feedback-list, Linux Kernel Mailing List, linux-pwm

On Tue, Dec 30, 2014 at 2:43 PM, Jonathan Richardson
<jonathar@broadcom.com> wrote:
> Setting the default polarity in probe to normal for all channels caused
> the speaker pwm channel to click. The polarity does need to be set to
> normal because the hw default is inversed whereas the pwm framework
> defaults to normal. If a channel is enabled without setting the polarity
> then the signal would be inversed while linux reports normal. A check
> is now done prior to enabling the channel to ensure that the hw polarity
> matches the desired polarity and is changed if there is a discrepency. This
> prevents unnecessary settings being applied to unused channels but still
> ensures the correct polarity to be set.

A more direct solution that avoids the potentially undesirable
consequences of delaying when polarity changes are written to hardware
would be to update the PWM framework to allow for the registration of
chips with inversed default polarity.

I will post a patch for your review.

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

* Re: [PATCH v4 2/3] pwm: kona: Remove setting default smooth type and polarity for all channels
  2015-01-05  1:12     ` Tim Kryger
@ 2015-01-05  1:33       ` Tim Kryger
  0 siblings, 0 replies; 92+ messages in thread
From: Tim Kryger @ 2015-01-05  1:33 UTC (permalink / raw)
  To: Jonathan Richardson
  Cc: Scott Branden, Arun Ramamurthy, Thierry Reding, Ray Jui,
	bcm-kernel-feedback-list, Linux Kernel Mailing List, linux-pwm

On Sun, Jan 4, 2015 at 5:12 PM, Tim Kryger <tim.kryger@gmail.com> wrote:
> On Tue, Dec 30, 2014 at 2:43 PM, Jonathan Richardson
> <jonathar@broadcom.com> wrote:
>> Setting the default polarity in probe to normal for all channels caused
>> the speaker pwm channel to click. The polarity does need to be set to
>> normal because the hw default is inversed whereas the pwm framework
>> defaults to normal. If a channel is enabled without setting the polarity
>> then the signal would be inversed while linux reports normal. A check
>> is now done prior to enabling the channel to ensure that the hw polarity
>> matches the desired polarity and is changed if there is a discrepency. This
>> prevents unnecessary settings being applied to unused channels but still
>> ensures the correct polarity to be set.
>
> A more direct solution that avoids the potentially undesirable
> consequences of delaying when polarity changes are written to hardware
> would be to update the PWM framework to allow for the registration of
> chips with inversed default polarity.
>
> I will post a patch for your review.

Please see:  https://lkml.org/lkml/2015/1/4/199

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

* [PATCH v5 0/2] Fix bugs in kona pwm driver and pwm core
       [not found] <Jonathan Richardson <jonathar@broadcom.com>
                   ` (6 preceding siblings ...)
  2014-12-30 22:43 ` [PATCH v4 0/3] Fix bugs in kona pwm driver and pwm core Jonathan Richardson
@ 2015-01-07 19:42 ` Jonathan Richardson
  2015-01-07 19:42   ` [PATCH v5 1/2] pwm: kona: Fix incorrect config, disable, and polarity procedures Jonathan Richardson
  2015-01-07 19:42   ` [PATCH v5 2/2] pwm: core: Set enable state properly on failed call to enable Jonathan Richardson
  2015-02-24 19:13 ` [PATCH 0/1] Enable Broadcom Cygnus BCM958305K Jonathan Richardson
                   ` (5 subsequent siblings)
  13 siblings, 2 replies; 92+ messages in thread
From: Jonathan Richardson @ 2015-01-07 19:42 UTC (permalink / raw)
  To: Tim Kryger
  Cc: Scott Branden, Arun Ramamurthy, Thierry Reding, Ray Jui,
	bcm-kernel-feedback-list, linux-kernel, linux-pwm,
	Jonathan Richardson

This patchset fixes a number of bugs in the Broadcom Kona pwm driver. It also 
fixes a bug in the pwm core where the state was incorrect on failed calls to
enable.

Changes from v4:
  - Rebased to Tim Kryger's patch that adds support in pwm core to add driver 
    with inversed polarity.   
  - Removed patch 2 that resolved difference between hardware default polarity
    and pwm framework default polarity. The default polarity is set properly now
    when the pwm driver is registered with the pwm framework.

Jonathan Richardson (2):
  pwm: kona: Fix incorrect config, disable, and polarity procedures
  pwm: core: Set enable state properly on failed call to enable

 drivers/pwm/core.c         |   10 ++++--
 drivers/pwm/pwm-bcm-kona.c |   75 +++++++++++++++++++++++++++++++++++---------
 2 files changed, 68 insertions(+), 17 deletions(-)

-- 
1.7.9.5


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

* [PATCH v5 1/2] pwm: kona: Fix incorrect config, disable, and polarity procedures
  2015-01-07 19:42 ` [PATCH v5 0/2] Fix bugs in kona pwm driver and pwm core Jonathan Richardson
@ 2015-01-07 19:42   ` Jonathan Richardson
  2015-01-07 19:42   ` [PATCH v5 2/2] pwm: core: Set enable state properly on failed call to enable Jonathan Richardson
  1 sibling, 0 replies; 92+ messages in thread
From: Jonathan Richardson @ 2015-01-07 19:42 UTC (permalink / raw)
  To: Tim Kryger
  Cc: Scott Branden, Arun Ramamurthy, Thierry Reding, Ray Jui,
	bcm-kernel-feedback-list, linux-kernel, linux-pwm,
	Jonathan Richardson

The config procedure didn't follow the spec which periodically resulted
in failing to enable the output signal. This happened one in ten or
twenty attempts. Following the spec and adding a 400ns delay in the
appropriate locations resolves this problem.

The disable procedure now also follows the spec. The old disable
procedure would result in no change in signal when called.

The polarity procedure no longer applies the settings to change the
output signal because it can't be called when the pwm is enabled anyway.
The polarity is only updated in the control register. The correct
polarity will be applied on enable. The old method of applying changes
would result in no signal when the polarity was changed. The new
apply_settings function would fix this problem but it isn't required
anyway.

Reviewed-by: Arun Ramamurthy <arunrama@broadcom.com>
Reviewed-by: Scott Branden <sbranden@broadcom.com>
Tested-by: Scott Branden <sbranden@broadcom.com>
Signed-off-by: Jonathan Richardson <jonathar@broadcom.com>
---
 drivers/pwm/pwm-bcm-kona.c |   75 +++++++++++++++++++++++++++++++++++---------
 1 file changed, 60 insertions(+), 15 deletions(-)

diff --git a/drivers/pwm/pwm-bcm-kona.c b/drivers/pwm/pwm-bcm-kona.c
index 32b3ec6..8a1dfba 100644
--- a/drivers/pwm/pwm-bcm-kona.c
+++ b/drivers/pwm/pwm-bcm-kona.c
@@ -80,15 +80,19 @@ static void kona_pwmc_apply_settings(struct kona_pwmc *kp, unsigned int chan)
 {
 	unsigned int value = readl(kp->base + PWM_CONTROL_OFFSET);
 
-	/* Clear trigger bit but set smooth bit to maintain old output */
-	value |= 1 << PWM_CONTROL_SMOOTH_SHIFT(chan);
-	value &= ~(1 << PWM_CONTROL_TRIGGER_SHIFT(chan));
-	writel(value, kp->base + PWM_CONTROL_OFFSET);
+	/*
+	 * There must be a min 400ns delay between clearing enable and setting
+	 * it. Failing to do this may result in no PWM signal.
+	 */
+	ndelay(400);
 
 	/* Set trigger bit and clear smooth bit to apply new settings */
 	value &= ~(1 << PWM_CONTROL_SMOOTH_SHIFT(chan));
 	value |= 1 << PWM_CONTROL_TRIGGER_SHIFT(chan);
 	writel(value, kp->base + PWM_CONTROL_OFFSET);
+
+	/* PWMOUT_ENABLE must be held high for at least 400 ns. */
+	ndelay(400);
 }
 
 static int kona_pwmc_config(struct pwm_chip *chip, struct pwm_device *pwm,
@@ -121,20 +125,56 @@ static int kona_pwmc_config(struct pwm_chip *chip, struct pwm_device *pwm,
 		dc = div64_u64(val, div);
 
 		/* If duty_ns or period_ns are not achievable then return */
-		if (pc < PERIOD_COUNT_MIN || dc < DUTY_CYCLE_HIGH_MIN)
+		if (pc < PERIOD_COUNT_MIN) {
+			dev_warn(chip->dev,
+				"%s: pwm[%d]: period=%d is not achievable, pc=%lu, prescale=%lu\n",
+				__func__, chan, period_ns, pc, prescale);
+			return -EINVAL;
+		}
+
+		/* If duty_ns is not achievable then return */
+		if (dc < DUTY_CYCLE_HIGH_MIN) {
+			if (0 != duty_ns) {
+				dev_warn(chip->dev,
+					"%s: pwm[%d]: duty cycle=%d is not achievable, dc=%lu, prescale=%lu\n",
+					__func__, chan, duty_ns, dc, prescale);
+			}
 			return -EINVAL;
+		}
 
 		/* If pc and dc are in bounds, the calculation is done */
 		if (pc <= PERIOD_COUNT_MAX && dc <= DUTY_CYCLE_HIGH_MAX)
 			break;
 
 		/* Otherwise, increase prescale and recalculate pc and dc */
-		if (++prescale > PRESCALE_MAX)
+		if (++prescale > PRESCALE_MAX) {
+			dev_warn(chip->dev,
+				"%s: pwm[%d]: Prescale (=%lu) within max (=%d) for period=%d and duty cycle=%d is not achievable\n",
+				__func__, chan, prescale, PRESCALE_MAX,
+				period_ns, duty_ns);
 			return -EINVAL;
+		}
 	}
 
-	/* If the PWM channel is enabled, write the settings to the HW */
+	dev_dbg(chip->dev, "pwm[%d]: period=%lu, duty_high=%lu, prescale=%lu\n",
+		chan, pc, dc, prescale);
+
+	/*
+	 * Don't apply settings if disabled. The period and duty cycle are
+	 * always calculated above to ensure the new values are
+	 * validated immediately instead of on enable.
+	 */
 	if (test_bit(PWMF_ENABLED, &pwm->flags)) {
+		value = readl(kp->base + PWM_CONTROL_OFFSET);
+
+		/*
+		 * Clear trigger bit but set smooth bit to maintain old
+		 * output.
+		 */
+		value |= 1 << PWM_CONTROL_SMOOTH_SHIFT(chan);
+		value &= ~(1 << PWM_CONTROL_TRIGGER_SHIFT(chan));
+		writel(value, kp->base + PWM_CONTROL_OFFSET);
+
 		value = readl(kp->base + PRESCALE_OFFSET);
 		value &= ~PRESCALE_MASK(chan);
 		value |= prescale << PRESCALE_SHIFT(chan);
@@ -173,11 +213,6 @@ static int kona_pwmc_set_polarity(struct pwm_chip *chip, struct pwm_device *pwm,
 
 	writel(value, kp->base + PWM_CONTROL_OFFSET);
 
-	kona_pwmc_apply_settings(kp, chan);
-
-	/* Wait for waveform to settle before gating off the clock */
-	ndelay(400);
-
 	clk_disable_unprepare(kp->clk);
 
 	return 0;
@@ -207,13 +242,23 @@ static void kona_pwmc_disable(struct pwm_chip *chip, struct pwm_device *pwm)
 {
 	struct kona_pwmc *kp = to_kona_pwmc(chip);
 	unsigned int chan = pwm->hwpwm;
+	unsigned int value = readl(kp->base + PWM_CONTROL_OFFSET);
+
+	/* Set smooth type to 1 and disable */
+	value |= 1 << PWM_CONTROL_SMOOTH_SHIFT(chan);
+	value &= ~(1 << PWM_CONTROL_TRIGGER_SHIFT(chan));
+	writel(value, kp->base + PWM_CONTROL_OFFSET);
 
 	/* Simulate a disable by configuring for zero duty */
 	writel(0, kp->base + DUTY_CYCLE_HIGH_OFFSET(chan));
-	kona_pwmc_apply_settings(kp, chan);
+	writel(0, kp->base + PERIOD_COUNT_OFFSET(chan));
 
-	/* Wait for waveform to settle before gating off the clock */
-	ndelay(400);
+	/* Set prescale to 0 for this channel */
+	value = readl(kp->base + PRESCALE_OFFSET);
+	value &= ~PRESCALE_MASK(chan);
+	writel(value, kp->base + PRESCALE_OFFSET);
+
+	kona_pwmc_apply_settings(kp, chan);
 
 	clk_disable_unprepare(kp->clk);
 }
-- 
1.7.9.5


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

* [PATCH v5 2/2] pwm: core: Set enable state properly on failed call to enable
  2015-01-07 19:42 ` [PATCH v5 0/2] Fix bugs in kona pwm driver and pwm core Jonathan Richardson
  2015-01-07 19:42   ` [PATCH v5 1/2] pwm: kona: Fix incorrect config, disable, and polarity procedures Jonathan Richardson
@ 2015-01-07 19:42   ` Jonathan Richardson
  2015-02-11 23:59     ` Dmitry Torokhov
  1 sibling, 1 reply; 92+ messages in thread
From: Jonathan Richardson @ 2015-01-07 19:42 UTC (permalink / raw)
  To: Tim Kryger
  Cc: Scott Branden, Arun Ramamurthy, Thierry Reding, Ray Jui,
	bcm-kernel-feedback-list, linux-kernel, linux-pwm,
	Jonathan Richardson

The pwm_enable function didn't clear the enabled bit if a call to a
clients enable function returned an error. The result was that the state
of the pwm core was wrong. Clearing the bit when enable returns an error
ensures the state is properly set.

Tested-by: Jonathan Richardson <jonathar@broadcom.com>
Signed-off-by: Jonathan Richardson <jonathar@broadcom.com>
---
 drivers/pwm/core.c |   10 ++++++++--
 1 file changed, 8 insertions(+), 2 deletions(-)

diff --git a/drivers/pwm/core.c b/drivers/pwm/core.c
index f28c4ce..c33e24f 100644
--- a/drivers/pwm/core.c
+++ b/drivers/pwm/core.c
@@ -477,8 +477,14 @@ EXPORT_SYMBOL_GPL(pwm_set_polarity);
  */
 int pwm_enable(struct pwm_device *pwm)
 {
-	if (pwm && !test_and_set_bit(PWMF_ENABLED, &pwm->flags))
-		return pwm->chip->ops->enable(pwm->chip, pwm);
+	int err;
+
+	if (pwm && !test_and_set_bit(PWMF_ENABLED, &pwm->flags)) {
+		err = pwm->chip->ops->enable(pwm->chip, pwm);
+		if (err)
+			clear_bit(PWMF_ENABLED, &pwm->flags);
+		return err;
+	}
 
 	return pwm ? 0 : -EINVAL;
 }
-- 
1.7.9.5


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

* Re: [PATCH v2 1/2] Input: touchscreen-iproc: Add Broadcom iProc touchscreen driver
  2014-12-19 22:17   ` [PATCH v2 1/2] Input: touchscreen-iproc: Add Broadcom iProc touchscreen driver Jonathan Richardson
  2014-12-19 22:26     ` Joe Perches
@ 2015-01-15  1:02     ` Dmitry Torokhov
  2015-01-15  5:44       ` Scott Branden
  2015-02-24 23:29     ` Dmitry Torokhov
  2 siblings, 1 reply; 92+ messages in thread
From: Dmitry Torokhov @ 2015-01-15  1:02 UTC (permalink / raw)
  To: Jonathan Richardson
  Cc: Grant Likely, Rob Herring, Ray Jui, linux-kernel, linux-input,
	linux-arm-kernel, bcm-kernel-feedback-list, devicetree,
	Joe Perches

Hi Jonathan,

On Fri, Dec 19, 2014 at 02:17:49PM -0800, Jonathan Richardson wrote:
> +	if (of_property_read_u32(np, "scanning_period", &val) >= 0) {
> +		if (val < 1 || val > 256) {
> +			dev_err(dev, "scanning_period must be [1-256]\n");
> +			return -EINVAL;
> +		}
> +		priv->cfg_params.scanning_period = val;
> +	}
> +
> +	if (of_property_read_u32(np, "debounce_timeout", &val) >= 0) {
> +		if (val < 0 || val > 255) {
> +			dev_err(dev, "debounce_timeout must be [0-255]\n");
> +			return -EINVAL;
> +		}
> +		priv->cfg_params.debounce_timeout = val;
> +	}
> +
> +	if (of_property_read_u32(np, "settling_timeout", &val) >= 0) {
> +		if (val < 0 || val > 11) {
> +			dev_err(dev, "settling_timeout must be [0-11]\n");
> +			return -EINVAL;
> +		}
> +		priv->cfg_params.settling_timeout = val;
> +	}
> +
> +	if (of_property_read_u32(np, "touch_timeout", &val) >= 0) {
> +		if (val < 0 || val > 255) {
> +			dev_err(dev, "touch_timeout must be [0-255]\n");
> +			return -EINVAL;
> +		}
> +		priv->cfg_params.touch_timeout = val;
> +	}
> +
> +	if (of_property_read_u32(np, "average_data", &val) >= 0) {
> +		if (val < 0 || val > 8) {
> +			dev_err(dev, "average_data must be [0-8]\n");
> +			return -EINVAL;
> +		}
> +		priv->cfg_params.average_data = val;
> +	}
> +
> +	if (of_property_read_u32(np, "fifo_threshold", &val) >= 0) {
> +		if (val < 0 || val > 31) {
> +			dev_err(dev, "fifo_threshold must be [0-31]\n");
> +			return -EINVAL;
> +		}
> +		priv->cfg_params.fifo_threshold = val;
> +	}

I think these are dveice specific and thus should have "brcm," prefix.

> +
> +	priv->ts_rotation = TS_ROTATION_0;
> +	if (of_property_read_u32(np, "ts-rotation", &val) >= 0) {
> +		priv->ts_rotation = val;
> +		dev_dbg(dev, "ts rotation [%d] degrees\n",
> +			90 * priv->ts_rotation);
> +	}

This I am not quite sure about - if we want rotation or swap+invert. You
are CCed on another email (tsc2007) that talks about need of generic
touchscreen transforms in input core/of bindings.

Thanks.

-- 
Dmitry

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

* Re: [PATCH v2 1/2] Input: touchscreen-iproc: Add Broadcom iProc touchscreen driver
  2014-12-19 23:03       ` Jonathan Richardson
  2015-01-01  0:55         ` Jonathan Richardson
@ 2015-01-15  1:08         ` Florian Fainelli
  2015-01-15 19:19           ` Jonathan Richardson
  1 sibling, 1 reply; 92+ messages in thread
From: Florian Fainelli @ 2015-01-15  1:08 UTC (permalink / raw)
  To: Jonathan Richardson, Joe Perches
  Cc: devicetree, Ray Jui, Dmitry Torokhov, linux-kernel, Rob Herring,
	bcm-kernel-feedback-list, linux-input, Grant Likely,
	linux-arm-kernel

On 19/12/14 15:03, Jonathan Richardson wrote:
> On 14-12-19 02:26 PM, Joe Perches wrote:
>> On Fri, 2014-12-19 at 14:17 -0800, Jonathan Richardson wrote:
>>> Add initial version of the Broadcom touchscreen driver.
>>
>> more trivia:
>>
>>> diff --git a/drivers/input/touchscreen/bcm_iproc_tsc.c b/drivers/input/touchscreen/bcm_iproc_tsc.c
>> []
>>> +static int get_tsc_config(struct device_node *np, struct iproc_ts_priv *priv)
>>> +{
>>> +	u32 val;
>> []
>>> +	if (of_property_read_u32(np, "debounce_timeout", &val) >= 0) {
>>> +		if (val < 0 || val > 255) {
>>> +			dev_err(dev, "debounce_timeout must be [0-255]\n");
>>> +			return -EINVAL;
>>> +		}
>>> +		priv->cfg_params.debounce_timeout = val;

BTW, common practice for DT properties is to use a dash instead of an
underscore for multi-worded properties.

>>
>> Doesn't the compiler generate a warning message
>> about an impossible "unsigned < 0" test for all
>> of these "val < 0" uses?
>>
> 
> Actually no it doesn't. The gcc output shows that neither -Wtype-limits
> nor -Wextra are used to compile that file. I assume this is because
> there would be just too many warnings.
> 
> 
>>> +	}
>>> +
>>> +	if (of_property_read_u32(np, "settling_timeout", &val) >= 0) {
>>> +		if (val < 0 || val > 11) {
>> []
>>> +	if (of_property_read_u32(np, "touch_timeout", &val) >= 0) {
>>> +		if (val < 0 || val > 255) {
>> []
>>> +	if (of_property_read_u32(np, "average_data", &val) >= 0) {
>>> +		if (val < 0 || val > 8) {
>> []
>>> +	if (of_property_read_u32(np, "fifo_threshold", &val) >= 0) {
>>> +		if (val < 0 || val > 31) {
>>
>>
> 
> 
> _______________________________________________
> linux-arm-kernel mailing list
> linux-arm-kernel@lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
> 


-- 
Florian

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

* Re: [PATCH v2 1/2] Input: touchscreen-iproc: Add Broadcom iProc touchscreen driver
  2015-01-15  1:02     ` Dmitry Torokhov
@ 2015-01-15  5:44       ` Scott Branden
  2015-01-15  6:07         ` Dmitry Torokhov
  0 siblings, 1 reply; 92+ messages in thread
From: Scott Branden @ 2015-01-15  5:44 UTC (permalink / raw)
  To: Dmitry Torokhov, Jonathan Richardson
  Cc: Grant Likely, Rob Herring, Ray Jui, linux-kernel, linux-input,
	linux-arm-kernel, bcm-kernel-feedback-list, devicetree,
	Joe Perches

On 15-01-14 05:02 PM, Dmitry Torokhov wrote:
> Hi Jonathan,
>
> On Fri, Dec 19, 2014 at 02:17:49PM -0800, Jonathan Richardson wrote:
>> +	if (of_property_read_u32(np, "scanning_period", &val) >= 0) {
>> +		if (val < 1 || val > 256) {
>> +			dev_err(dev, "scanning_period must be [1-256]\n");
>> +			return -EINVAL;
>> +		}
>> +		priv->cfg_params.scanning_period = val;
>> +	}
>> +
>> +	if (of_property_read_u32(np, "debounce_timeout", &val) >= 0) {
>> +		if (val < 0 || val > 255) {
>> +			dev_err(dev, "debounce_timeout must be [0-255]\n");
>> +			return -EINVAL;
>> +		}
>> +		priv->cfg_params.debounce_timeout = val;
>> +	}
>> +
>> +	if (of_property_read_u32(np, "settling_timeout", &val) >= 0) {
>> +		if (val < 0 || val > 11) {
>> +			dev_err(dev, "settling_timeout must be [0-11]\n");
>> +			return -EINVAL;
>> +		}
>> +		priv->cfg_params.settling_timeout = val;
>> +	}
>> +
>> +	if (of_property_read_u32(np, "touch_timeout", &val) >= 0) {
>> +		if (val < 0 || val > 255) {
>> +			dev_err(dev, "touch_timeout must be [0-255]\n");
>> +			return -EINVAL;
>> +		}
>> +		priv->cfg_params.touch_timeout = val;
>> +	}
>> +
>> +	if (of_property_read_u32(np, "average_data", &val) >= 0) {
>> +		if (val < 0 || val > 8) {
>> +			dev_err(dev, "average_data must be [0-8]\n");
>> +			return -EINVAL;
>> +		}
>> +		priv->cfg_params.average_data = val;
>> +	}
>> +
>> +	if (of_property_read_u32(np, "fifo_threshold", &val) >= 0) {
>> +		if (val < 0 || val > 31) {
>> +			dev_err(dev, "fifo_threshold must be [0-31]\n");
>> +			return -EINVAL;
>> +		}
>> +		priv->cfg_params.fifo_threshold = val;
>> +	}
>
> I think these are dveice specific and thus should have "brcm," prefix.
I'm confused as to why we need the brcm prefix?  Other device tree 
bindings we have for other drivers do not need such prefix.  Is this 
convention documented somewhere?
>
>> +
>> +	priv->ts_rotation = TS_ROTATION_0;
>> +	if (of_property_read_u32(np, "ts-rotation", &val) >= 0) {
>> +		priv->ts_rotation = val;
>> +		dev_dbg(dev, "ts rotation [%d] degrees\n",
>> +			90 * priv->ts_rotation);
>> +	}
>
> This I am not quite sure about - if we want rotation or swap+invert. You
> are CCed on another email (tsc2007) that talks about need of generic
> touchscreen transforms in input core/of bindings.
Does such generic binding exist today?  If not, I would like to go with 
this implementation and update to the new binding if/when it exists?
>
> Thanks.
>


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

* Re: [PATCH v2 1/2] Input: touchscreen-iproc: Add Broadcom iProc touchscreen driver
  2015-01-15  5:44       ` Scott Branden
@ 2015-01-15  6:07         ` Dmitry Torokhov
  2015-01-15 19:51           ` Jonathan Richardson
  0 siblings, 1 reply; 92+ messages in thread
From: Dmitry Torokhov @ 2015-01-15  6:07 UTC (permalink / raw)
  To: Scott Branden
  Cc: Jonathan Richardson, Grant Likely, Rob Herring, Ray Jui,
	linux-kernel, linux-input, linux-arm-kernel,
	bcm-kernel-feedback-list, devicetree, Joe Perches

On Wed, Jan 14, 2015 at 09:44:39PM -0800, Scott Branden wrote:
> On 15-01-14 05:02 PM, Dmitry Torokhov wrote:
> >Hi Jonathan,
> >
> >On Fri, Dec 19, 2014 at 02:17:49PM -0800, Jonathan Richardson wrote:
> >>+	if (of_property_read_u32(np, "scanning_period", &val) >= 0) {
> >>+		if (val < 1 || val > 256) {
> >>+			dev_err(dev, "scanning_period must be [1-256]\n");
> >>+			return -EINVAL;
> >>+		}
> >>+		priv->cfg_params.scanning_period = val;
> >>+	}
> >>+
> >>+	if (of_property_read_u32(np, "debounce_timeout", &val) >= 0) {
> >>+		if (val < 0 || val > 255) {
> >>+			dev_err(dev, "debounce_timeout must be [0-255]\n");
> >>+			return -EINVAL;
> >>+		}
> >>+		priv->cfg_params.debounce_timeout = val;
> >>+	}
> >>+
> >>+	if (of_property_read_u32(np, "settling_timeout", &val) >= 0) {
> >>+		if (val < 0 || val > 11) {
> >>+			dev_err(dev, "settling_timeout must be [0-11]\n");
> >>+			return -EINVAL;
> >>+		}
> >>+		priv->cfg_params.settling_timeout = val;
> >>+	}
> >>+
> >>+	if (of_property_read_u32(np, "touch_timeout", &val) >= 0) {
> >>+		if (val < 0 || val > 255) {
> >>+			dev_err(dev, "touch_timeout must be [0-255]\n");
> >>+			return -EINVAL;
> >>+		}
> >>+		priv->cfg_params.touch_timeout = val;
> >>+	}
> >>+
> >>+	if (of_property_read_u32(np, "average_data", &val) >= 0) {
> >>+		if (val < 0 || val > 8) {
> >>+			dev_err(dev, "average_data must be [0-8]\n");
> >>+			return -EINVAL;
> >>+		}
> >>+		priv->cfg_params.average_data = val;
> >>+	}
> >>+
> >>+	if (of_property_read_u32(np, "fifo_threshold", &val) >= 0) {
> >>+		if (val < 0 || val > 31) {
> >>+			dev_err(dev, "fifo_threshold must be [0-31]\n");
> >>+			return -EINVAL;
> >>+		}
> >>+		priv->cfg_params.fifo_threshold = val;
> >>+	}
> >
> >I think these are dveice specific and thus should have "brcm," prefix.
> I'm confused as to why we need the brcm prefix?  Other device tree
> bindings we have for other drivers do not need such prefix.

Properties that are not standard on the system (reg, interrupts,
clkocks, etc) or subsystem level customarily carry the vendor prefix so
that they do not clash with newly added global or subsystem properties.

>  Is this
> convention documented somewhere?

Not sure. I glanced through Documentation/devicetree and do not see it
spelled out. Device tree overlords, what say you?

> >
> >>+
> >>+	priv->ts_rotation = TS_ROTATION_0;
> >>+	if (of_property_read_u32(np, "ts-rotation", &val) >= 0) {
> >>+		priv->ts_rotation = val;
> >>+		dev_dbg(dev, "ts rotation [%d] degrees\n",
> >>+			90 * priv->ts_rotation);
> >>+	}
> >
> >This I am not quite sure about - if we want rotation or swap+invert. You
> >are CCed on another email (tsc2007) that talks about need of generic
> >touchscreen transforms in input core/of bindings.
> Does such generic binding exist today?  If not, I would like to go
> with this implementation and update to the new binding if/when it
> exists?

Not yet but there several people interested. I think we have enough time
till 3.20 to hash it out properly.

Thanks.

-- 
Dmitry

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

* Re: [PATCH v2 1/2] Input: touchscreen-iproc: Add Broadcom iProc touchscreen driver
  2015-01-15  1:08         ` Florian Fainelli
@ 2015-01-15 19:19           ` Jonathan Richardson
  0 siblings, 0 replies; 92+ messages in thread
From: Jonathan Richardson @ 2015-01-15 19:19 UTC (permalink / raw)
  To: Florian Fainelli
  Cc: Joe Perches, devicetree, Ray Jui, Dmitry Torokhov, linux-kernel,
	Rob Herring, bcm-kernel-feedback-list, linux-input, Grant Likely,
	linux-arm-kernel

On 15-01-14 05:08 PM, Florian Fainelli wrote:
> On 19/12/14 15:03, Jonathan Richardson wrote:
>> On 14-12-19 02:26 PM, Joe Perches wrote:
>>> On Fri, 2014-12-19 at 14:17 -0800, Jonathan Richardson wrote:
>>>> Add initial version of the Broadcom touchscreen driver.
>>>
>>> more trivia:
>>>
>>>> diff --git a/drivers/input/touchscreen/bcm_iproc_tsc.c b/drivers/input/touchscreen/bcm_iproc_tsc.c
>>> []
>>>> +static int get_tsc_config(struct device_node *np, struct iproc_ts_priv *priv)
>>>> +{
>>>> +	u32 val;
>>> []
>>>> +	if (of_property_read_u32(np, "debounce_timeout", &val) >= 0) {
>>>> +		if (val < 0 || val > 255) {
>>>> +			dev_err(dev, "debounce_timeout must be [0-255]\n");
>>>> +			return -EINVAL;
>>>> +		}
>>>> +		priv->cfg_params.debounce_timeout = val;
> 
> BTW, common practice for DT properties is to use a dash instead of an
> underscore for multi-worded properties.

ts-rotation is done that way already so I'll change the others to be
consistent. Thanks.

> 
>>>
>>> Doesn't the compiler generate a warning message
>>> about an impossible "unsigned < 0" test for all
>>> of these "val < 0" uses?
>>>
>>
>> Actually no it doesn't. The gcc output shows that neither -Wtype-limits
>> nor -Wextra are used to compile that file. I assume this is because
>> there would be just too many warnings.
>>
>>
>>>> +	}
>>>> +
>>>> +	if (of_property_read_u32(np, "settling_timeout", &val) >= 0) {
>>>> +		if (val < 0 || val > 11) {
>>> []
>>>> +	if (of_property_read_u32(np, "touch_timeout", &val) >= 0) {
>>>> +		if (val < 0 || val > 255) {
>>> []
>>>> +	if (of_property_read_u32(np, "average_data", &val) >= 0) {
>>>> +		if (val < 0 || val > 8) {
>>> []
>>>> +	if (of_property_read_u32(np, "fifo_threshold", &val) >= 0) {
>>>> +		if (val < 0 || val > 31) {
>>>
>>>
>>
>>
>> _______________________________________________
>> linux-arm-kernel mailing list
>> linux-arm-kernel@lists.infradead.org
>> http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
>>
> 
> 


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

* Re: [PATCH v2 1/2] Input: touchscreen-iproc: Add Broadcom iProc touchscreen driver
  2015-01-15  6:07         ` Dmitry Torokhov
@ 2015-01-15 19:51           ` Jonathan Richardson
  2015-02-11 18:45             ` Jonathan Richardson
  0 siblings, 1 reply; 92+ messages in thread
From: Jonathan Richardson @ 2015-01-15 19:51 UTC (permalink / raw)
  To: Dmitry Torokhov
  Cc: Scott Branden, Grant Likely, Rob Herring, Ray Jui, linux-kernel,
	linux-input, linux-arm-kernel, bcm-kernel-feedback-list,
	devicetree, Joe Perches

Hi Dmitry,

On 15-01-14 10:07 PM, Dmitry Torokhov wrote:
> On Wed, Jan 14, 2015 at 09:44:39PM -0800, Scott Branden wrote:
>> On 15-01-14 05:02 PM, Dmitry Torokhov wrote:
>>> Hi Jonathan,
>>>
>>> On Fri, Dec 19, 2014 at 02:17:49PM -0800, Jonathan Richardson wrote:
>>>> +	if (of_property_read_u32(np, "scanning_period", &val) >= 0) {
>>>> +		if (val < 1 || val > 256) {
>>>> +			dev_err(dev, "scanning_period must be [1-256]\n");
>>>> +			return -EINVAL;
>>>> +		}
>>>> +		priv->cfg_params.scanning_period = val;
>>>> +	}
>>>> +
>>>> +	if (of_property_read_u32(np, "debounce_timeout", &val) >= 0) {
>>>> +		if (val < 0 || val > 255) {
>>>> +			dev_err(dev, "debounce_timeout must be [0-255]\n");
>>>> +			return -EINVAL;
>>>> +		}
>>>> +		priv->cfg_params.debounce_timeout = val;
>>>> +	}
>>>> +
>>>> +	if (of_property_read_u32(np, "settling_timeout", &val) >= 0) {
>>>> +		if (val < 0 || val > 11) {
>>>> +			dev_err(dev, "settling_timeout must be [0-11]\n");
>>>> +			return -EINVAL;
>>>> +		}
>>>> +		priv->cfg_params.settling_timeout = val;
>>>> +	}
>>>> +
>>>> +	if (of_property_read_u32(np, "touch_timeout", &val) >= 0) {
>>>> +		if (val < 0 || val > 255) {
>>>> +			dev_err(dev, "touch_timeout must be [0-255]\n");
>>>> +			return -EINVAL;
>>>> +		}
>>>> +		priv->cfg_params.touch_timeout = val;
>>>> +	}
>>>> +
>>>> +	if (of_property_read_u32(np, "average_data", &val) >= 0) {
>>>> +		if (val < 0 || val > 8) {
>>>> +			dev_err(dev, "average_data must be [0-8]\n");
>>>> +			return -EINVAL;
>>>> +		}
>>>> +		priv->cfg_params.average_data = val;
>>>> +	}
>>>> +
>>>> +	if (of_property_read_u32(np, "fifo_threshold", &val) >= 0) {
>>>> +		if (val < 0 || val > 31) {
>>>> +			dev_err(dev, "fifo_threshold must be [0-31]\n");
>>>> +			return -EINVAL;
>>>> +		}
>>>> +		priv->cfg_params.fifo_threshold = val;
>>>> +	}
>>>
>>> I think these are dveice specific and thus should have "brcm," prefix.
>> I'm confused as to why we need the brcm prefix?  Other device tree
>> bindings we have for other drivers do not need such prefix.
> 
> Properties that are not standard on the system (reg, interrupts,
> clkocks, etc) or subsystem level customarily carry the vendor prefix so
> that they do not clash with newly added global or subsystem properties.
> 
>>  Is this
>> convention documented somewhere?
> 
> Not sure. I glanced through Documentation/devicetree and do not see it
> spelled out. Device tree overlords, what say you?

Let me know. I haven't seen this before either. I will change the
entries to use dashes though instead of underscores but will wait until
these other issues are decided on before sending out another patch.

> 
>>>
>>>> +
>>>> +	priv->ts_rotation = TS_ROTATION_0;
>>>> +	if (of_property_read_u32(np, "ts-rotation", &val) >= 0) {
>>>> +		priv->ts_rotation = val;
>>>> +		dev_dbg(dev, "ts rotation [%d] degrees\n",
>>>> +			90 * priv->ts_rotation);
>>>> +	}
>>>
>>> This I am not quite sure about - if we want rotation or swap+invert. You
>>> are CCed on another email (tsc2007) that talks about need of generic
>>> touchscreen transforms in input core/of bindings.
>> Does such generic binding exist today?  If not, I would like to go
>> with this implementation and update to the new binding if/when it
>> exists?
> 
> Not yet but there several people interested. I think we have enough time
> till 3.20 to hash it out properly.

I think the rotation is simpler personally. Everyone would understand
rotation refers to how it's oriented but I'm not sure everyone would
immediately know how it is wired. Let me know what is decided and I'll
make any changes required.

Thanks,
Jon


> 
> Thanks.
> 


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

* Re: [PATCH v2 1/2] Input: touchscreen-iproc: Add Broadcom iProc touchscreen driver
  2015-01-15 19:51           ` Jonathan Richardson
@ 2015-02-11 18:45             ` Jonathan Richardson
  2015-02-24 23:18               ` Dmitry Torokhov
  0 siblings, 1 reply; 92+ messages in thread
From: Jonathan Richardson @ 2015-02-11 18:45 UTC (permalink / raw)
  To: Dmitry Torokhov
  Cc: Scott Branden, Grant Likely, Rob Herring, Ray Jui, linux-kernel,
	linux-input, linux-arm-kernel, bcm-kernel-feedback-list,
	devicetree, Joe Perches

Pinging maintainers... Am I ok to go ahead with the current rotation
implementation? I haven't heard anything further. Any feedback on naming
conventions from DT people?

Thanks!

On 15-01-15 11:51 AM, Jonathan Richardson wrote:
> Hi Dmitry,
> 
> On 15-01-14 10:07 PM, Dmitry Torokhov wrote:
>> On Wed, Jan 14, 2015 at 09:44:39PM -0800, Scott Branden wrote:
>>> On 15-01-14 05:02 PM, Dmitry Torokhov wrote:
>>>> Hi Jonathan,
>>>>
>>>> On Fri, Dec 19, 2014 at 02:17:49PM -0800, Jonathan Richardson wrote:
>>>>> +	if (of_property_read_u32(np, "scanning_period", &val) >= 0) {
>>>>> +		if (val < 1 || val > 256) {
>>>>> +			dev_err(dev, "scanning_period must be [1-256]\n");
>>>>> +			return -EINVAL;
>>>>> +		}
>>>>> +		priv->cfg_params.scanning_period = val;
>>>>> +	}
>>>>> +
>>>>> +	if (of_property_read_u32(np, "debounce_timeout", &val) >= 0) {
>>>>> +		if (val < 0 || val > 255) {
>>>>> +			dev_err(dev, "debounce_timeout must be [0-255]\n");
>>>>> +			return -EINVAL;
>>>>> +		}
>>>>> +		priv->cfg_params.debounce_timeout = val;
>>>>> +	}
>>>>> +
>>>>> +	if (of_property_read_u32(np, "settling_timeout", &val) >= 0) {
>>>>> +		if (val < 0 || val > 11) {
>>>>> +			dev_err(dev, "settling_timeout must be [0-11]\n");
>>>>> +			return -EINVAL;
>>>>> +		}
>>>>> +		priv->cfg_params.settling_timeout = val;
>>>>> +	}
>>>>> +
>>>>> +	if (of_property_read_u32(np, "touch_timeout", &val) >= 0) {
>>>>> +		if (val < 0 || val > 255) {
>>>>> +			dev_err(dev, "touch_timeout must be [0-255]\n");
>>>>> +			return -EINVAL;
>>>>> +		}
>>>>> +		priv->cfg_params.touch_timeout = val;
>>>>> +	}
>>>>> +
>>>>> +	if (of_property_read_u32(np, "average_data", &val) >= 0) {
>>>>> +		if (val < 0 || val > 8) {
>>>>> +			dev_err(dev, "average_data must be [0-8]\n");
>>>>> +			return -EINVAL;
>>>>> +		}
>>>>> +		priv->cfg_params.average_data = val;
>>>>> +	}
>>>>> +
>>>>> +	if (of_property_read_u32(np, "fifo_threshold", &val) >= 0) {
>>>>> +		if (val < 0 || val > 31) {
>>>>> +			dev_err(dev, "fifo_threshold must be [0-31]\n");
>>>>> +			return -EINVAL;
>>>>> +		}
>>>>> +		priv->cfg_params.fifo_threshold = val;
>>>>> +	}
>>>>
>>>> I think these are dveice specific and thus should have "brcm," prefix.
>>> I'm confused as to why we need the brcm prefix?  Other device tree
>>> bindings we have for other drivers do not need such prefix.
>>
>> Properties that are not standard on the system (reg, interrupts,
>> clkocks, etc) or subsystem level customarily carry the vendor prefix so
>> that they do not clash with newly added global or subsystem properties.
>>
>>>  Is this
>>> convention documented somewhere?
>>
>> Not sure. I glanced through Documentation/devicetree and do not see it
>> spelled out. Device tree overlords, what say you?
> 
> Let me know. I haven't seen this before either. I will change the
> entries to use dashes though instead of underscores but will wait until
> these other issues are decided on before sending out another patch.
> 
>>
>>>>
>>>>> +
>>>>> +	priv->ts_rotation = TS_ROTATION_0;
>>>>> +	if (of_property_read_u32(np, "ts-rotation", &val) >= 0) {
>>>>> +		priv->ts_rotation = val;
>>>>> +		dev_dbg(dev, "ts rotation [%d] degrees\n",
>>>>> +			90 * priv->ts_rotation);
>>>>> +	}
>>>>
>>>> This I am not quite sure about - if we want rotation or swap+invert. You
>>>> are CCed on another email (tsc2007) that talks about need of generic
>>>> touchscreen transforms in input core/of bindings.
>>> Does such generic binding exist today?  If not, I would like to go
>>> with this implementation and update to the new binding if/when it
>>> exists?
>>
>> Not yet but there several people interested. I think we have enough time
>> till 3.20 to hash it out properly.
> 
> I think the rotation is simpler personally. Everyone would understand
> rotation refers to how it's oriented but I'm not sure everyone would
> immediately know how it is wired. Let me know what is decided and I'll
> make any changes required.
> 
> Thanks,
> Jon
> 
> 
>>
>> Thanks.
>>
> 


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

* Re: [PATCH v5 2/2] pwm: core: Set enable state properly on failed call to enable
  2015-01-07 19:42   ` [PATCH v5 2/2] pwm: core: Set enable state properly on failed call to enable Jonathan Richardson
@ 2015-02-11 23:59     ` Dmitry Torokhov
  0 siblings, 0 replies; 92+ messages in thread
From: Dmitry Torokhov @ 2015-02-11 23:59 UTC (permalink / raw)
  To: Jonathan Richardson
  Cc: Tim Kryger, Scott Branden, Arun Ramamurthy, Thierry Reding,
	Ray Jui, bcm-kernel-feedback-list, linux-kernel, linux-pwm

On Wed, Jan 07, 2015 at 11:42:51AM -0800, Jonathan Richardson wrote:
> The pwm_enable function didn't clear the enabled bit if a call to a
> clients enable function returned an error. The result was that the state
> of the pwm core was wrong. Clearing the bit when enable returns an error
> ensures the state is properly set.
> 
> Tested-by: Jonathan Richardson <jonathar@broadcom.com>
> Signed-off-by: Jonathan Richardson <jonathar@broadcom.com>
> ---
>  drivers/pwm/core.c |   10 ++++++++--
>  1 file changed, 8 insertions(+), 2 deletions(-)
> 
> diff --git a/drivers/pwm/core.c b/drivers/pwm/core.c
> index f28c4ce..c33e24f 100644
> --- a/drivers/pwm/core.c
> +++ b/drivers/pwm/core.c
> @@ -477,8 +477,14 @@ EXPORT_SYMBOL_GPL(pwm_set_polarity);
>   */
>  int pwm_enable(struct pwm_device *pwm)
>  {
> -	if (pwm && !test_and_set_bit(PWMF_ENABLED, &pwm->flags))
> -		return pwm->chip->ops->enable(pwm->chip, pwm);
> +	int err;
> +
> +	if (pwm && !test_and_set_bit(PWMF_ENABLED, &pwm->flags)) {
> +		err = pwm->chip->ops->enable(pwm->chip, pwm);
> +		if (err)
> +			clear_bit(PWMF_ENABLED, &pwm->flags);
> +		return err;
> +	}
>  
>  	return pwm ? 0 : -EINVAL;

Seems fine in principle, but somewhat messy. Can we do the following:

int pwm_enable(struct pwm_device *pwm)
{
	int err;

	if (!pwm)
		return -EINVAL;

	if (!test_and_set_bit(PWMF_ENABLED, &pwm->flags)) {
		err = pwm->chip->ops->enable(pwm->chip, pwm);
		if (err) {
			clear_bit(PWMF_ENABLED, &pwm->flags);
			return err;
		}
	}

	return 0;
}

Otherwise:

Reviewed-by: Dmitry Torokhov <dmitry.torokhov@gmail.com>

Thanks.

-- 
Dmitry

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

* [PATCH 0/1] Enable Broadcom Cygnus BCM958305K
       [not found] <Jonathan Richardson <jonathar@broadcom.com>
                   ` (7 preceding siblings ...)
  2015-01-07 19:42 ` [PATCH v5 0/2] Fix bugs in kona pwm driver and pwm core Jonathan Richardson
@ 2015-02-24 19:13 ` Jonathan Richardson
  2015-02-24 19:13   ` [PATCH 1/1] ARM: dts: " Jonathan Richardson
  2015-02-25 19:04 ` [PATCH 0/1] Synopsis 8250 serial port driver fix Jonathan Richardson
                   ` (4 subsequent siblings)
  13 siblings, 1 reply; 92+ messages in thread
From: Jonathan Richardson @ 2015-02-24 19:13 UTC (permalink / raw)
  To: Dmitry Torokhov, Jonathan Richardson, Scott Branden, Ray Jui,
	Rob Herring, Pawel Moll, Mark Rutland, Ian Campbell, Kumar Gala,
	Russell King
  Cc: devicetree, linux-arm-kernel, linux-kernel, bcm-kernel-feedback-list

This patchset adds a DTS file to enable the BCM58305 Wireless Audio reference
design based on Cygnus. It will be kept up to date as Cygnus drivers are
accepted into the mainline.

Jonathan Richardson (1):
  ARM: dts: Enable Broadcom Cygnus BCM958305K

 arch/arm/boot/dts/Makefile       |    3 ++-
 arch/arm/boot/dts/bcm958305k.dts |   53 ++++++++++++++++++++++++++++++++++++++
 2 files changed, 55 insertions(+), 1 deletion(-)
 create mode 100644 arch/arm/boot/dts/bcm958305k.dts

-- 
1.7.9.5


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

* [PATCH 1/1] ARM: dts: Enable Broadcom Cygnus BCM958305K
  2015-02-24 19:13 ` [PATCH 0/1] Enable Broadcom Cygnus BCM958305K Jonathan Richardson
@ 2015-02-24 19:13   ` Jonathan Richardson
  0 siblings, 0 replies; 92+ messages in thread
From: Jonathan Richardson @ 2015-02-24 19:13 UTC (permalink / raw)
  To: Dmitry Torokhov, Jonathan Richardson, Scott Branden, Ray Jui,
	Rob Herring, Pawel Moll, Mark Rutland, Ian Campbell, Kumar Gala,
	Russell King
  Cc: devicetree, linux-arm-kernel, linux-kernel, bcm-kernel-feedback-list

DT file to enable the Wireless Audio reference design based on the
BCM58305.

Reviewed-by: Ray Jui <rjui@broadcom.com>
Reviewed-by: Scott Branden <sbranden@broadcom.com>
Tested-by: Scott Branden <sbranden@broadcom.com>
Signed-off-by: Jonathan Richardson <jonathar@broadcom.com>
---
 arch/arm/boot/dts/Makefile       |    3 ++-
 arch/arm/boot/dts/bcm958305k.dts |   53 ++++++++++++++++++++++++++++++++++++++
 2 files changed, 55 insertions(+), 1 deletion(-)
 create mode 100644 arch/arm/boot/dts/bcm958305k.dts

diff --git a/arch/arm/boot/dts/Makefile b/arch/arm/boot/dts/Makefile
index 91bd5bd..24b6084 100644
--- a/arch/arm/boot/dts/Makefile
+++ b/arch/arm/boot/dts/Makefile
@@ -64,7 +64,8 @@ dtb-$(CONFIG_ARCH_BCM_5301X) += \
 dtb-$(CONFIG_ARCH_BCM_63XX) += bcm963138dvt.dtb
 dtb-$(CONFIG_ARCH_BCM_CYGNUS) += bcm911360_entphn.dtb \
 	bcm911360k.dtb \
-	bcm958300k.dtb
+	bcm958300k.dtb \
+	bcm958305k.dtb
 dtb-$(CONFIG_ARCH_BCM_MOBILE) += bcm28155-ap.dtb \
 	bcm21664-garnet.dtb
 dtb-$(CONFIG_ARCH_BERLIN) += \
diff --git a/arch/arm/boot/dts/bcm958305k.dts b/arch/arm/boot/dts/bcm958305k.dts
new file mode 100644
index 0000000..56b429a
--- /dev/null
+++ b/arch/arm/boot/dts/bcm958305k.dts
@@ -0,0 +1,53 @@
+/*
+ *  BSD LICENSE
+ *
+ *  Copyright(c) 2015 Broadcom Corporation.  All rights reserved.
+ *
+ *  Redistribution and use in source and binary forms, with or without
+ *  modification, are permitted provided that the following conditions
+ *  are met:
+ *
+ *    * Redistributions of source code must retain the above copyright
+ *      notice, this list of conditions and the following disclaimer.
+ *    * Redistributions in binary form must reproduce the above copyright
+ *      notice, this list of conditions and the following disclaimer in
+ *      the documentation and/or other materials provided with the
+ *      distribution.
+ *    * Neither the name of Broadcom Corporation nor the names of its
+ *      contributors may be used to endorse or promote products derived
+ *      from this software without specific prior written permission.
+ *
+ *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ *  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ *  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ *  A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ *  OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ *  SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ *  LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ *  DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ *  THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ *  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/dts-v1/;
+
+#include "bcm-cygnus.dtsi"
+
+/ {
+	model = "Cygnus Wireless Audio (BCM958305K)";
+	compatible = "brcm,bcm58305", "brcm,cygnus";
+
+	aliases {
+		serial0 = &uart3;
+	};
+
+	chosen {
+		stdout-path = &uart3;
+		bootargs = "console=ttyS0,115200";
+	};
+
+	uart3: serial@18023000 {
+		status = "okay";
+	};
+};
-- 
1.7.9.5


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

* Re: [PATCH v2 1/2] Input: touchscreen-iproc: Add Broadcom iProc touchscreen driver
  2015-02-11 18:45             ` Jonathan Richardson
@ 2015-02-24 23:18               ` Dmitry Torokhov
  2015-02-27  1:02                 ` Jonathan Richardson
  0 siblings, 1 reply; 92+ messages in thread
From: Dmitry Torokhov @ 2015-02-24 23:18 UTC (permalink / raw)
  To: Jonathan Richardson
  Cc: Scott Branden, Grant Likely, Rob Herring, Ray Jui, linux-kernel,
	linux-input, linux-arm-kernel, bcm-kernel-feedback-list,
	devicetree, Joe Perches, Hans de Goede

Jonathan,


On Wed, Feb 11, 2015 at 10:45:34AM -0800, Jonathan Richardson wrote:
> Pinging maintainers... Am I ok to go ahead with the current rotation
> implementation? I haven't heard anything further. Any feedback on naming
> conventions from DT people?
>

I believe we should go with touchscreen-inverted-x,
touchscreen-inverted-y and touchscreen-swapped-x-y properties since
rotation can't really describe all permutations of potential
connections.

I'll be taking Hans de Goede's patch adding this new property to the
bindings (adjusting the name slightly).

Thanks.

> Thanks!
> 
> On 15-01-15 11:51 AM, Jonathan Richardson wrote:
> > Hi Dmitry,
> > 
> > On 15-01-14 10:07 PM, Dmitry Torokhov wrote:
> >> On Wed, Jan 14, 2015 at 09:44:39PM -0800, Scott Branden wrote:
> >>> On 15-01-14 05:02 PM, Dmitry Torokhov wrote:
> >>>> Hi Jonathan,
> >>>>
> >>>> On Fri, Dec 19, 2014 at 02:17:49PM -0800, Jonathan Richardson wrote:
> >>>>> +	if (of_property_read_u32(np, "scanning_period", &val) >= 0) {
> >>>>> +		if (val < 1 || val > 256) {
> >>>>> +			dev_err(dev, "scanning_period must be [1-256]\n");
> >>>>> +			return -EINVAL;
> >>>>> +		}
> >>>>> +		priv->cfg_params.scanning_period = val;
> >>>>> +	}
> >>>>> +
> >>>>> +	if (of_property_read_u32(np, "debounce_timeout", &val) >= 0) {
> >>>>> +		if (val < 0 || val > 255) {
> >>>>> +			dev_err(dev, "debounce_timeout must be [0-255]\n");
> >>>>> +			return -EINVAL;
> >>>>> +		}
> >>>>> +		priv->cfg_params.debounce_timeout = val;
> >>>>> +	}
> >>>>> +
> >>>>> +	if (of_property_read_u32(np, "settling_timeout", &val) >= 0) {
> >>>>> +		if (val < 0 || val > 11) {
> >>>>> +			dev_err(dev, "settling_timeout must be [0-11]\n");
> >>>>> +			return -EINVAL;
> >>>>> +		}
> >>>>> +		priv->cfg_params.settling_timeout = val;
> >>>>> +	}
> >>>>> +
> >>>>> +	if (of_property_read_u32(np, "touch_timeout", &val) >= 0) {
> >>>>> +		if (val < 0 || val > 255) {
> >>>>> +			dev_err(dev, "touch_timeout must be [0-255]\n");
> >>>>> +			return -EINVAL;
> >>>>> +		}
> >>>>> +		priv->cfg_params.touch_timeout = val;
> >>>>> +	}
> >>>>> +
> >>>>> +	if (of_property_read_u32(np, "average_data", &val) >= 0) {
> >>>>> +		if (val < 0 || val > 8) {
> >>>>> +			dev_err(dev, "average_data must be [0-8]\n");
> >>>>> +			return -EINVAL;
> >>>>> +		}
> >>>>> +		priv->cfg_params.average_data = val;
> >>>>> +	}
> >>>>> +
> >>>>> +	if (of_property_read_u32(np, "fifo_threshold", &val) >= 0) {
> >>>>> +		if (val < 0 || val > 31) {
> >>>>> +			dev_err(dev, "fifo_threshold must be [0-31]\n");
> >>>>> +			return -EINVAL;
> >>>>> +		}
> >>>>> +		priv->cfg_params.fifo_threshold = val;
> >>>>> +	}
> >>>>
> >>>> I think these are dveice specific and thus should have "brcm," prefix.
> >>> I'm confused as to why we need the brcm prefix?  Other device tree
> >>> bindings we have for other drivers do not need such prefix.
> >>
> >> Properties that are not standard on the system (reg, interrupts,
> >> clkocks, etc) or subsystem level customarily carry the vendor prefix so
> >> that they do not clash with newly added global or subsystem properties.
> >>
> >>>  Is this
> >>> convention documented somewhere?
> >>
> >> Not sure. I glanced through Documentation/devicetree and do not see it
> >> spelled out. Device tree overlords, what say you?
> > 
> > Let me know. I haven't seen this before either. I will change the
> > entries to use dashes though instead of underscores but will wait until
> > these other issues are decided on before sending out another patch.
> > 
> >>
> >>>>
> >>>>> +
> >>>>> +	priv->ts_rotation = TS_ROTATION_0;
> >>>>> +	if (of_property_read_u32(np, "ts-rotation", &val) >= 0) {
> >>>>> +		priv->ts_rotation = val;
> >>>>> +		dev_dbg(dev, "ts rotation [%d] degrees\n",
> >>>>> +			90 * priv->ts_rotation);
> >>>>> +	}
> >>>>
> >>>> This I am not quite sure about - if we want rotation or swap+invert. You
> >>>> are CCed on another email (tsc2007) that talks about need of generic
> >>>> touchscreen transforms in input core/of bindings.
> >>> Does such generic binding exist today?  If not, I would like to go
> >>> with this implementation and update to the new binding if/when it
> >>> exists?
> >>
> >> Not yet but there several people interested. I think we have enough time
> >> till 3.20 to hash it out properly.
> > 
> > I think the rotation is simpler personally. Everyone would understand
> > rotation refers to how it's oriented but I'm not sure everyone would
> > immediately know how it is wired. Let me know what is decided and I'll
> > make any changes required.
> > 
> > Thanks,
> > Jon
> > 
> > 
> >>
> >> Thanks.
> >>
> > 
> 

-- 
Dmitry

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

* Re: [PATCH v2 1/2] Input: touchscreen-iproc: Add Broadcom iProc touchscreen driver
  2014-12-19 22:17   ` [PATCH v2 1/2] Input: touchscreen-iproc: Add Broadcom iProc touchscreen driver Jonathan Richardson
  2014-12-19 22:26     ` Joe Perches
  2015-01-15  1:02     ` Dmitry Torokhov
@ 2015-02-24 23:29     ` Dmitry Torokhov
  2015-03-02 19:13       ` Jonathan Richardson
  2 siblings, 1 reply; 92+ messages in thread
From: Dmitry Torokhov @ 2015-02-24 23:29 UTC (permalink / raw)
  To: Jonathan Richardson
  Cc: Grant Likely, Rob Herring, Ray Jui, linux-kernel, linux-input,
	linux-arm-kernel, bcm-kernel-feedback-list, devicetree,
	Joe Perches

Hi Jonathan,

On Fri, Dec 19, 2014 at 02:17:49PM -0800, Jonathan Richardson wrote:
> Add initial version of the Broadcom touchscreen driver.
> 
> Reviewed-by: Ray Jui <rjui@broadcom.com>
> Reviewed-by: Scott Branden <sbranden@broadcom.com>
> Tested-by: Scott Branden <sbranden@broadcom.com>
> Signed-off-by: Jonathan Richardson <jonathar@broadcom.com>
> ---
>  drivers/input/touchscreen/Kconfig         |   11 +
>  drivers/input/touchscreen/Makefile        |    1 +
>  drivers/input/touchscreen/bcm_iproc_tsc.c |  535 +++++++++++++++++++++++++++++
>  3 files changed, 547 insertions(+)
>  create mode 100644 drivers/input/touchscreen/bcm_iproc_tsc.c
> 
> diff --git a/drivers/input/touchscreen/Kconfig b/drivers/input/touchscreen/Kconfig
> index e1d8003..77ff531 100644
> --- a/drivers/input/touchscreen/Kconfig
> +++ b/drivers/input/touchscreen/Kconfig
> @@ -310,6 +310,17 @@ config TOUCHSCREEN_ILI210X
>  	  To compile this driver as a module, choose M here: the
>  	  module will be called ili210x.
>  
> +config TOUCHSCREEN_IPROC
> +	tristate "IPROC touch panel driver support"
> +	help
> +	  Say Y here if you want to add support for the IPROC touch
> +	  controller to your system.
> +
> +	  If unsure, say N.
> +
> +	  To compile this driver as a module, choose M here: the
> +	  module will be called iproc-ts.
> +
>  config TOUCHSCREEN_S3C2410
>  	tristate "Samsung S3C2410/generic touchscreen input driver"
>  	depends on ARCH_S3C24XX || SAMSUNG_DEV_TS
> diff --git a/drivers/input/touchscreen/Makefile b/drivers/input/touchscreen/Makefile
> index 090e61c..f7e6de9 100644
> --- a/drivers/input/touchscreen/Makefile
> +++ b/drivers/input/touchscreen/Makefile
> @@ -37,6 +37,7 @@ obj-$(CONFIG_TOUCHSCREEN_FUJITSU)	+= fujitsu_ts.o
>  obj-$(CONFIG_TOUCHSCREEN_ILI210X)	+= ili210x.o
>  obj-$(CONFIG_TOUCHSCREEN_INEXIO)	+= inexio.o
>  obj-$(CONFIG_TOUCHSCREEN_INTEL_MID)	+= intel-mid-touch.o
> +obj-$(CONFIG_TOUCHSCREEN_IPROC)		+= bcm_iproc_tsc.o
>  obj-$(CONFIG_TOUCHSCREEN_LPC32XX)	+= lpc32xx_ts.o
>  obj-$(CONFIG_TOUCHSCREEN_MAX11801)	+= max11801_ts.o
>  obj-$(CONFIG_TOUCHSCREEN_MC13783)	+= mc13783_ts.o
> diff --git a/drivers/input/touchscreen/bcm_iproc_tsc.c b/drivers/input/touchscreen/bcm_iproc_tsc.c
> new file mode 100644
> index 0000000..bf6eb7f
> --- /dev/null
> +++ b/drivers/input/touchscreen/bcm_iproc_tsc.c
> @@ -0,0 +1,535 @@
> +/*
> +* Copyright (C) 2014 Broadcom Corporation
> +*
> +* This program is free software; you can redistribute it and/or
> +* modify it under the terms of the GNU General Public License as
> +* published by the Free Software Foundation version 2.
> +*
> +* This program is distributed "as is" WITHOUT ANY WARRANTY of any
> +* kind, whether express or implied; without even the implied warranty
> +* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
> +* GNU General Public License for more details.
> +*/
> +#include <linux/module.h>
> +#include <linux/init.h>
> +#include <linux/input.h>
> +#include <linux/delay.h>
> +#include <linux/interrupt.h>
> +#include <linux/keyboard.h>
> +#include <linux/platform_device.h>
> +#include <linux/slab.h>
> +#include <linux/of.h>
> +#include <asm/irq.h>
> +#include <linux/io.h>
> +#include <linux/clk.h>
> +#include <linux/serio.h>
> +
> +#define IPROC_TS_NAME "iproc-ts"
> +
> +#define PEN_DOWN_STATUS     1
> +#define PEN_UP_STATUS       0
> +
> +#define X_MIN               0
> +#define Y_MIN               0
> +#define X_MAX               0xFFF
> +#define Y_MAX               0xFFF
> +
> +/* Value given by controller for invalid coordinate. */
> +#define INVALID_COORD       0xFFFFFFFF
> +
> +/* Register offsets */
> +#define REGCTL1             0x00
> +#define REGCTL2             0x04
> +#define INTERRUPT_THRES     0x08
> +#define INTERRUPT_MASK      0x0c
> +
> +#define INTERRUPT_STATUS    0x10
> +#define CONTROLLER_STATUS   0x14
> +#define FIFO_DATA           0x18
> +#define FIFO_DATA_X_Y_MASK  0xFFFF
> +#define ANALOG_CONTROL      0x1c
> +
> +#define AUX_DATA            0x20
> +#define DEBOUNCE_CNTR_STAT  0x24
> +#define SCAN_CNTR_STAT      0x28
> +#define REM_CNTR_STAT       0x2c
> +
> +#define SETTLING_TIMER_STAT 0x30
> +#define SPARE_REG           0x34
> +#define SOFT_BYPASS_CONTROL 0x38
> +#define SOFT_BYPASS_DATA    0x3c
> +
> +
> +/* Bit values for INTERRUPT_MASK and INTERRUPT_STATUS regs */
> +#define TS_PEN_INTR_MASK        BIT(0)
> +#define TS_FIFO_INTR_MASK       BIT(2)
> +
> +/* Bit values for CONTROLLER_STATUS reg1 */
> +#define TS_PEN_DOWN             BIT(0)
> +
> +/* Shift values for control reg1 */
> +#define SCANNING_PERIOD_SHIFT   24
> +#define DEBOUNCE_TIMEOUT_SHIFT  16
> +#define SETTLING_TIMEOUT_SHIFT  8
> +#define TOUCH_TIMEOUT_SHIFT     0
> +
> +/* Shift values for coordinates from fifo */
> +#define X_COORD_SHIFT  0
> +#define Y_COORD_SHIFT  16
> +
> +/* Bit values for REGCTL2 */
> +#define TS_CONTROLLER_EN_BIT    BIT(16)
> +#define TS_CONTROLLER_AVGDATA_SHIFT 8
> +#define TS_CONTROLLER_AVGDATA_MASK (0x7 << TS_CONTROLLER_AVGDATA_SHIFT)
> +#define TS_CONTROLLER_PWR_LDO   BIT(5)
> +#define TS_CONTROLLER_PWR_ADC   BIT(4)
> +#define TS_CONTROLLER_PWR_BGP   BIT(3)
> +#define TS_CONTROLLER_PWR_TS    BIT(2)
> +#define TS_WIRE_MODE_BIT        BIT(1)
> +
> +/*
> + * Touch screen mount angles w.r.t LCD panel left side top corner
> + * TS (x_min,y_min) placed at LCD (x_min,y_min) rotation angle is 0
> + * TS (x_min,y_max) placed at LCD (x_min,y_min) rotation angle is 90
> + * TS (x_max,y_max) placed at LCD (x_min,y_min) rotation angle is 180
> + * TS (x_max,y_min) placed at LCD (x_min,y_min) rotation angle is 270
> + */
> +enum ts_rotation_angles {
> +	TS_ROTATION_0,
> +	TS_ROTATION_90,
> +	TS_ROTATION_180,
> +	TS_ROTATION_270,
> +};
> +
> +struct tsc_param {
> +	/* Each step is 1024 us.  Valid 1-256 */
> +	u32 scanning_period;
> +
> +	/*  Each step is 512 us.  Valid 0-255 */
> +	u32 debounce_timeout;
> +
> +	/*
> +	 * The settling duration (in ms) is the amount of time the tsc
> +	 * waits to allow the voltage to settle after turning on the
> +	 * drivers in detection mode. Valid values: 0-11
> +	 *   0 =  0.008 ms
> +	 *   1 =  0.01 ms
> +	 *   2 =  0.02 ms
> +	 *   3 =  0.04 ms
> +	 *   4 =  0.08 ms
> +	 *   5 =  0.16 ms
> +	 *   6 =  0.32 ms
> +	 *   7 =  0.64 ms
> +	 *   8 =  1.28 ms
> +	 *   9 =  2.56 ms
> +	 *   10 = 5.12 ms
> +	 *   11 = 10.24 ms
> +	 */
> +	u32 settling_timeout;
> +
> +	/* touch timeout in sample counts */
> +	u32 touch_timeout;
> +
> +	/*
> +	 * Number of data samples which are averaged before a final data point
> +	 * is placed into the FIFO
> +	 */
> +	u32 average_data;
> +
> +	/* FIFO threshold */
> +	u32 fifo_threshold;
> +};
> +
> +struct iproc_ts_priv {
> +	struct platform_device *pdev;
> +	struct input_dev *idev;
> +
> +	void __iomem *regs;
> +	struct clk *tsc_clk;
> +
> +	int  pen_status;
> +	int  ts_rotation;
> +	struct tsc_param cfg_params;
> +};
> +
> +/*
> + * Set default values the same as hardware reset values
> + * except for fifo_threshold with is set to 1.
> + */
> +static struct tsc_param default_config = {
> +	.scanning_period  = 0x5,  /* 1 to 256 */
> +	.debounce_timeout = 0x28, /* 0 to 255 */
> +	.settling_timeout = 0x7,  /* 0 to 11 */
> +	.touch_timeout    = 0xa,  /* 0 to 255 */
> +	.average_data     = 5,    /* entry 5 = 32 pts */
> +	.fifo_threshold   = 1,    /* 0 to 31 */
> +};
> +
> +static void ts_reg_dump(struct iproc_ts_priv *priv)
> +{
> +	struct device *dev = &priv->pdev->dev;
> +
> +	dev_dbg(dev, "regCtl1             = 0x%08x\n",
> +				readl(priv->regs + REGCTL1));
> +	dev_dbg(dev, "regCtl2             = 0x%08x\n",
> +				readl(priv->regs + REGCTL2));
> +	dev_dbg(dev, "interrupt_Thres     = 0x%08x\n",
> +				readl(priv->regs + INTERRUPT_THRES));
> +	dev_dbg(dev, "interrupt_Mask      = 0x%08x\n",
> +				readl(priv->regs + INTERRUPT_MASK));
> +	dev_dbg(dev, "interrupt_Status    = 0x%08x\n",
> +				readl(priv->regs + INTERRUPT_STATUS));
> +	dev_dbg(dev, "controller_Status   = 0x%08x\n",
> +				readl(priv->regs + CONTROLLER_STATUS));
> +	dev_dbg(dev, "FIFO_Data           = 0x%08x\n",
> +				readl(priv->regs + FIFO_DATA));
> +	dev_dbg(dev, "analog_Control      = 0x%08x\n",
> +				readl(priv->regs + ANALOG_CONTROL));
> +	dev_dbg(dev, "aux_Data            = 0x%08x\n",
> +				readl(priv->regs + AUX_DATA));
> +	dev_dbg(dev, "debounce_Cntr_Stat  = 0x%08x\n",
> +				readl(priv->regs + DEBOUNCE_CNTR_STAT));
> +	dev_dbg(dev, "scan_Cntr_Stat      = 0x%08x\n",
> +				readl(priv->regs + SCAN_CNTR_STAT));
> +	dev_dbg(dev, "rem_Cntr_Stat       = 0x%08x\n",
> +				readl(priv->regs + REM_CNTR_STAT));
> +	dev_dbg(dev, "settling_Timer_Stat = 0x%08x\n",
> +				readl(priv->regs + SETTLING_TIMER_STAT));
> +	dev_dbg(dev, "spare_Reg           = 0x%08x\n",
> +				readl(priv->regs + SPARE_REG));
> +	dev_dbg(dev, "soft_Bypass_Control = 0x%08x\n",
> +				readl(priv->regs + SOFT_BYPASS_CONTROL));
> +	dev_dbg(dev, "soft_Bypass_Data    = 0x%08x\n",
> +				readl(priv->regs + SOFT_BYPASS_DATA));
> +}
> +
> +static irqreturn_t iproc_touchscreen_interrupt(int irq, void *data)
> +{
> +	struct platform_device *pdev = (struct platform_device *)data;

No need to cast here.

> +	struct iproc_ts_priv *priv;
> +	u32 intr_status = 0;
> +	u32 raw_coordinate = 0;
> +	u16 x = 0;
> +	u16 y = 0;

Why do you need all these initialized? It just hides potential problems
when variable is used without assigning proper value.

> +	int i;
> +
> +	priv = (struct iproc_ts_priv *)platform_get_drvdata(pdev);

No need to cast here.

> +
> +	intr_status = readl(priv->regs + INTERRUPT_STATUS);
> +	intr_status &= (TS_PEN_INTR_MASK | TS_FIFO_INTR_MASK);
> +	if (intr_status == 0)
> +		return IRQ_NONE;
> +
> +	/* Clear all interrupt status bits, write-1-clear */
> +	writel(intr_status, priv->regs + INTERRUPT_STATUS);
> +
> +	/* Pen up/down */
> +	if (intr_status & TS_PEN_INTR_MASK) {
> +		if (readl(priv->regs + CONTROLLER_STATUS) & TS_PEN_DOWN) {
> +			priv->pen_status = PEN_DOWN_STATUS;
> +			input_report_key(priv->idev, BTN_TOUCH,
> +				priv->pen_status);

We do not do input_sync() here... But what happens if we do not get
TS_FIFO_INTR_MASK in the status? Won't we "lose" the sync?

I'd prefer you parsed the hardware state fully and then emitted all
needed events based on the state.

> +		} else {
> +			priv->pen_status = PEN_UP_STATUS;
> +			input_report_key(priv->idev, BTN_TOUCH,
> +				priv->pen_status);
> +			input_sync(priv->idev);

Same here. Can we be reporting coordinates from FIFO even after pen is
up?

> +		}
> +
> +		dev_dbg(&priv->pdev->dev,
> +			"pen up-down (%d)\n", priv->pen_status);
> +	}
> +
> +	/* coordinates in FIFO exceed the theshold */
> +	if (intr_status & TS_FIFO_INTR_MASK) {
> +		for (i = 0; i < priv->cfg_params.fifo_threshold; i++) {
> +			raw_coordinate = readl(priv->regs + FIFO_DATA);
> +			if (raw_coordinate == INVALID_COORD)
> +				continue;
> +
> +			/*
> +			 * The x and y coordinate are 16 bits each
> +			 * with the x in the lower 16 bits and y in the
> +			 * upper 16 bits.
> +			 */
> +			x = (raw_coordinate >> X_COORD_SHIFT) &
> +				FIFO_DATA_X_Y_MASK;
> +			y = (raw_coordinate >> Y_COORD_SHIFT) &
> +				FIFO_DATA_X_Y_MASK;
> +
> +			/* We only want to retain the 12 msb of the 16 */
> +			x = (x >> 4) & 0x0FFF;
> +			y = (y >> 4) & 0x0FFF;
> +
> +			/* adjust x y according to lcd tsc mount angle */
> +			if (priv->ts_rotation == TS_ROTATION_90) {
> +				y = Y_MAX - y;
> +			} else if (priv->ts_rotation == TS_ROTATION_180) {
> +				x = X_MAX - x;
> +				y = Y_MAX - y;
> +			} else if (priv->ts_rotation == TS_ROTATION_270) {
> +				x = X_MAX - x;
> +			}
> +
> +			input_report_abs(priv->idev, ABS_X, x);
> +			input_report_abs(priv->idev, ABS_Y, y);
> +			input_sync(priv->idev);
> +
> +			dev_dbg(&priv->pdev->dev, "xy (0x%x 0x%x)\n", x, y);
> +		}
> +	}
> +
> +	return IRQ_HANDLED;
> +}
> +
> +static int iproc_ts_start(struct input_dev *idev)
> +{
> +	u32 val;
> +	int ret;
> +	struct iproc_ts_priv *priv;
> +
> +	priv = input_get_drvdata(idev);
> +	if (priv == NULL)
> +		return -ENODEV;

How can it be NULL? It is fully controlled by this driver and it should
set it up before registering the input device.

> +
> +	/* Enable clock */
> +	ret = clk_prepare_enable(priv->tsc_clk);
> +	if (ret) {
> +		dev_err(&priv->pdev->dev, "%s clk_prepare_enable failed %d\n",
> +			__func__, ret);
> +		return ret;
> +	}
> +
> +	/*
> +	 * Interrupt is generated when:
> +	 *  FIFO reaches the int_th value, and pen event(up/down)
> +	 */
> +	val = TS_PEN_INTR_MASK | TS_FIFO_INTR_MASK;
> +	writel(val, priv->regs + INTERRUPT_MASK);
> +
> +	writel(priv->cfg_params.fifo_threshold, priv->regs + INTERRUPT_THRES);
> +
> +	/* Initialize control reg1 */
> +	val = 0;
> +	val |= (priv->cfg_params.scanning_period << SCANNING_PERIOD_SHIFT);

Please drop extra parentheses here and elsewhere.

> +	val |= (priv->cfg_params.debounce_timeout << DEBOUNCE_TIMEOUT_SHIFT);
> +	val |= (priv->cfg_params.settling_timeout << SETTLING_TIMEOUT_SHIFT);
> +	val |= (priv->cfg_params.touch_timeout << TOUCH_TIMEOUT_SHIFT);
> +	writel(val, priv->regs + REGCTL1);
> +
> +	/* Try to clear all interrupt status */
> +	val = readl(priv->regs + INTERRUPT_STATUS);
> +	val |= (TS_FIFO_INTR_MASK | TS_PEN_INTR_MASK);
> +	writel(val, priv->regs + INTERRUPT_STATUS);
> +
> +	/* Initialize control reg2 */
> +	val = readl(priv->regs + REGCTL2);
> +	val |= (TS_CONTROLLER_EN_BIT | TS_WIRE_MODE_BIT);
> +
> +	val &= ~(TS_CONTROLLER_AVGDATA_MASK);
> +	val |= (priv->cfg_params.average_data << TS_CONTROLLER_AVGDATA_SHIFT);
> +
> +	val &= ~(TS_CONTROLLER_PWR_LDO |	/* PWR up LDO */
> +		   TS_CONTROLLER_PWR_ADC |	/* PWR up ADC */
> +		   TS_CONTROLLER_PWR_BGP |	/* PWR up BGP */
> +		   TS_CONTROLLER_PWR_TS);	/* PWR up TS */
> +
> +	writel(val, priv->regs + REGCTL2);
> +
> +	ts_reg_dump(priv);
> +
> +	return 0;
> +}
> +
> +static void iproc_ts_stop(struct input_dev *dev)
> +{
> +	u32 val;
> +	struct iproc_ts_priv *priv;
> +
> +	priv = input_get_drvdata(dev);
> +	if (priv == NULL)
> +		return;

Again, no need to check it here.

> +
> +	writel(0, priv->regs + INTERRUPT_MASK); /* Disable all interrupts */
> +
> +	/* Only power down touch screen controller */
> +	val = readl(priv->regs + REGCTL2);
> +	val |= TS_CONTROLLER_PWR_TS;
> +	writel(val, priv->regs + REGCTL2);
> +
> +	clk_disable(priv->tsc_clk);
> +}
> +
> +static int get_tsc_config(struct device_node *np, struct iproc_ts_priv *priv)
> +{
> +	u32 val;
> +	struct device *dev = &priv->pdev->dev;
> +
> +	priv->cfg_params = default_config;
> +
> +	if (of_property_read_u32(np, "scanning_period", &val) >= 0) {
> +		if (val < 1 || val > 256) {
> +			dev_err(dev, "scanning_period must be [1-256]\n");
> +			return -EINVAL;
> +		}
> +		priv->cfg_params.scanning_period = val;
> +	}
> +
> +	if (of_property_read_u32(np, "debounce_timeout", &val) >= 0) {
> +		if (val < 0 || val > 255) {
> +			dev_err(dev, "debounce_timeout must be [0-255]\n");
> +			return -EINVAL;
> +		}
> +		priv->cfg_params.debounce_timeout = val;
> +	}
> +
> +	if (of_property_read_u32(np, "settling_timeout", &val) >= 0) {
> +		if (val < 0 || val > 11) {
> +			dev_err(dev, "settling_timeout must be [0-11]\n");
> +			return -EINVAL;
> +		}
> +		priv->cfg_params.settling_timeout = val;
> +	}
> +
> +	if (of_property_read_u32(np, "touch_timeout", &val) >= 0) {
> +		if (val < 0 || val > 255) {
> +			dev_err(dev, "touch_timeout must be [0-255]\n");
> +			return -EINVAL;
> +		}
> +		priv->cfg_params.touch_timeout = val;
> +	}
> +
> +	if (of_property_read_u32(np, "average_data", &val) >= 0) {
> +		if (val < 0 || val > 8) {
> +			dev_err(dev, "average_data must be [0-8]\n");
> +			return -EINVAL;
> +		}
> +		priv->cfg_params.average_data = val;
> +	}
> +
> +	if (of_property_read_u32(np, "fifo_threshold", &val) >= 0) {
> +		if (val < 0 || val > 31) {
> +			dev_err(dev, "fifo_threshold must be [0-31]\n");
> +			return -EINVAL;
> +		}
> +		priv->cfg_params.fifo_threshold = val;
> +	}
> +
> +	priv->ts_rotation = TS_ROTATION_0;
> +	if (of_property_read_u32(np, "ts-rotation", &val) >= 0) {
> +		priv->ts_rotation = val;
> +		dev_dbg(dev, "ts rotation [%d] degrees\n",
> +			90 * priv->ts_rotation);
> +	}
> +
> +	return 0;
> +}
> +
> +static int iproc_ts_probe(struct platform_device *pdev)
> +{
> +	struct iproc_ts_priv *priv;
> +	struct input_dev *idev;
> +	struct resource *res;
> +	int ret;
> +	int irq;
> +
> +	priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
> +	if (!priv)
> +		return -ENOMEM;
> +
> +	/* touchscreen controller memory mapped regs */
> +	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> +	priv->regs = devm_ioremap_resource(&pdev->dev, res);
> +	if (IS_ERR(priv->regs)) {
> +		dev_err(&pdev->dev, "unable to map I/O memory\n");
> +		return PTR_ERR(priv->regs);
> +	}
> +
> +	priv->tsc_clk = devm_clk_get(&pdev->dev, "tsc_clk");
> +	if (IS_ERR(priv->tsc_clk)) {
> +		dev_err(&pdev->dev,
> +			"%s Failed getting clock tsc_clk\n", __func__);
> +		return PTR_ERR(priv->tsc_clk);
> +	}
> +
> +	ret = get_tsc_config(pdev->dev.of_node, priv);
> +	if (ret != 0) {
> +		dev_err(&pdev->dev, "%s get_tsc_config failed\n", __func__);
> +		return ret;
> +	}
> +
> +	idev = devm_input_allocate_device(&pdev->dev);
> +	if (!idev) {
> +		dev_err(&pdev->dev,
> +			"%s Allocate input device failed\n", __func__);
> +		return -ENOMEM;
> +	}
> +
> +	priv->idev = idev;
> +	priv->pdev = pdev;
> +
> +	priv->pen_status = PEN_UP_STATUS;
> +
> +	/* Set input device info  */
> +	idev->name = IPROC_TS_NAME;
> +	idev->dev.parent = &pdev->dev;
> +
> +	idev->id.bustype = BUS_HOST;
> +	idev->id.vendor = SERIO_UNKNOWN;
> +	idev->id.product = 0;
> +	idev->id.version = 0;
> +
> +	idev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS);
> +	set_bit(BTN_TOUCH, idev->keybit);
> +
> +	input_set_abs_params(idev, ABS_X, X_MIN, X_MAX, 0, 0);
> +	input_set_abs_params(idev, ABS_Y, Y_MIN, Y_MAX, 0, 0);
> +
> +	idev->open = iproc_ts_start;
> +	idev->close = iproc_ts_stop;
> +
> +	input_set_drvdata(idev, priv);
> +	platform_set_drvdata(pdev, priv);
> +
> +	/* get interrupt */
> +	irq = platform_get_irq(pdev, 0);
> +	if (irq < 0) {
> +		dev_err(&pdev->dev, "%s platform_get_irq failed\n", __func__);
> +		return irq;
> +	}
> +
> +	ret = devm_request_irq(&pdev->dev, irq,
> +		iproc_touchscreen_interrupt,
> +		IRQF_SHARED, IPROC_TS_NAME, pdev);
> +	if (ret)
> +		return ret;
> +
> +	ret = input_register_device(priv->idev);
> +	if (ret) {
> +		dev_err(&pdev->dev,
> +			"%s register input device failed %d\n", __func__, ret);
> +		return ret;
> +	}
> +
> +	return 0;
> +}
> +
> +static const struct of_device_id iproc_ts_of_match[] = {
> +	{.compatible = "brcm,iproc-touchscreen", },
> +	{ },
> +};
> +MODULE_DEVICE_TABLE(of, iproc_ts_of_match);
> +
> +static struct platform_driver iproc_ts_driver = {
> +	.probe = iproc_ts_probe,
> +	.driver = {
> +		.name	= IPROC_TS_NAME,
> +		.of_match_table = of_match_ptr(iproc_ts_of_match),
> +	},
> +};
> +
> +module_platform_driver(iproc_ts_driver);
> +
> +MODULE_DESCRIPTION("IPROC Touchscreen driver");
> +MODULE_AUTHOR("Broadcom");
> +MODULE_LICENSE("GPL v2");
> -- 
> 1.7.9.5
> 

Thanks.

-- 
Dmitry

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

* [PATCH 0/1] Synopsis 8250 serial port driver fix
       [not found] <Jonathan Richardson <jonathar@broadcom.com>
                   ` (8 preceding siblings ...)
  2015-02-24 19:13 ` [PATCH 0/1] Enable Broadcom Cygnus BCM958305K Jonathan Richardson
@ 2015-02-25 19:04 ` Jonathan Richardson
  2015-02-25 19:04   ` [PATCH 1/1] serial: 8250_dw: Fix get_mctrl behaviour Jonathan Richardson
  2015-02-27  0:35 ` [PATCH v2 0/1] Synopsis 8250 serial port driver fix Jonathan Richardson
                   ` (3 subsequent siblings)
  13 siblings, 1 reply; 92+ messages in thread
From: Jonathan Richardson @ 2015-02-25 19:04 UTC (permalink / raw)
  To: Dmitry Torokhov, Anatol Pomazau, Jonathan Richardson,
	Scott Branden, Rob Herring, Pawel Moll, Mark Rutland,
	Ian Campbell, Kumar Gala, Greg Kroah-Hartman, Jiri Slaby
  Cc: devicetree, linux-kernel, linux-serial

Hi,

This patchset fixes a bug in the Synopsis 8250 serial driver which causes the
driver to hang. The bug occurs on simple 2 wire serial ports when modem control
signalling has been enabled. It can be reproduced from user space by enabling
modem control signals (stty -clocal), then opening a serial port and polling for
data available to read with a timeout. A properly implemented driver will
ignore the control signals and the call to poll will return. The current
version of the driver hangs forever on the call to poll despite the timeout.

Jon

Desmond Liu (1):
  serial: 8250_dw: Fix get_mctrl behaviour

 .../bindings/serial/snps-dw-apb-uart.txt           |    7 ++++
 drivers/tty/serial/8250/8250_dw.c                  |   41 ++++++++++++++++++++
 2 files changed, 48 insertions(+)

-- 
1.7.9.5


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

* [PATCH 1/1] serial: 8250_dw: Fix get_mctrl behaviour
  2015-02-25 19:04 ` [PATCH 0/1] Synopsis 8250 serial port driver fix Jonathan Richardson
@ 2015-02-25 19:04   ` Jonathan Richardson
  2015-02-25 19:21     ` Arnd Bergmann
  0 siblings, 1 reply; 92+ messages in thread
From: Jonathan Richardson @ 2015-02-25 19:04 UTC (permalink / raw)
  To: Dmitry Torokhov, Anatol Pomazau, Jonathan Richardson,
	Scott Branden, Rob Herring, Pawel Moll, Mark Rutland,
	Ian Campbell, Kumar Gala, Greg Kroah-Hartman, Jiri Slaby
  Cc: devicetree, linux-kernel, linux-serial

Fixed behaviour of get_mctrl() serial driver function as documented in:
https://www.kernel.org/doc/Documentation/serial/driver

Added device-tree property 'msr-override' specific to the Synopsis 8250
DesignWare UART driver. Allows one to force Data Carrier Detect,
Clear To Send, and Data Set Ready signals to permanently be reported as
active. The Ring indicator can be forced to be reported as inactive.

It is possible that if modem control signalling is enabled on a port
that doesn't have these pins (e.g. - a simple two wire Tx/Rx port), the
driver can hang indefinitely waiting for the state to change. The new
DT properties allow the driver to ignore the state of these pins on
serial ports that don't support them, as recommended in the kernel
documentation.

Reviewed-by: JD (Jiandong) Zheng <jdzheng@broadcom.com>
Reviewed-by: Jonathan Richardson <jonathar@broadcom.com>
Reviewed-by: Scott Branden <sbranden@broadcom.com>
Tested-by: Scott Branden <sbranden@broadcom.com>
Tested-by: Jonathan Richardson <jonathar@broadcom.com>
Signed-off-by: Jonathan Richardson <jonathar@broadcom.com>
---
 .../bindings/serial/snps-dw-apb-uart.txt           |    7 ++++
 drivers/tty/serial/8250/8250_dw.c                  |   41 ++++++++++++++++++++
 2 files changed, 48 insertions(+)

diff --git a/Documentation/devicetree/bindings/serial/snps-dw-apb-uart.txt b/Documentation/devicetree/bindings/serial/snps-dw-apb-uart.txt
index 7f76214..010e52b 100644
--- a/Documentation/devicetree/bindings/serial/snps-dw-apb-uart.txt
+++ b/Documentation/devicetree/bindings/serial/snps-dw-apb-uart.txt
@@ -21,6 +21,12 @@ Optional properties:
 - reg-io-width : the size (in bytes) of the IO accesses that should be
   performed on the device.  If this property is not present then single byte
   accesses are used.
+- msr-override : array of strings to be used to override the individual
+  modem status signals for DCD, DSR, CTS, and RI.  If the property is not
+  present, the individual signals are obtained from the modem status register.
+  Strings accepted are "dcd", "dsr", "cts", and "ri". If "dcd", "dsr", or
+  "cts" are present, these signals will always be reported as active. If
+  "ri" is present, this signal will always be reported as inactive.
 
 Example:
 
@@ -31,6 +37,7 @@ Example:
 		interrupts = <10>;
 		reg-shift = <2>;
 		reg-io-width = <4>;
+		msr-override = "dcd", "dsr", cts", "ri"
 	};
 
 Example with one clock:
diff --git a/drivers/tty/serial/8250/8250_dw.c b/drivers/tty/serial/8250/8250_dw.c
index 555de07..06dc873 100644
--- a/drivers/tty/serial/8250/8250_dw.c
+++ b/drivers/tty/serial/8250/8250_dw.c
@@ -59,6 +59,8 @@ struct dw8250_data {
 	u8			usr_reg;
 	int			last_mcr;
 	int			line;
+	int			msr_mask_on;
+	int			msr_mask_off;
 	struct clk		*clk;
 	struct clk		*pclk;
 	struct reset_control	*rst;
@@ -81,6 +83,12 @@ static inline int dw8250_modify_msr(struct uart_port *p, int offset, int value)
 		value &= ~UART_MSR_DCTS;
 	}
 
+	/* Override any modem control signals if needed */
+	if (offset == UART_MSR) {
+		value |= d->msr_mask_on;
+		value &= ~d->msr_mask_off;
+	}
+
 	return value;
 }
 
@@ -290,6 +298,8 @@ static int dw8250_probe_of(struct uart_port *p,
 	u32			val;
 	bool has_ucv = true;
 	int id;
+	int msr_cnt, i;
+	const char *inp_name;
 
 #ifdef CONFIG_64BIT
 	if (of_device_is_compatible(np, "cavium,octeon-3860-uart")) {
@@ -334,6 +344,37 @@ static int dw8250_probe_of(struct uart_port *p,
 	if (id >= 0)
 		p->line = id;
 
+	msr_cnt = of_property_count_strings(np, "msr-override");
+
+	if (msr_cnt > 0) {
+		for (i = 0; i < msr_cnt; i++) {
+			of_property_read_string_index(np, "msr-override", i,
+				&inp_name);
+
+			if (!strcmp("dcd", inp_name)) {
+				/* Always report DCD as active */
+				data->msr_mask_on |= UART_MSR_DCD;
+				data->msr_mask_off |= UART_MSR_DDCD;
+			} else if (!strcmp("dsr", inp_name)) {
+				/* Always report DSR as active */
+				data->msr_mask_on |= UART_MSR_DSR;
+				data->msr_mask_off |= UART_MSR_DDSR;
+			} else if (!strcmp("cts", inp_name)) {
+				/* Always report CTS as active */
+				data->msr_mask_on |= UART_MSR_CTS;
+				data->msr_mask_off |= UART_MSR_DCTS;
+			} else if (!strcmp("ri", inp_name)) {
+				/* Always report Ring indicator as inactive */
+				data->msr_mask_off |= UART_MSR_RI;
+				data->msr_mask_off |= UART_MSR_TERI;
+			} else {
+				dev_err(p->dev,
+					"Ignore unknown msr-override %s\n",
+					inp_name);
+			}
+		}
+	}
+
 	/* clock got configured through clk api, all done */
 	if (p->uartclk)
 		return 0;
-- 
1.7.9.5


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

* Re: [PATCH 1/1] serial: 8250_dw: Fix get_mctrl behaviour
  2015-02-25 19:04   ` [PATCH 1/1] serial: 8250_dw: Fix get_mctrl behaviour Jonathan Richardson
@ 2015-02-25 19:21     ` Arnd Bergmann
  2015-02-25 20:00       ` Jonathan Richardson
  0 siblings, 1 reply; 92+ messages in thread
From: Arnd Bergmann @ 2015-02-25 19:21 UTC (permalink / raw)
  To: Jonathan Richardson
  Cc: Dmitry Torokhov, Anatol Pomazau, Scott Branden, Rob Herring,
	Pawel Moll, Mark Rutland, Ian Campbell, Kumar Gala,
	Greg Kroah-Hartman, Jiri Slaby, devicetree, linux-kernel,
	linux-serial

On Wednesday 25 February 2015 11:04:16 Jonathan Richardson wrote:
> +- msr-override : array of strings to be used to override the individual
> +  modem status signals for DCD, DSR, CTS, and RI.  If the property is not
> +  present, the individual signals are obtained from the modem status register.
> +  Strings accepted are "dcd", "dsr", "cts", and "ri". If "dcd", "dsr", or
> +  "cts" are present, these signals will always be reported as active. If
> +  "ri" is present, this signal will always be reported as inactive.
> 

Did you copy this definition from another driver? If not, we should try
to come up with a more natural way to do it. How about defining four
boolean properties instead, like

	dcd-override
	dsr-override
	cts-override
	ri-override

Simplifies the parser and the binding.

	Arnd

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

* Re: [PATCH 1/1] serial: 8250_dw: Fix get_mctrl behaviour
  2015-02-25 19:21     ` Arnd Bergmann
@ 2015-02-25 20:00       ` Jonathan Richardson
  2015-02-25 20:07         ` Arnd Bergmann
  0 siblings, 1 reply; 92+ messages in thread
From: Jonathan Richardson @ 2015-02-25 20:00 UTC (permalink / raw)
  To: Arnd Bergmann
  Cc: Dmitry Torokhov, Anatol Pomazau, Scott Branden, Rob Herring,
	Pawel Moll, Mark Rutland, Ian Campbell, Kumar Gala,
	Greg Kroah-Hartman, Jiri Slaby, devicetree, linux-kernel,
	linux-serial

Hi Arnd,

On 15-02-25 11:21 AM, Arnd Bergmann wrote:
> On Wednesday 25 February 2015 11:04:16 Jonathan Richardson wrote:
>> +- msr-override : array of strings to be used to override the individual
>> +  modem status signals for DCD, DSR, CTS, and RI.  If the property is not
>> +  present, the individual signals are obtained from the modem status register.
>> +  Strings accepted are "dcd", "dsr", "cts", and "ri". If "dcd", "dsr", or
>> +  "cts" are present, these signals will always be reported as active. If
>> +  "ri" is present, this signal will always be reported as inactive.
>>
> 
> Did you copy this definition from another driver? If not, we should try
> to come up with a more natural way to do it. How about defining four
> boolean properties instead, like
> 
> 	dcd-override
> 	dsr-override
> 	cts-override
> 	ri-override
> 
> Simplifies the parser and the binding.

I didn't see anything similar in another driver. I agree with the bools
instead of strings. Did you want to keep these in the Synopsis driver
for now or were you thinking of putting them somewhere that they could
be re-used?

Thanks.

> 
> 	Arnd
> 


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

* Re: [PATCH 1/1] serial: 8250_dw: Fix get_mctrl behaviour
  2015-02-25 20:00       ` Jonathan Richardson
@ 2015-02-25 20:07         ` Arnd Bergmann
  0 siblings, 0 replies; 92+ messages in thread
From: Arnd Bergmann @ 2015-02-25 20:07 UTC (permalink / raw)
  To: Jonathan Richardson
  Cc: Dmitry Torokhov, Anatol Pomazau, Scott Branden, Rob Herring,
	Pawel Moll, Mark Rutland, Ian Campbell, Kumar Gala,
	Greg Kroah-Hartman, Jiri Slaby, devicetree, linux-kernel,
	linux-serial

On Wednesday 25 February 2015 12:00:15 Jonathan Richardson wrote:
> On 15-02-25 11:21 AM, Arnd Bergmann wrote:
> > On Wednesday 25 February 2015 11:04:16 Jonathan Richardson wrote:
> >> +- msr-override : array of strings to be used to override the individual
> >> +  modem status signals for DCD, DSR, CTS, and RI.  If the property is not
> >> +  present, the individual signals are obtained from the modem status register.
> >> +  Strings accepted are "dcd", "dsr", "cts", and "ri". If "dcd", "dsr", or
> >> +  "cts" are present, these signals will always be reported as active. If
> >> +  "ri" is present, this signal will always be reported as inactive.
> >>
> > 
> > Did you copy this definition from another driver? If not, we should try
> > to come up with a more natural way to do it. How about defining four
> > boolean properties instead, like
> > 
> >       dcd-override
> >       dsr-override
> >       cts-override
> >       ri-override
> > 
> > Simplifies the parser and the binding.
> 
> I didn't see anything similar in another driver. I agree with the bools
> instead of strings. Did you want to keep these in the Synopsis driver
> for now or were you thinking of putting them somewhere that they could
> be re-used?

I'm fine with it either way. Unless someone else has an opinion on the
matter, feel free to pick what makes sense to you.

	Arnd

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

* [PATCH v2 0/1] Synopsis 8250 serial port driver fix
       [not found] <Jonathan Richardson <jonathar@broadcom.com>
                   ` (9 preceding siblings ...)
  2015-02-25 19:04 ` [PATCH 0/1] Synopsis 8250 serial port driver fix Jonathan Richardson
@ 2015-02-27  0:35 ` Jonathan Richardson
  2015-02-27  0:35   ` [PATCH v2 1/1] serial: 8250_dw: Fix get_mctrl behaviour Jonathan Richardson
  2015-03-02 22:41 ` [PATCH RESEND 0/1] Enable Broadcom Cygnus BCM958305K Jonathan Richardson
                   ` (2 subsequent siblings)
  13 siblings, 1 reply; 92+ messages in thread
From: Jonathan Richardson @ 2015-02-27  0:35 UTC (permalink / raw)
  To: Dmitry Torokhov, Anatol Pomazau, Jonathan Richardson,
	Scott Branden, Rob Herring, Pawel Moll, Mark Rutland,
	Ian Campbell, Kumar Gala, Greg Kroah-Hartman, Jiri Slaby
  Cc: devicetree, linux-kernel, linux-serial, Arnd Bergmann

Hi,

This patchset fixes a bug in the Synopsis 8250 serial driver which causes the
driver to hang. The bug occurs on simple 2 wire serial ports when modem control
signalling has been enabled. It can be reproduced from user space by enabling
modem control signals (stty -clocal), then opening a serial port and polling for
data available to read with a timeout. A properly implemented driver will
ignore the control signals and the call to poll will return. The current
version of the driver hangs forever on the call to poll despite the timeout.

Jon

Changes from v1:
- Changed DT properties from strings to booleans as suggested by Arnd. 
  Documentation updated accordingly.

Desmond Liu (1):
  serial: 8250_dw: Fix get_mctrl behaviour

 .../bindings/serial/snps-dw-apb-uart.txt           |   16 ++++++++++
 drivers/tty/serial/8250/8250_dw.c                  |   32 ++++++++++++++++++++
 2 files changed, 48 insertions(+)

-- 
1.7.9.5


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

* [PATCH v2 1/1] serial: 8250_dw: Fix get_mctrl behaviour
  2015-02-27  0:35 ` [PATCH v2 0/1] Synopsis 8250 serial port driver fix Jonathan Richardson
@ 2015-02-27  0:35   ` Jonathan Richardson
  2015-03-09 18:40     ` Dmitry Torokhov
  0 siblings, 1 reply; 92+ messages in thread
From: Jonathan Richardson @ 2015-02-27  0:35 UTC (permalink / raw)
  To: Dmitry Torokhov, Anatol Pomazau, Jonathan Richardson,
	Scott Branden, Rob Herring, Pawel Moll, Mark Rutland,
	Ian Campbell, Kumar Gala, Greg Kroah-Hartman, Jiri Slaby
  Cc: devicetree, linux-kernel, linux-serial, Arnd Bergmann, Desmond Liu

From: Desmond Liu <desmondl@broadcom.com>

Fixed behaviour of get_mctrl() serial driver function as documented in:
https://www.kernel.org/doc/Documentation/serial/driver

Added device-tree properties 'dcd-override', 'dsr-override',
'cts-override', and 'ri-override' specific to the Synopsis 8250
DesignWare UART driver. Allows one to force Data Carrier Detect,
Clear To Send, and Data Set Ready signals to permanently be reported as
active. The Ring indicator can be forced to be reported as inactive.

It is possible that if modem control signalling is enabled on a port
that doesn't have these pins (e.g. - a simple two wire Tx/Rx port), the
driver can hang indefinitely waiting for the state to change. The new
DT properties allow the driver to ignore the state of these pins on
serial ports that don't support them, as recommended in the kernel
documentation.

Reviewed-by: JD (Jiandong) Zheng <jdzheng@broadcom.com>
Signed-off-by: Jonathan Richardson <jonathar@broadcom.com>
---
 .../bindings/serial/snps-dw-apb-uart.txt           |   16 ++++++++++
 drivers/tty/serial/8250/8250_dw.c                  |   32 ++++++++++++++++++++
 2 files changed, 48 insertions(+)

diff --git a/Documentation/devicetree/bindings/serial/snps-dw-apb-uart.txt b/Documentation/devicetree/bindings/serial/snps-dw-apb-uart.txt
index 7f76214..289c40e 100644
--- a/Documentation/devicetree/bindings/serial/snps-dw-apb-uart.txt
+++ b/Documentation/devicetree/bindings/serial/snps-dw-apb-uart.txt
@@ -21,6 +21,18 @@ Optional properties:
 - reg-io-width : the size (in bytes) of the IO accesses that should be
   performed on the device.  If this property is not present then single byte
   accesses are used.
+- dcd-override : Override the DCD modem status signal. This signal will always
+  be reported as active instead of being obtained from the modem status
+  register. Define this if your serial port does not use this pin.
+- dsr-override : Override the DTS modem status signal. This signal will always
+  be reported as active instead of being obtained from the modem status
+  register. Define this if your serial port does not use this pin.
+- cts-override : Override the CTS modem status signal. This signal will always
+  be reported as active instead of being obtained from the modem status
+  register. Define this if your serial port does not use this pin.
+- ri-override : Override the RI modem status signal. This signal will always be
+  reported as inactive instead of being obtained from the modem status register.
+  Define this if your serial port does not use this pin.
 
 Example:
 
@@ -31,6 +43,10 @@ Example:
 		interrupts = <10>;
 		reg-shift = <2>;
 		reg-io-width = <4>;
+		dcd-override;
+		dsr-override;
+		cts-override;
+		ri-override;
 	};
 
 Example with one clock:
diff --git a/drivers/tty/serial/8250/8250_dw.c b/drivers/tty/serial/8250/8250_dw.c
index 555de07..1f1d2e6 100644
--- a/drivers/tty/serial/8250/8250_dw.c
+++ b/drivers/tty/serial/8250/8250_dw.c
@@ -59,6 +59,8 @@ struct dw8250_data {
 	u8			usr_reg;
 	int			last_mcr;
 	int			line;
+	int			msr_mask_on;
+	int			msr_mask_off;
 	struct clk		*clk;
 	struct clk		*pclk;
 	struct reset_control	*rst;
@@ -81,6 +83,12 @@ static inline int dw8250_modify_msr(struct uart_port *p, int offset, int value)
 		value &= ~UART_MSR_DCTS;
 	}
 
+	/* Override any modem control signals if needed */
+	if (offset == UART_MSR) {
+		value |= d->msr_mask_on;
+		value &= ~d->msr_mask_off;
+	}
+
 	return value;
 }
 
@@ -334,6 +342,30 @@ static int dw8250_probe_of(struct uart_port *p,
 	if (id >= 0)
 		p->line = id;
 
+	if (of_property_read_bool(np, "dcd-override")) {
+		/* Always report DCD as active */
+		data->msr_mask_on |= UART_MSR_DCD;
+		data->msr_mask_off |= UART_MSR_DDCD;
+	}
+
+	if (of_property_read_bool(np, "dsr-override")) {
+		/* Always report DSR as active */
+		data->msr_mask_on |= UART_MSR_DSR;
+		data->msr_mask_off |= UART_MSR_DDSR;
+	}
+
+	if (of_property_read_bool(np, "cts-override")) {
+		/* Always report DSR as active */
+		data->msr_mask_on |= UART_MSR_DSR;
+		data->msr_mask_off |= UART_MSR_DDSR;
+	}
+
+	if (of_property_read_bool(np, "ri-override")) {
+		/* Always report Ring indicator as inactive */
+		data->msr_mask_off |= UART_MSR_RI;
+		data->msr_mask_off |= UART_MSR_TERI;
+	}
+
 	/* clock got configured through clk api, all done */
 	if (p->uartclk)
 		return 0;
-- 
1.7.9.5


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

* Re: [PATCH v2 1/2] Input: touchscreen-iproc: Add Broadcom iProc touchscreen driver
  2015-02-24 23:18               ` Dmitry Torokhov
@ 2015-02-27  1:02                 ` Jonathan Richardson
  0 siblings, 0 replies; 92+ messages in thread
From: Jonathan Richardson @ 2015-02-27  1:02 UTC (permalink / raw)
  To: Dmitry Torokhov
  Cc: Scott Branden, Grant Likely, Rob Herring, Ray Jui, linux-kernel,
	linux-input, linux-arm-kernel, bcm-kernel-feedback-list,
	devicetree, Joe Perches, Hans de Goede

Hi Dmitry,

Thanks. I'll go through his patch and make the appropriate changes to
our driver.

Jon

On 15-02-24 03:18 PM, Dmitry Torokhov wrote:
> Jonathan,
> 
> 
> On Wed, Feb 11, 2015 at 10:45:34AM -0800, Jonathan Richardson wrote:
>> Pinging maintainers... Am I ok to go ahead with the current rotation
>> implementation? I haven't heard anything further. Any feedback on naming
>> conventions from DT people?
>>
> 
> I believe we should go with touchscreen-inverted-x,
> touchscreen-inverted-y and touchscreen-swapped-x-y properties since
> rotation can't really describe all permutations of potential
> connections.
> 
> I'll be taking Hans de Goede's patch adding this new property to the
> bindings (adjusting the name slightly).
> 
> Thanks.
> 
>> Thanks!
>>
>> On 15-01-15 11:51 AM, Jonathan Richardson wrote:
>>> Hi Dmitry,
>>>
>>> On 15-01-14 10:07 PM, Dmitry Torokhov wrote:
>>>> On Wed, Jan 14, 2015 at 09:44:39PM -0800, Scott Branden wrote:
>>>>> On 15-01-14 05:02 PM, Dmitry Torokhov wrote:
>>>>>> Hi Jonathan,
>>>>>>
>>>>>> On Fri, Dec 19, 2014 at 02:17:49PM -0800, Jonathan Richardson wrote:
>>>>>>> +	if (of_property_read_u32(np, "scanning_period", &val) >= 0) {
>>>>>>> +		if (val < 1 || val > 256) {
>>>>>>> +			dev_err(dev, "scanning_period must be [1-256]\n");
>>>>>>> +			return -EINVAL;
>>>>>>> +		}
>>>>>>> +		priv->cfg_params.scanning_period = val;
>>>>>>> +	}
>>>>>>> +
>>>>>>> +	if (of_property_read_u32(np, "debounce_timeout", &val) >= 0) {
>>>>>>> +		if (val < 0 || val > 255) {
>>>>>>> +			dev_err(dev, "debounce_timeout must be [0-255]\n");
>>>>>>> +			return -EINVAL;
>>>>>>> +		}
>>>>>>> +		priv->cfg_params.debounce_timeout = val;
>>>>>>> +	}
>>>>>>> +
>>>>>>> +	if (of_property_read_u32(np, "settling_timeout", &val) >= 0) {
>>>>>>> +		if (val < 0 || val > 11) {
>>>>>>> +			dev_err(dev, "settling_timeout must be [0-11]\n");
>>>>>>> +			return -EINVAL;
>>>>>>> +		}
>>>>>>> +		priv->cfg_params.settling_timeout = val;
>>>>>>> +	}
>>>>>>> +
>>>>>>> +	if (of_property_read_u32(np, "touch_timeout", &val) >= 0) {
>>>>>>> +		if (val < 0 || val > 255) {
>>>>>>> +			dev_err(dev, "touch_timeout must be [0-255]\n");
>>>>>>> +			return -EINVAL;
>>>>>>> +		}
>>>>>>> +		priv->cfg_params.touch_timeout = val;
>>>>>>> +	}
>>>>>>> +
>>>>>>> +	if (of_property_read_u32(np, "average_data", &val) >= 0) {
>>>>>>> +		if (val < 0 || val > 8) {
>>>>>>> +			dev_err(dev, "average_data must be [0-8]\n");
>>>>>>> +			return -EINVAL;
>>>>>>> +		}
>>>>>>> +		priv->cfg_params.average_data = val;
>>>>>>> +	}
>>>>>>> +
>>>>>>> +	if (of_property_read_u32(np, "fifo_threshold", &val) >= 0) {
>>>>>>> +		if (val < 0 || val > 31) {
>>>>>>> +			dev_err(dev, "fifo_threshold must be [0-31]\n");
>>>>>>> +			return -EINVAL;
>>>>>>> +		}
>>>>>>> +		priv->cfg_params.fifo_threshold = val;
>>>>>>> +	}
>>>>>>
>>>>>> I think these are dveice specific and thus should have "brcm," prefix.
>>>>> I'm confused as to why we need the brcm prefix?  Other device tree
>>>>> bindings we have for other drivers do not need such prefix.
>>>>
>>>> Properties that are not standard on the system (reg, interrupts,
>>>> clkocks, etc) or subsystem level customarily carry the vendor prefix so
>>>> that they do not clash with newly added global or subsystem properties.
>>>>
>>>>>  Is this
>>>>> convention documented somewhere?
>>>>
>>>> Not sure. I glanced through Documentation/devicetree and do not see it
>>>> spelled out. Device tree overlords, what say you?
>>>
>>> Let me know. I haven't seen this before either. I will change the
>>> entries to use dashes though instead of underscores but will wait until
>>> these other issues are decided on before sending out another patch.
>>>
>>>>
>>>>>>
>>>>>>> +
>>>>>>> +	priv->ts_rotation = TS_ROTATION_0;
>>>>>>> +	if (of_property_read_u32(np, "ts-rotation", &val) >= 0) {
>>>>>>> +		priv->ts_rotation = val;
>>>>>>> +		dev_dbg(dev, "ts rotation [%d] degrees\n",
>>>>>>> +			90 * priv->ts_rotation);
>>>>>>> +	}
>>>>>>
>>>>>> This I am not quite sure about - if we want rotation or swap+invert. You
>>>>>> are CCed on another email (tsc2007) that talks about need of generic
>>>>>> touchscreen transforms in input core/of bindings.
>>>>> Does such generic binding exist today?  If not, I would like to go
>>>>> with this implementation and update to the new binding if/when it
>>>>> exists?
>>>>
>>>> Not yet but there several people interested. I think we have enough time
>>>> till 3.20 to hash it out properly.
>>>
>>> I think the rotation is simpler personally. Everyone would understand
>>> rotation refers to how it's oriented but I'm not sure everyone would
>>> immediately know how it is wired. Let me know what is decided and I'll
>>> make any changes required.
>>>
>>> Thanks,
>>> Jon
>>>
>>>
>>>>
>>>> Thanks.
>>>>
>>>
>>
> 


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

* Re: [PATCH v2 1/2] Input: touchscreen-iproc: Add Broadcom iProc touchscreen driver
  2015-02-24 23:29     ` Dmitry Torokhov
@ 2015-03-02 19:13       ` Jonathan Richardson
  0 siblings, 0 replies; 92+ messages in thread
From: Jonathan Richardson @ 2015-03-02 19:13 UTC (permalink / raw)
  To: Dmitry Torokhov
  Cc: Grant Likely, Rob Herring, Ray Jui, linux-kernel, linux-input,
	linux-arm-kernel, bcm-kernel-feedback-list, devicetree,
	Joe Perches

Hi Dmitry,

Thanks for the review. I'll fix everything as suggested. One comment
below. New patchset coming once I can test the latest DT bindings in
Hans de Goede's patch.

Thanks,
Jon

On 15-02-24 03:29 PM, Dmitry Torokhov wrote:
> Hi Jonathan,
> 
> On Fri, Dec 19, 2014 at 02:17:49PM -0800, Jonathan Richardson wrote:
>> Add initial version of the Broadcom touchscreen driver.
>>
>> Reviewed-by: Ray Jui <rjui@broadcom.com>
>> Reviewed-by: Scott Branden <sbranden@broadcom.com>
>> Tested-by: Scott Branden <sbranden@broadcom.com>
>> Signed-off-by: Jonathan Richardson <jonathar@broadcom.com>
>> ---
>>  drivers/input/touchscreen/Kconfig         |   11 +
>>  drivers/input/touchscreen/Makefile        |    1 +
>>  drivers/input/touchscreen/bcm_iproc_tsc.c |  535 +++++++++++++++++++++++++++++
>>  3 files changed, 547 insertions(+)
>>  create mode 100644 drivers/input/touchscreen/bcm_iproc_tsc.c
>>
>> diff --git a/drivers/input/touchscreen/Kconfig b/drivers/input/touchscreen/Kconfig
>> index e1d8003..77ff531 100644
>> --- a/drivers/input/touchscreen/Kconfig
>> +++ b/drivers/input/touchscreen/Kconfig
>> @@ -310,6 +310,17 @@ config TOUCHSCREEN_ILI210X
>>  	  To compile this driver as a module, choose M here: the
>>  	  module will be called ili210x.
>>  
>> +config TOUCHSCREEN_IPROC
>> +	tristate "IPROC touch panel driver support"
>> +	help
>> +	  Say Y here if you want to add support for the IPROC touch
>> +	  controller to your system.
>> +
>> +	  If unsure, say N.
>> +
>> +	  To compile this driver as a module, choose M here: the
>> +	  module will be called iproc-ts.
>> +
>>  config TOUCHSCREEN_S3C2410
>>  	tristate "Samsung S3C2410/generic touchscreen input driver"
>>  	depends on ARCH_S3C24XX || SAMSUNG_DEV_TS
>> diff --git a/drivers/input/touchscreen/Makefile b/drivers/input/touchscreen/Makefile
>> index 090e61c..f7e6de9 100644
>> --- a/drivers/input/touchscreen/Makefile
>> +++ b/drivers/input/touchscreen/Makefile
>> @@ -37,6 +37,7 @@ obj-$(CONFIG_TOUCHSCREEN_FUJITSU)	+= fujitsu_ts.o
>>  obj-$(CONFIG_TOUCHSCREEN_ILI210X)	+= ili210x.o
>>  obj-$(CONFIG_TOUCHSCREEN_INEXIO)	+= inexio.o
>>  obj-$(CONFIG_TOUCHSCREEN_INTEL_MID)	+= intel-mid-touch.o
>> +obj-$(CONFIG_TOUCHSCREEN_IPROC)		+= bcm_iproc_tsc.o
>>  obj-$(CONFIG_TOUCHSCREEN_LPC32XX)	+= lpc32xx_ts.o
>>  obj-$(CONFIG_TOUCHSCREEN_MAX11801)	+= max11801_ts.o
>>  obj-$(CONFIG_TOUCHSCREEN_MC13783)	+= mc13783_ts.o
>> diff --git a/drivers/input/touchscreen/bcm_iproc_tsc.c b/drivers/input/touchscreen/bcm_iproc_tsc.c
>> new file mode 100644
>> index 0000000..bf6eb7f
>> --- /dev/null
>> +++ b/drivers/input/touchscreen/bcm_iproc_tsc.c
>> @@ -0,0 +1,535 @@
>> +/*
>> +* Copyright (C) 2014 Broadcom Corporation
>> +*
>> +* This program is free software; you can redistribute it and/or
>> +* modify it under the terms of the GNU General Public License as
>> +* published by the Free Software Foundation version 2.
>> +*
>> +* This program is distributed "as is" WITHOUT ANY WARRANTY of any
>> +* kind, whether express or implied; without even the implied warranty
>> +* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
>> +* GNU General Public License for more details.
>> +*/
>> +#include <linux/module.h>
>> +#include <linux/init.h>
>> +#include <linux/input.h>
>> +#include <linux/delay.h>
>> +#include <linux/interrupt.h>
>> +#include <linux/keyboard.h>
>> +#include <linux/platform_device.h>
>> +#include <linux/slab.h>
>> +#include <linux/of.h>
>> +#include <asm/irq.h>
>> +#include <linux/io.h>
>> +#include <linux/clk.h>
>> +#include <linux/serio.h>
>> +
>> +#define IPROC_TS_NAME "iproc-ts"
>> +
>> +#define PEN_DOWN_STATUS     1
>> +#define PEN_UP_STATUS       0
>> +
>> +#define X_MIN               0
>> +#define Y_MIN               0
>> +#define X_MAX               0xFFF
>> +#define Y_MAX               0xFFF
>> +
>> +/* Value given by controller for invalid coordinate. */
>> +#define INVALID_COORD       0xFFFFFFFF
>> +
>> +/* Register offsets */
>> +#define REGCTL1             0x00
>> +#define REGCTL2             0x04
>> +#define INTERRUPT_THRES     0x08
>> +#define INTERRUPT_MASK      0x0c
>> +
>> +#define INTERRUPT_STATUS    0x10
>> +#define CONTROLLER_STATUS   0x14
>> +#define FIFO_DATA           0x18
>> +#define FIFO_DATA_X_Y_MASK  0xFFFF
>> +#define ANALOG_CONTROL      0x1c
>> +
>> +#define AUX_DATA            0x20
>> +#define DEBOUNCE_CNTR_STAT  0x24
>> +#define SCAN_CNTR_STAT      0x28
>> +#define REM_CNTR_STAT       0x2c
>> +
>> +#define SETTLING_TIMER_STAT 0x30
>> +#define SPARE_REG           0x34
>> +#define SOFT_BYPASS_CONTROL 0x38
>> +#define SOFT_BYPASS_DATA    0x3c
>> +
>> +
>> +/* Bit values for INTERRUPT_MASK and INTERRUPT_STATUS regs */
>> +#define TS_PEN_INTR_MASK        BIT(0)
>> +#define TS_FIFO_INTR_MASK       BIT(2)
>> +
>> +/* Bit values for CONTROLLER_STATUS reg1 */
>> +#define TS_PEN_DOWN             BIT(0)
>> +
>> +/* Shift values for control reg1 */
>> +#define SCANNING_PERIOD_SHIFT   24
>> +#define DEBOUNCE_TIMEOUT_SHIFT  16
>> +#define SETTLING_TIMEOUT_SHIFT  8
>> +#define TOUCH_TIMEOUT_SHIFT     0
>> +
>> +/* Shift values for coordinates from fifo */
>> +#define X_COORD_SHIFT  0
>> +#define Y_COORD_SHIFT  16
>> +
>> +/* Bit values for REGCTL2 */
>> +#define TS_CONTROLLER_EN_BIT    BIT(16)
>> +#define TS_CONTROLLER_AVGDATA_SHIFT 8
>> +#define TS_CONTROLLER_AVGDATA_MASK (0x7 << TS_CONTROLLER_AVGDATA_SHIFT)
>> +#define TS_CONTROLLER_PWR_LDO   BIT(5)
>> +#define TS_CONTROLLER_PWR_ADC   BIT(4)
>> +#define TS_CONTROLLER_PWR_BGP   BIT(3)
>> +#define TS_CONTROLLER_PWR_TS    BIT(2)
>> +#define TS_WIRE_MODE_BIT        BIT(1)
>> +
>> +/*
>> + * Touch screen mount angles w.r.t LCD panel left side top corner
>> + * TS (x_min,y_min) placed at LCD (x_min,y_min) rotation angle is 0
>> + * TS (x_min,y_max) placed at LCD (x_min,y_min) rotation angle is 90
>> + * TS (x_max,y_max) placed at LCD (x_min,y_min) rotation angle is 180
>> + * TS (x_max,y_min) placed at LCD (x_min,y_min) rotation angle is 270
>> + */
>> +enum ts_rotation_angles {
>> +	TS_ROTATION_0,
>> +	TS_ROTATION_90,
>> +	TS_ROTATION_180,
>> +	TS_ROTATION_270,
>> +};
>> +
>> +struct tsc_param {
>> +	/* Each step is 1024 us.  Valid 1-256 */
>> +	u32 scanning_period;
>> +
>> +	/*  Each step is 512 us.  Valid 0-255 */
>> +	u32 debounce_timeout;
>> +
>> +	/*
>> +	 * The settling duration (in ms) is the amount of time the tsc
>> +	 * waits to allow the voltage to settle after turning on the
>> +	 * drivers in detection mode. Valid values: 0-11
>> +	 *   0 =  0.008 ms
>> +	 *   1 =  0.01 ms
>> +	 *   2 =  0.02 ms
>> +	 *   3 =  0.04 ms
>> +	 *   4 =  0.08 ms
>> +	 *   5 =  0.16 ms
>> +	 *   6 =  0.32 ms
>> +	 *   7 =  0.64 ms
>> +	 *   8 =  1.28 ms
>> +	 *   9 =  2.56 ms
>> +	 *   10 = 5.12 ms
>> +	 *   11 = 10.24 ms
>> +	 */
>> +	u32 settling_timeout;
>> +
>> +	/* touch timeout in sample counts */
>> +	u32 touch_timeout;
>> +
>> +	/*
>> +	 * Number of data samples which are averaged before a final data point
>> +	 * is placed into the FIFO
>> +	 */
>> +	u32 average_data;
>> +
>> +	/* FIFO threshold */
>> +	u32 fifo_threshold;
>> +};
>> +
>> +struct iproc_ts_priv {
>> +	struct platform_device *pdev;
>> +	struct input_dev *idev;
>> +
>> +	void __iomem *regs;
>> +	struct clk *tsc_clk;
>> +
>> +	int  pen_status;
>> +	int  ts_rotation;
>> +	struct tsc_param cfg_params;
>> +};
>> +
>> +/*
>> + * Set default values the same as hardware reset values
>> + * except for fifo_threshold with is set to 1.
>> + */
>> +static struct tsc_param default_config = {
>> +	.scanning_period  = 0x5,  /* 1 to 256 */
>> +	.debounce_timeout = 0x28, /* 0 to 255 */
>> +	.settling_timeout = 0x7,  /* 0 to 11 */
>> +	.touch_timeout    = 0xa,  /* 0 to 255 */
>> +	.average_data     = 5,    /* entry 5 = 32 pts */
>> +	.fifo_threshold   = 1,    /* 0 to 31 */
>> +};
>> +
>> +static void ts_reg_dump(struct iproc_ts_priv *priv)
>> +{
>> +	struct device *dev = &priv->pdev->dev;
>> +
>> +	dev_dbg(dev, "regCtl1             = 0x%08x\n",
>> +				readl(priv->regs + REGCTL1));
>> +	dev_dbg(dev, "regCtl2             = 0x%08x\n",
>> +				readl(priv->regs + REGCTL2));
>> +	dev_dbg(dev, "interrupt_Thres     = 0x%08x\n",
>> +				readl(priv->regs + INTERRUPT_THRES));
>> +	dev_dbg(dev, "interrupt_Mask      = 0x%08x\n",
>> +				readl(priv->regs + INTERRUPT_MASK));
>> +	dev_dbg(dev, "interrupt_Status    = 0x%08x\n",
>> +				readl(priv->regs + INTERRUPT_STATUS));
>> +	dev_dbg(dev, "controller_Status   = 0x%08x\n",
>> +				readl(priv->regs + CONTROLLER_STATUS));
>> +	dev_dbg(dev, "FIFO_Data           = 0x%08x\n",
>> +				readl(priv->regs + FIFO_DATA));
>> +	dev_dbg(dev, "analog_Control      = 0x%08x\n",
>> +				readl(priv->regs + ANALOG_CONTROL));
>> +	dev_dbg(dev, "aux_Data            = 0x%08x\n",
>> +				readl(priv->regs + AUX_DATA));
>> +	dev_dbg(dev, "debounce_Cntr_Stat  = 0x%08x\n",
>> +				readl(priv->regs + DEBOUNCE_CNTR_STAT));
>> +	dev_dbg(dev, "scan_Cntr_Stat      = 0x%08x\n",
>> +				readl(priv->regs + SCAN_CNTR_STAT));
>> +	dev_dbg(dev, "rem_Cntr_Stat       = 0x%08x\n",
>> +				readl(priv->regs + REM_CNTR_STAT));
>> +	dev_dbg(dev, "settling_Timer_Stat = 0x%08x\n",
>> +				readl(priv->regs + SETTLING_TIMER_STAT));
>> +	dev_dbg(dev, "spare_Reg           = 0x%08x\n",
>> +				readl(priv->regs + SPARE_REG));
>> +	dev_dbg(dev, "soft_Bypass_Control = 0x%08x\n",
>> +				readl(priv->regs + SOFT_BYPASS_CONTROL));
>> +	dev_dbg(dev, "soft_Bypass_Data    = 0x%08x\n",
>> +				readl(priv->regs + SOFT_BYPASS_DATA));
>> +}
>> +
>> +static irqreturn_t iproc_touchscreen_interrupt(int irq, void *data)
>> +{
>> +	struct platform_device *pdev = (struct platform_device *)data;
> 
> No need to cast here.
> 
>> +	struct iproc_ts_priv *priv;
>> +	u32 intr_status = 0;
>> +	u32 raw_coordinate = 0;
>> +	u16 x = 0;
>> +	u16 y = 0;
> 
> Why do you need all these initialized? It just hides potential problems
> when variable is used without assigning proper value.
> 
>> +	int i;
>> +
>> +	priv = (struct iproc_ts_priv *)platform_get_drvdata(pdev);
> 
> No need to cast here.
> 
>> +
>> +	intr_status = readl(priv->regs + INTERRUPT_STATUS);
>> +	intr_status &= (TS_PEN_INTR_MASK | TS_FIFO_INTR_MASK);
>> +	if (intr_status == 0)
>> +		return IRQ_NONE;
>> +
>> +	/* Clear all interrupt status bits, write-1-clear */
>> +	writel(intr_status, priv->regs + INTERRUPT_STATUS);
>> +
>> +	/* Pen up/down */
>> +	if (intr_status & TS_PEN_INTR_MASK) {
>> +		if (readl(priv->regs + CONTROLLER_STATUS) & TS_PEN_DOWN) {
>> +			priv->pen_status = PEN_DOWN_STATUS;
>> +			input_report_key(priv->idev, BTN_TOUCH,
>> +				priv->pen_status);
> 
> We do not do input_sync() here... But what happens if we do not get
> TS_FIFO_INTR_MASK in the status? Won't we "lose" the sync?
> 
> I'd prefer you parsed the hardware state fully and then emitted all
> needed events based on the state.

I'll change this to one input_sync() call for all events.

> 
>> +		} else {
>> +			priv->pen_status = PEN_UP_STATUS;
>> +			input_report_key(priv->idev, BTN_TOUCH,
>> +				priv->pen_status);
>> +			input_sync(priv->idev);
> 
> Same here. Can we be reporting coordinates from FIFO even after pen is
> up?

The h/w doesn't seem to. I couldn't see it generate a pen down without
fifo data nor fifo data with pen up. But probably better not to assume
it will never. One call to input_sync() as suggested above should fix
the problem.

> 
>> +		}
>> +
>> +		dev_dbg(&priv->pdev->dev,
>> +			"pen up-down (%d)\n", priv->pen_status);
>> +	}
>> +
>> +	/* coordinates in FIFO exceed the theshold */
>> +	if (intr_status & TS_FIFO_INTR_MASK) {
>> +		for (i = 0; i < priv->cfg_params.fifo_threshold; i++) {
>> +			raw_coordinate = readl(priv->regs + FIFO_DATA);
>> +			if (raw_coordinate == INVALID_COORD)
>> +				continue;
>> +
>> +			/*
>> +			 * The x and y coordinate are 16 bits each
>> +			 * with the x in the lower 16 bits and y in the
>> +			 * upper 16 bits.
>> +			 */
>> +			x = (raw_coordinate >> X_COORD_SHIFT) &
>> +				FIFO_DATA_X_Y_MASK;
>> +			y = (raw_coordinate >> Y_COORD_SHIFT) &
>> +				FIFO_DATA_X_Y_MASK;
>> +
>> +			/* We only want to retain the 12 msb of the 16 */
>> +			x = (x >> 4) & 0x0FFF;
>> +			y = (y >> 4) & 0x0FFF;
>> +
>> +			/* adjust x y according to lcd tsc mount angle */
>> +			if (priv->ts_rotation == TS_ROTATION_90) {
>> +				y = Y_MAX - y;
>> +			} else if (priv->ts_rotation == TS_ROTATION_180) {
>> +				x = X_MAX - x;
>> +				y = Y_MAX - y;
>> +			} else if (priv->ts_rotation == TS_ROTATION_270) {
>> +				x = X_MAX - x;
>> +			}
>> +
>> +			input_report_abs(priv->idev, ABS_X, x);
>> +			input_report_abs(priv->idev, ABS_Y, y);
>> +			input_sync(priv->idev);
>> +
>> +			dev_dbg(&priv->pdev->dev, "xy (0x%x 0x%x)\n", x, y);
>> +		}
>> +	}
>> +
>> +	return IRQ_HANDLED;
>> +}
>> +
>> +static int iproc_ts_start(struct input_dev *idev)
>> +{
>> +	u32 val;
>> +	int ret;
>> +	struct iproc_ts_priv *priv;
>> +
>> +	priv = input_get_drvdata(idev);
>> +	if (priv == NULL)
>> +		return -ENODEV;
> 
> How can it be NULL? It is fully controlled by this driver and it should
> set it up before registering the input device.
> 
>> +
>> +	/* Enable clock */
>> +	ret = clk_prepare_enable(priv->tsc_clk);
>> +	if (ret) {
>> +		dev_err(&priv->pdev->dev, "%s clk_prepare_enable failed %d\n",
>> +			__func__, ret);
>> +		return ret;
>> +	}
>> +
>> +	/*
>> +	 * Interrupt is generated when:
>> +	 *  FIFO reaches the int_th value, and pen event(up/down)
>> +	 */
>> +	val = TS_PEN_INTR_MASK | TS_FIFO_INTR_MASK;
>> +	writel(val, priv->regs + INTERRUPT_MASK);
>> +
>> +	writel(priv->cfg_params.fifo_threshold, priv->regs + INTERRUPT_THRES);
>> +
>> +	/* Initialize control reg1 */
>> +	val = 0;
>> +	val |= (priv->cfg_params.scanning_period << SCANNING_PERIOD_SHIFT);
> 
> Please drop extra parentheses here and elsewhere.
> 
>> +	val |= (priv->cfg_params.debounce_timeout << DEBOUNCE_TIMEOUT_SHIFT);
>> +	val |= (priv->cfg_params.settling_timeout << SETTLING_TIMEOUT_SHIFT);
>> +	val |= (priv->cfg_params.touch_timeout << TOUCH_TIMEOUT_SHIFT);
>> +	writel(val, priv->regs + REGCTL1);
>> +
>> +	/* Try to clear all interrupt status */
>> +	val = readl(priv->regs + INTERRUPT_STATUS);
>> +	val |= (TS_FIFO_INTR_MASK | TS_PEN_INTR_MASK);
>> +	writel(val, priv->regs + INTERRUPT_STATUS);
>> +
>> +	/* Initialize control reg2 */
>> +	val = readl(priv->regs + REGCTL2);
>> +	val |= (TS_CONTROLLER_EN_BIT | TS_WIRE_MODE_BIT);
>> +
>> +	val &= ~(TS_CONTROLLER_AVGDATA_MASK);
>> +	val |= (priv->cfg_params.average_data << TS_CONTROLLER_AVGDATA_SHIFT);
>> +
>> +	val &= ~(TS_CONTROLLER_PWR_LDO |	/* PWR up LDO */
>> +		   TS_CONTROLLER_PWR_ADC |	/* PWR up ADC */
>> +		   TS_CONTROLLER_PWR_BGP |	/* PWR up BGP */
>> +		   TS_CONTROLLER_PWR_TS);	/* PWR up TS */
>> +
>> +	writel(val, priv->regs + REGCTL2);
>> +
>> +	ts_reg_dump(priv);
>> +
>> +	return 0;
>> +}
>> +
>> +static void iproc_ts_stop(struct input_dev *dev)
>> +{
>> +	u32 val;
>> +	struct iproc_ts_priv *priv;
>> +
>> +	priv = input_get_drvdata(dev);
>> +	if (priv == NULL)
>> +		return;
> 
> Again, no need to check it here.
> 
>> +
>> +	writel(0, priv->regs + INTERRUPT_MASK); /* Disable all interrupts */
>> +
>> +	/* Only power down touch screen controller */
>> +	val = readl(priv->regs + REGCTL2);
>> +	val |= TS_CONTROLLER_PWR_TS;
>> +	writel(val, priv->regs + REGCTL2);
>> +
>> +	clk_disable(priv->tsc_clk);
>> +}
>> +
>> +static int get_tsc_config(struct device_node *np, struct iproc_ts_priv *priv)
>> +{
>> +	u32 val;
>> +	struct device *dev = &priv->pdev->dev;
>> +
>> +	priv->cfg_params = default_config;
>> +
>> +	if (of_property_read_u32(np, "scanning_period", &val) >= 0) {
>> +		if (val < 1 || val > 256) {
>> +			dev_err(dev, "scanning_period must be [1-256]\n");
>> +			return -EINVAL;
>> +		}
>> +		priv->cfg_params.scanning_period = val;
>> +	}
>> +
>> +	if (of_property_read_u32(np, "debounce_timeout", &val) >= 0) {
>> +		if (val < 0 || val > 255) {
>> +			dev_err(dev, "debounce_timeout must be [0-255]\n");
>> +			return -EINVAL;
>> +		}
>> +		priv->cfg_params.debounce_timeout = val;
>> +	}
>> +
>> +	if (of_property_read_u32(np, "settling_timeout", &val) >= 0) {
>> +		if (val < 0 || val > 11) {
>> +			dev_err(dev, "settling_timeout must be [0-11]\n");
>> +			return -EINVAL;
>> +		}
>> +		priv->cfg_params.settling_timeout = val;
>> +	}
>> +
>> +	if (of_property_read_u32(np, "touch_timeout", &val) >= 0) {
>> +		if (val < 0 || val > 255) {
>> +			dev_err(dev, "touch_timeout must be [0-255]\n");
>> +			return -EINVAL;
>> +		}
>> +		priv->cfg_params.touch_timeout = val;
>> +	}
>> +
>> +	if (of_property_read_u32(np, "average_data", &val) >= 0) {
>> +		if (val < 0 || val > 8) {
>> +			dev_err(dev, "average_data must be [0-8]\n");
>> +			return -EINVAL;
>> +		}
>> +		priv->cfg_params.average_data = val;
>> +	}
>> +
>> +	if (of_property_read_u32(np, "fifo_threshold", &val) >= 0) {
>> +		if (val < 0 || val > 31) {
>> +			dev_err(dev, "fifo_threshold must be [0-31]\n");
>> +			return -EINVAL;
>> +		}
>> +		priv->cfg_params.fifo_threshold = val;
>> +	}
>> +
>> +	priv->ts_rotation = TS_ROTATION_0;
>> +	if (of_property_read_u32(np, "ts-rotation", &val) >= 0) {
>> +		priv->ts_rotation = val;
>> +		dev_dbg(dev, "ts rotation [%d] degrees\n",
>> +			90 * priv->ts_rotation);
>> +	}
>> +
>> +	return 0;
>> +}
>> +
>> +static int iproc_ts_probe(struct platform_device *pdev)
>> +{
>> +	struct iproc_ts_priv *priv;
>> +	struct input_dev *idev;
>> +	struct resource *res;
>> +	int ret;
>> +	int irq;
>> +
>> +	priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
>> +	if (!priv)
>> +		return -ENOMEM;
>> +
>> +	/* touchscreen controller memory mapped regs */
>> +	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
>> +	priv->regs = devm_ioremap_resource(&pdev->dev, res);
>> +	if (IS_ERR(priv->regs)) {
>> +		dev_err(&pdev->dev, "unable to map I/O memory\n");
>> +		return PTR_ERR(priv->regs);
>> +	}
>> +
>> +	priv->tsc_clk = devm_clk_get(&pdev->dev, "tsc_clk");
>> +	if (IS_ERR(priv->tsc_clk)) {
>> +		dev_err(&pdev->dev,
>> +			"%s Failed getting clock tsc_clk\n", __func__);
>> +		return PTR_ERR(priv->tsc_clk);
>> +	}
>> +
>> +	ret = get_tsc_config(pdev->dev.of_node, priv);
>> +	if (ret != 0) {
>> +		dev_err(&pdev->dev, "%s get_tsc_config failed\n", __func__);
>> +		return ret;
>> +	}
>> +
>> +	idev = devm_input_allocate_device(&pdev->dev);
>> +	if (!idev) {
>> +		dev_err(&pdev->dev,
>> +			"%s Allocate input device failed\n", __func__);
>> +		return -ENOMEM;
>> +	}
>> +
>> +	priv->idev = idev;
>> +	priv->pdev = pdev;
>> +
>> +	priv->pen_status = PEN_UP_STATUS;
>> +
>> +	/* Set input device info  */
>> +	idev->name = IPROC_TS_NAME;
>> +	idev->dev.parent = &pdev->dev;
>> +
>> +	idev->id.bustype = BUS_HOST;
>> +	idev->id.vendor = SERIO_UNKNOWN;
>> +	idev->id.product = 0;
>> +	idev->id.version = 0;
>> +
>> +	idev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS);
>> +	set_bit(BTN_TOUCH, idev->keybit);
>> +
>> +	input_set_abs_params(idev, ABS_X, X_MIN, X_MAX, 0, 0);
>> +	input_set_abs_params(idev, ABS_Y, Y_MIN, Y_MAX, 0, 0);
>> +
>> +	idev->open = iproc_ts_start;
>> +	idev->close = iproc_ts_stop;
>> +
>> +	input_set_drvdata(idev, priv);
>> +	platform_set_drvdata(pdev, priv);
>> +
>> +	/* get interrupt */
>> +	irq = platform_get_irq(pdev, 0);
>> +	if (irq < 0) {
>> +		dev_err(&pdev->dev, "%s platform_get_irq failed\n", __func__);
>> +		return irq;
>> +	}
>> +
>> +	ret = devm_request_irq(&pdev->dev, irq,
>> +		iproc_touchscreen_interrupt,
>> +		IRQF_SHARED, IPROC_TS_NAME, pdev);
>> +	if (ret)
>> +		return ret;
>> +
>> +	ret = input_register_device(priv->idev);
>> +	if (ret) {
>> +		dev_err(&pdev->dev,
>> +			"%s register input device failed %d\n", __func__, ret);
>> +		return ret;
>> +	}
>> +
>> +	return 0;
>> +}
>> +
>> +static const struct of_device_id iproc_ts_of_match[] = {
>> +	{.compatible = "brcm,iproc-touchscreen", },
>> +	{ },
>> +};
>> +MODULE_DEVICE_TABLE(of, iproc_ts_of_match);
>> +
>> +static struct platform_driver iproc_ts_driver = {
>> +	.probe = iproc_ts_probe,
>> +	.driver = {
>> +		.name	= IPROC_TS_NAME,
>> +		.of_match_table = of_match_ptr(iproc_ts_of_match),
>> +	},
>> +};
>> +
>> +module_platform_driver(iproc_ts_driver);
>> +
>> +MODULE_DESCRIPTION("IPROC Touchscreen driver");
>> +MODULE_AUTHOR("Broadcom");
>> +MODULE_LICENSE("GPL v2");
>> -- 
>> 1.7.9.5
>>
> 
> Thanks.
> 



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

* [PATCH RESEND 0/1] Enable Broadcom Cygnus BCM958305K
       [not found] <Jonathan Richardson <jonathar@broadcom.com>
                   ` (10 preceding siblings ...)
  2015-02-27  0:35 ` [PATCH v2 0/1] Synopsis 8250 serial port driver fix Jonathan Richardson
@ 2015-03-02 22:41 ` Jonathan Richardson
  2015-03-02 22:41   ` [PATCH RESEND 1/1] ARM: dts: " Jonathan Richardson
  2015-03-11  1:17 ` [PATCH v3 0/2] Add support for Broadcom iProc touchscreen Jonathan Richardson
  2015-03-12 17:45 ` [PATCH v4 0/2] Add support for Broadcom iProc touchscreen Jonathan Richardson
  13 siblings, 1 reply; 92+ messages in thread
From: Jonathan Richardson @ 2015-03-02 22:41 UTC (permalink / raw)
  To: Dmitry Torokhov, Anatol Pomazau, Jonathan Richardson,
	Scott Branden, Ray Jui, Rob Herring, Pawel Moll, Mark Rutland,
	Ian Campbell, Kumar Gala, Russell King
  Cc: devicetree, linux-arm-kernel, linux-kernel, bcm-kernel-feedback-list

This patchset adds a DTS file to enable the BCM58305 Wireless Audio reference
design based on Cygnus. It will be kept up to date as Cygnus drivers are
accepted into the mainline.

Jonathan Richardson (1):
  ARM: dts: Enable Broadcom Cygnus BCM958305K

 arch/arm/boot/dts/Makefile       |    3 ++-
 arch/arm/boot/dts/bcm958305k.dts |   53 ++++++++++++++++++++++++++++++++++++++
 2 files changed, 55 insertions(+), 1 deletion(-)
 create mode 100644 arch/arm/boot/dts/bcm958305k.dts

-- 
1.7.9.5


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

* [PATCH RESEND 1/1] ARM: dts: Enable Broadcom Cygnus BCM958305K
  2015-03-02 22:41 ` [PATCH RESEND 0/1] Enable Broadcom Cygnus BCM958305K Jonathan Richardson
@ 2015-03-02 22:41   ` Jonathan Richardson
  2015-03-02 23:45     ` Florian Fainelli
  0 siblings, 1 reply; 92+ messages in thread
From: Jonathan Richardson @ 2015-03-02 22:41 UTC (permalink / raw)
  To: Dmitry Torokhov, Anatol Pomazau, Jonathan Richardson,
	Scott Branden, Ray Jui, Rob Herring, Pawel Moll, Mark Rutland,
	Ian Campbell, Kumar Gala, Russell King
  Cc: devicetree, linux-arm-kernel, linux-kernel, bcm-kernel-feedback-list

DT file to enable the Wireless Audio reference design based on the
BCM58305.

Reviewed-by: Ray Jui <rjui@broadcom.com>
Reviewed-by: Scott Branden <sbranden@broadcom.com>
Tested-by: Scott Branden <sbranden@broadcom.com>
Signed-off-by: Jonathan Richardson <jonathar@broadcom.com>
---
 arch/arm/boot/dts/Makefile       |    3 ++-
 arch/arm/boot/dts/bcm958305k.dts |   53 ++++++++++++++++++++++++++++++++++++++
 2 files changed, 55 insertions(+), 1 deletion(-)
 create mode 100644 arch/arm/boot/dts/bcm958305k.dts

diff --git a/arch/arm/boot/dts/Makefile b/arch/arm/boot/dts/Makefile
index 91bd5bd..24b6084 100644
--- a/arch/arm/boot/dts/Makefile
+++ b/arch/arm/boot/dts/Makefile
@@ -64,7 +64,8 @@ dtb-$(CONFIG_ARCH_BCM_5301X) += \
 dtb-$(CONFIG_ARCH_BCM_63XX) += bcm963138dvt.dtb
 dtb-$(CONFIG_ARCH_BCM_CYGNUS) += bcm911360_entphn.dtb \
 	bcm911360k.dtb \
-	bcm958300k.dtb
+	bcm958300k.dtb \
+	bcm958305k.dtb
 dtb-$(CONFIG_ARCH_BCM_MOBILE) += bcm28155-ap.dtb \
 	bcm21664-garnet.dtb
 dtb-$(CONFIG_ARCH_BERLIN) += \
diff --git a/arch/arm/boot/dts/bcm958305k.dts b/arch/arm/boot/dts/bcm958305k.dts
new file mode 100644
index 0000000..56b429a
--- /dev/null
+++ b/arch/arm/boot/dts/bcm958305k.dts
@@ -0,0 +1,53 @@
+/*
+ *  BSD LICENSE
+ *
+ *  Copyright(c) 2015 Broadcom Corporation.  All rights reserved.
+ *
+ *  Redistribution and use in source and binary forms, with or without
+ *  modification, are permitted provided that the following conditions
+ *  are met:
+ *
+ *    * Redistributions of source code must retain the above copyright
+ *      notice, this list of conditions and the following disclaimer.
+ *    * Redistributions in binary form must reproduce the above copyright
+ *      notice, this list of conditions and the following disclaimer in
+ *      the documentation and/or other materials provided with the
+ *      distribution.
+ *    * Neither the name of Broadcom Corporation nor the names of its
+ *      contributors may be used to endorse or promote products derived
+ *      from this software without specific prior written permission.
+ *
+ *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ *  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ *  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ *  A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ *  OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ *  SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ *  LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ *  DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ *  THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ *  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/dts-v1/;
+
+#include "bcm-cygnus.dtsi"
+
+/ {
+	model = "Cygnus Wireless Audio (BCM958305K)";
+	compatible = "brcm,bcm58305", "brcm,cygnus";
+
+	aliases {
+		serial0 = &uart3;
+	};
+
+	chosen {
+		stdout-path = &uart3;
+		bootargs = "console=ttyS0,115200";
+	};
+
+	uart3: serial@18023000 {
+		status = "okay";
+	};
+};
-- 
1.7.9.5


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

* Re: [PATCH RESEND 1/1] ARM: dts: Enable Broadcom Cygnus BCM958305K
  2015-03-02 22:41   ` [PATCH RESEND 1/1] ARM: dts: " Jonathan Richardson
@ 2015-03-02 23:45     ` Florian Fainelli
  0 siblings, 0 replies; 92+ messages in thread
From: Florian Fainelli @ 2015-03-02 23:45 UTC (permalink / raw)
  To: Jonathan Richardson, Dmitry Torokhov, Anatol Pomazau,
	Scott Branden, Ray Jui, Rob Herring, Pawel Moll, Mark Rutland,
	Ian Campbell, Kumar Gala, Russell King
  Cc: devicetree, linux-arm-kernel, linux-kernel, bcm-kernel-feedback-list

On 02/03/15 14:41, Jonathan Richardson wrote:
> DT file to enable the Wireless Audio reference design based on the
> BCM58305.
> 
> Reviewed-by: Ray Jui <rjui@broadcom.com>
> Reviewed-by: Scott Branden <sbranden@broadcom.com>
> Tested-by: Scott Branden <sbranden@broadcom.com>
> Signed-off-by: Jonathan Richardson <jonathar@broadcom.com>

Applied to devicetree/next at github.com/stblinux, thanks!
-- 
Florian

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

* Re: [PATCH v2 1/1] serial: 8250_dw: Fix get_mctrl behaviour
  2015-02-27  0:35   ` [PATCH v2 1/1] serial: 8250_dw: Fix get_mctrl behaviour Jonathan Richardson
@ 2015-03-09 18:40     ` Dmitry Torokhov
  2015-03-09 18:51       ` Jonathan Richardson
  0 siblings, 1 reply; 92+ messages in thread
From: Dmitry Torokhov @ 2015-03-09 18:40 UTC (permalink / raw)
  To: Jonathan Richardson
  Cc: Anatol Pomazau, Scott Branden, Rob Herring, Pawel Moll,
	Mark Rutland, Ian Campbell, Kumar Gala, Greg Kroah-Hartman,
	Jiri Slaby, devicetree, linux-kernel, linux-serial,
	Arnd Bergmann, Desmond Liu

On Thu, Feb 26, 2015 at 4:35 PM, Jonathan Richardson
<jonathar@broadcom.com> wrote:
> @@ -334,6 +342,30 @@ static int dw8250_probe_of(struct uart_port *p,
>         if (id >= 0)
>                 p->line = id;
>
> +       if (of_property_read_bool(np, "dcd-override")) {
> +               /* Always report DCD as active */
> +               data->msr_mask_on |= UART_MSR_DCD;
> +               data->msr_mask_off |= UART_MSR_DDCD;
> +       }
> +
> +       if (of_property_read_bool(np, "dsr-override")) {
> +               /* Always report DSR as active */
> +               data->msr_mask_on |= UART_MSR_DSR;
> +               data->msr_mask_off |= UART_MSR_DDSR;
> +       }
> +
> +       if (of_property_read_bool(np, "cts-override")) {
> +               /* Always report DSR as active */
> +               data->msr_mask_on |= UART_MSR_DSR;
> +               data->msr_mask_off |= UART_MSR_DDSR;
> +       }
> +
> +       if (of_property_read_bool(np, "ri-override")) {
> +               /* Always report Ring indicator as inactive */
> +               data->msr_mask_off |= UART_MSR_RI;
> +               data->msr_mask_off |= UART_MSR_TERI;

This looks like a typo. Should the 1st line be data->msr_mask_on by any chance?

Thanks,
Dmitry

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

* Re: [PATCH v2 1/1] serial: 8250_dw: Fix get_mctrl behaviour
  2015-03-09 18:40     ` Dmitry Torokhov
@ 2015-03-09 18:51       ` Jonathan Richardson
  0 siblings, 0 replies; 92+ messages in thread
From: Jonathan Richardson @ 2015-03-09 18:51 UTC (permalink / raw)
  To: Dmitry Torokhov
  Cc: Anatol Pomazau, Scott Branden, Rob Herring, Pawel Moll,
	Mark Rutland, Ian Campbell, Kumar Gala, Greg Kroah-Hartman,
	Jiri Slaby, devicetree, linux-kernel, linux-serial,
	Arnd Bergmann, Desmond Liu

On 15-03-09 11:40 AM, Dmitry Torokhov wrote:
> On Thu, Feb 26, 2015 at 4:35 PM, Jonathan Richardson
> <jonathar@broadcom.com> wrote:
>> @@ -334,6 +342,30 @@ static int dw8250_probe_of(struct uart_port *p,
>>         if (id >= 0)
>>                 p->line = id;
>>
>> +       if (of_property_read_bool(np, "dcd-override")) {
>> +               /* Always report DCD as active */
>> +               data->msr_mask_on |= UART_MSR_DCD;
>> +               data->msr_mask_off |= UART_MSR_DDCD;
>> +       }
>> +
>> +       if (of_property_read_bool(np, "dsr-override")) {
>> +               /* Always report DSR as active */
>> +               data->msr_mask_on |= UART_MSR_DSR;
>> +               data->msr_mask_off |= UART_MSR_DDSR;
>> +       }
>> +
>> +       if (of_property_read_bool(np, "cts-override")) {
>> +               /* Always report DSR as active */
>> +               data->msr_mask_on |= UART_MSR_DSR;
>> +               data->msr_mask_off |= UART_MSR_DDSR;
>> +       }
>> +
>> +       if (of_property_read_bool(np, "ri-override")) {
>> +               /* Always report Ring indicator as inactive */
>> +               data->msr_mask_off |= UART_MSR_RI;
>> +               data->msr_mask_off |= UART_MSR_TERI;
> 
> This looks like a typo. Should the 1st line be data->msr_mask_on by any chance?

I think the code is correct. The signals other than ri need to be
reported as active (masked on) if specified, but ri needs to be inactive
(masked off) unlike the other 3. This is stated in the kernel docs
mentioned in the commit. ri behaves differently than the others.

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


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

* [PATCH v3 0/2] Add support for Broadcom iProc touchscreen
       [not found] <Jonathan Richardson <jonathar@broadcom.com>
                   ` (11 preceding siblings ...)
  2015-03-02 22:41 ` [PATCH RESEND 0/1] Enable Broadcom Cygnus BCM958305K Jonathan Richardson
@ 2015-03-11  1:17 ` Jonathan Richardson
  2015-03-11  1:17   ` [PATCH v3 1/2] Input: touchscreen-iproc: Add Broadcom iProc touchscreen driver Jonathan Richardson
  2015-03-11  1:17   ` [PATCH v3 2/2] Input: touchscreen-iproc: add device tree bindings Jonathan Richardson
  2015-03-12 17:45 ` [PATCH v4 0/2] Add support for Broadcom iProc touchscreen Jonathan Richardson
  13 siblings, 2 replies; 92+ messages in thread
From: Jonathan Richardson @ 2015-03-11  1:17 UTC (permalink / raw)
  To: Dmitry Torokhov, Anatol Pomazau
  Cc: Jonathan Richardson, Scott Branden, Grant Likely, Rob Herring,
	Ray Jui, linux-kernel, linux-input, bcm-kernel-feedback-list,
	devicetree, Joe Perches, Pawel Moll, Mark Rutland, Ian Campbell,
	Kumar Gala

This patchset contains initial support for the touchscreen on the Broadcom
iProc family of SoCs. This driver has been validated with Cygnus and is expected
to work on other iProc family of SoCs that use the same touchscreen controller.

Changes from v2:
- Misc style changes.
- Removed assumptions about interrupts generated in ISR. It now emits all
  events and then syncs if necessary.
- Removed our rotation property and replaced with the latest
  touchscreen-inverted-x/y. Also added support for the standard optional
  properties touchscreen-size-x/y and touchscreen-fuzz-x/y. Did not add support
  for inverted-x/y at this time as our touchscreen is currently only oriented
  180 degres.

Changes from v1:
- Add missing newlines to debug messages
- Use BIT macro for defines
- Fix logic in get_tsc_config to improve readability
- Get rid of unnecessary remove() function

Jonathan Richardson (2):
  Input: touchscreen-iproc: Add Broadcom iProc touchscreen driver
  Input: touchscreen-iproc: add device tree bindings

 .../input/touchscreen/brcm,iproc-touchscreen.txt   |   76 +++
 drivers/input/touchscreen/Kconfig                  |   11 +
 drivers/input/touchscreen/Makefile                 |    1 +
 drivers/input/touchscreen/bcm_iproc_tsc.c          |  527 ++++++++++++++++++++
 4 files changed, 615 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/input/touchscreen/brcm,iproc-touchscreen.txt
 create mode 100644 drivers/input/touchscreen/bcm_iproc_tsc.c

-- 
1.7.9.5


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

* [PATCH v3 1/2] Input: touchscreen-iproc: Add Broadcom iProc touchscreen driver
  2015-03-11  1:17 ` [PATCH v3 0/2] Add support for Broadcom iProc touchscreen Jonathan Richardson
@ 2015-03-11  1:17   ` Jonathan Richardson
  2015-03-11  9:46     ` Paul Bolle
  2015-03-11  1:17   ` [PATCH v3 2/2] Input: touchscreen-iproc: add device tree bindings Jonathan Richardson
  1 sibling, 1 reply; 92+ messages in thread
From: Jonathan Richardson @ 2015-03-11  1:17 UTC (permalink / raw)
  To: Dmitry Torokhov, Anatol Pomazau
  Cc: Jonathan Richardson, Scott Branden, Grant Likely, Rob Herring,
	Ray Jui, linux-kernel, linux-input, bcm-kernel-feedback-list,
	devicetree, Joe Perches, Pawel Moll, Mark Rutland, Ian Campbell,
	Kumar Gala

Add initial version of the Broadcom touchscreen driver.

Reviewed-by: Ray Jui <rjui@broadcom.com>
Reviewed-by: Scott Branden <sbranden@broadcom.com>
Tested-by: Scott Branden <sbranden@broadcom.com>
Signed-off-by: Jonathan Richardson <jonathar@broadcom.com>
---
 drivers/input/touchscreen/Kconfig         |   11 +
 drivers/input/touchscreen/Makefile        |    1 +
 drivers/input/touchscreen/bcm_iproc_tsc.c |  527 +++++++++++++++++++++++++++++
 3 files changed, 539 insertions(+)
 create mode 100644 drivers/input/touchscreen/bcm_iproc_tsc.c

diff --git a/drivers/input/touchscreen/Kconfig b/drivers/input/touchscreen/Kconfig
index 5891752..1290486 100644
--- a/drivers/input/touchscreen/Kconfig
+++ b/drivers/input/touchscreen/Kconfig
@@ -323,6 +323,17 @@ config TOUCHSCREEN_ILI210X
 	  To compile this driver as a module, choose M here: the
 	  module will be called ili210x.
 
+config TOUCHSCREEN_IPROC
+	tristate "IPROC touch panel driver support"
+	help
+	  Say Y here if you want to add support for the IPROC touch
+	  controller to your system.
+
+	  If unsure, say N.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called iproc-ts.
+
 config TOUCHSCREEN_S3C2410
 	tristate "Samsung S3C2410/generic touchscreen input driver"
 	depends on ARCH_S3C24XX || SAMSUNG_DEV_TS
diff --git a/drivers/input/touchscreen/Makefile b/drivers/input/touchscreen/Makefile
index 0242fea..68f69bc 100644
--- a/drivers/input/touchscreen/Makefile
+++ b/drivers/input/touchscreen/Makefile
@@ -39,6 +39,7 @@ obj-$(CONFIG_TOUCHSCREEN_GOODIX)	+= goodix.o
 obj-$(CONFIG_TOUCHSCREEN_ILI210X)	+= ili210x.o
 obj-$(CONFIG_TOUCHSCREEN_INEXIO)	+= inexio.o
 obj-$(CONFIG_TOUCHSCREEN_INTEL_MID)	+= intel-mid-touch.o
+obj-$(CONFIG_TOUCHSCREEN_IPROC)		+= bcm_iproc_tsc.o
 obj-$(CONFIG_TOUCHSCREEN_LPC32XX)	+= lpc32xx_ts.o
 obj-$(CONFIG_TOUCHSCREEN_MAX11801)	+= max11801_ts.o
 obj-$(CONFIG_TOUCHSCREEN_MC13783)	+= mc13783_ts.o
diff --git a/drivers/input/touchscreen/bcm_iproc_tsc.c b/drivers/input/touchscreen/bcm_iproc_tsc.c
new file mode 100644
index 0000000..54c4dd1
--- /dev/null
+++ b/drivers/input/touchscreen/bcm_iproc_tsc.c
@@ -0,0 +1,527 @@
+/*
+* Copyright (C) 2015 Broadcom Corporation
+*
+* This program is free software; you can redistribute it and/or
+* modify it under the terms of the GNU General Public License as
+* published by the Free Software Foundation version 2.
+*
+* This program is distributed "as is" WITHOUT ANY WARRANTY of any
+* kind, whether express or implied; without even the implied warranty
+* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*/
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/input.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/keyboard.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/of.h>
+#include <asm/irq.h>
+#include <linux/io.h>
+#include <linux/clk.h>
+#include <linux/serio.h>
+
+#define IPROC_TS_NAME "iproc-ts"
+
+#define PEN_DOWN_STATUS     1
+#define PEN_UP_STATUS       0
+
+#define X_MIN               0
+#define Y_MIN               0
+#define X_MAX               0xFFF
+#define Y_MAX               0xFFF
+
+/* Value given by controller for invalid coordinate. */
+#define INVALID_COORD       0xFFFFFFFF
+
+/* Register offsets */
+#define REGCTL1             0x00
+#define REGCTL2             0x04
+#define INTERRUPT_THRES     0x08
+#define INTERRUPT_MASK      0x0c
+
+#define INTERRUPT_STATUS    0x10
+#define CONTROLLER_STATUS   0x14
+#define FIFO_DATA           0x18
+#define FIFO_DATA_X_Y_MASK  0xFFFF
+#define ANALOG_CONTROL      0x1c
+
+#define AUX_DATA            0x20
+#define DEBOUNCE_CNTR_STAT  0x24
+#define SCAN_CNTR_STAT      0x28
+#define REM_CNTR_STAT       0x2c
+
+#define SETTLING_TIMER_STAT 0x30
+#define SPARE_REG           0x34
+#define SOFT_BYPASS_CONTROL 0x38
+#define SOFT_BYPASS_DATA    0x3c
+
+
+/* Bit values for INTERRUPT_MASK and INTERRUPT_STATUS regs */
+#define TS_PEN_INTR_MASK        BIT(0)
+#define TS_FIFO_INTR_MASK       BIT(2)
+
+/* Bit values for CONTROLLER_STATUS reg1 */
+#define TS_PEN_DOWN             BIT(0)
+
+/* Shift values for control reg1 */
+#define SCANNING_PERIOD_SHIFT   24
+#define DEBOUNCE_TIMEOUT_SHIFT  16
+#define SETTLING_TIMEOUT_SHIFT  8
+#define TOUCH_TIMEOUT_SHIFT     0
+
+/* Shift values for coordinates from fifo */
+#define X_COORD_SHIFT  0
+#define Y_COORD_SHIFT  16
+
+/* Bit values for REGCTL2 */
+#define TS_CONTROLLER_EN_BIT    BIT(16)
+#define TS_CONTROLLER_AVGDATA_SHIFT 8
+#define TS_CONTROLLER_AVGDATA_MASK (0x7 << TS_CONTROLLER_AVGDATA_SHIFT)
+#define TS_CONTROLLER_PWR_LDO   BIT(5)
+#define TS_CONTROLLER_PWR_ADC   BIT(4)
+#define TS_CONTROLLER_PWR_BGP   BIT(3)
+#define TS_CONTROLLER_PWR_TS    BIT(2)
+#define TS_WIRE_MODE_BIT        BIT(1)
+
+struct tsc_param {
+	/* Each step is 1024 us.  Valid 1-256 */
+	u32 scanning_period;
+
+	/*  Each step is 512 us.  Valid 0-255 */
+	u32 debounce_timeout;
+
+	/*
+	 * The settling duration (in ms) is the amount of time the tsc
+	 * waits to allow the voltage to settle after turning on the
+	 * drivers in detection mode. Valid values: 0-11
+	 *   0 =  0.008 ms
+	 *   1 =  0.01 ms
+	 *   2 =  0.02 ms
+	 *   3 =  0.04 ms
+	 *   4 =  0.08 ms
+	 *   5 =  0.16 ms
+	 *   6 =  0.32 ms
+	 *   7 =  0.64 ms
+	 *   8 =  1.28 ms
+	 *   9 =  2.56 ms
+	 *   10 = 5.12 ms
+	 *   11 = 10.24 ms
+	 */
+	u32 settling_timeout;
+
+	/* touch timeout in sample counts */
+	u32 touch_timeout;
+
+	/*
+	 * Number of data samples which are averaged before a final data point
+	 * is placed into the FIFO
+	 */
+	u32 average_data;
+
+	/* FIFO threshold */
+	u32 fifo_threshold;
+
+	/* Optional standard touchscreen properties. */
+	u32 max_x;
+	u32 max_y;
+	u32 fuzz_x;
+	u32 fuzz_y;
+	bool invert_x;
+	bool invert_y;
+};
+
+struct iproc_ts_priv {
+	struct platform_device *pdev;
+	struct input_dev *idev;
+
+	void __iomem *regs;
+	struct clk *tsc_clk;
+
+	int  pen_status;
+	struct tsc_param cfg_params;
+};
+
+/*
+ * Set default values the same as hardware reset values
+ * except for fifo_threshold with is set to 1.
+ */
+static struct tsc_param default_config = {
+	.scanning_period  = 0x5,  /* 1 to 256 */
+	.debounce_timeout = 0x28, /* 0 to 255 */
+	.settling_timeout = 0x7,  /* 0 to 11 */
+	.touch_timeout    = 0xa,  /* 0 to 255 */
+	.average_data     = 5,    /* entry 5 = 32 pts */
+	.fifo_threshold   = 1,    /* 0 to 31 */
+	.max_x            = X_MAX,
+	.max_y            = Y_MAX,
+};
+
+static void ts_reg_dump(struct iproc_ts_priv *priv)
+{
+	struct device *dev = &priv->pdev->dev;
+
+	dev_dbg(dev, "regCtl1             = 0x%08x\n",
+				readl(priv->regs + REGCTL1));
+	dev_dbg(dev, "regCtl2             = 0x%08x\n",
+				readl(priv->regs + REGCTL2));
+	dev_dbg(dev, "interrupt_Thres     = 0x%08x\n",
+				readl(priv->regs + INTERRUPT_THRES));
+	dev_dbg(dev, "interrupt_Mask      = 0x%08x\n",
+				readl(priv->regs + INTERRUPT_MASK));
+	dev_dbg(dev, "interrupt_Status    = 0x%08x\n",
+				readl(priv->regs + INTERRUPT_STATUS));
+	dev_dbg(dev, "controller_Status   = 0x%08x\n",
+				readl(priv->regs + CONTROLLER_STATUS));
+	dev_dbg(dev, "FIFO_Data           = 0x%08x\n",
+				readl(priv->regs + FIFO_DATA));
+	dev_dbg(dev, "analog_Control      = 0x%08x\n",
+				readl(priv->regs + ANALOG_CONTROL));
+	dev_dbg(dev, "aux_Data            = 0x%08x\n",
+				readl(priv->regs + AUX_DATA));
+	dev_dbg(dev, "debounce_Cntr_Stat  = 0x%08x\n",
+				readl(priv->regs + DEBOUNCE_CNTR_STAT));
+	dev_dbg(dev, "scan_Cntr_Stat      = 0x%08x\n",
+				readl(priv->regs + SCAN_CNTR_STAT));
+	dev_dbg(dev, "rem_Cntr_Stat       = 0x%08x\n",
+				readl(priv->regs + REM_CNTR_STAT));
+	dev_dbg(dev, "settling_Timer_Stat = 0x%08x\n",
+				readl(priv->regs + SETTLING_TIMER_STAT));
+	dev_dbg(dev, "spare_Reg           = 0x%08x\n",
+				readl(priv->regs + SPARE_REG));
+	dev_dbg(dev, "soft_Bypass_Control = 0x%08x\n",
+				readl(priv->regs + SOFT_BYPASS_CONTROL));
+	dev_dbg(dev, "soft_Bypass_Data    = 0x%08x\n",
+				readl(priv->regs + SOFT_BYPASS_DATA));
+}
+
+static irqreturn_t iproc_touchscreen_interrupt(int irq, void *data)
+{
+	struct platform_device *pdev = data;
+	struct iproc_ts_priv *priv = platform_get_drvdata(pdev);
+	u32 intr_status;
+	u32 raw_coordinate;
+	u16 x;
+	u16 y;
+	int i;
+	bool needs_sync = false;
+
+	intr_status = readl(priv->regs + INTERRUPT_STATUS);
+	intr_status &= (TS_PEN_INTR_MASK | TS_FIFO_INTR_MASK);
+	if (intr_status == 0)
+		return IRQ_NONE;
+
+	/* Clear all interrupt status bits, write-1-clear */
+	writel(intr_status, priv->regs + INTERRUPT_STATUS);
+
+	/* Pen up/down */
+	if (intr_status & TS_PEN_INTR_MASK) {
+		if (readl(priv->regs + CONTROLLER_STATUS) & TS_PEN_DOWN)
+			priv->pen_status = PEN_DOWN_STATUS;
+		else
+			priv->pen_status = PEN_UP_STATUS;
+
+		input_report_key(priv->idev, BTN_TOUCH,	priv->pen_status);
+		needs_sync = true;
+
+		dev_dbg(&priv->pdev->dev,
+			"pen up-down (%d)\n", priv->pen_status);
+	}
+
+	/* coordinates in FIFO exceed the theshold */
+	if (intr_status & TS_FIFO_INTR_MASK) {
+		for (i = 0; i < priv->cfg_params.fifo_threshold; i++) {
+			raw_coordinate = readl(priv->regs + FIFO_DATA);
+			if (raw_coordinate == INVALID_COORD)
+				continue;
+
+			/*
+			 * The x and y coordinate are 16 bits each
+			 * with the x in the lower 16 bits and y in the
+			 * upper 16 bits.
+			 */
+			x = (raw_coordinate >> X_COORD_SHIFT) &
+				FIFO_DATA_X_Y_MASK;
+			y = (raw_coordinate >> Y_COORD_SHIFT) &
+				FIFO_DATA_X_Y_MASK;
+
+			/* We only want to retain the 12 msb of the 16 */
+			x = (x >> 4) & 0x0FFF;
+			y = (y >> 4) & 0x0FFF;
+
+			/* adjust x y according to lcd tsc mount angle */
+			if (priv->cfg_params.invert_x)
+				x = priv->cfg_params.max_x - x;
+
+			if (priv->cfg_params.invert_y)
+				y = priv->cfg_params.max_y - y;
+
+			input_report_abs(priv->idev, ABS_X, x);
+			input_report_abs(priv->idev, ABS_Y, y);
+			needs_sync = true;
+
+			dev_dbg(&priv->pdev->dev, "xy (0x%x 0x%x)\n", x, y);
+		}
+	}
+
+	if (needs_sync)
+		input_sync(priv->idev);
+
+	return IRQ_HANDLED;
+}
+
+static int iproc_ts_start(struct input_dev *idev)
+{
+	u32 val;
+	int ret;
+	struct iproc_ts_priv *priv = input_get_drvdata(idev);
+
+	/* Enable clock */
+	ret = clk_prepare_enable(priv->tsc_clk);
+	if (ret) {
+		dev_err(&priv->pdev->dev, "%s clk_prepare_enable failed %d\n",
+			__func__, ret);
+		return ret;
+	}
+
+	/*
+	 * Interrupt is generated when:
+	 *  FIFO reaches the int_th value, and pen event(up/down)
+	 */
+	val = TS_PEN_INTR_MASK | TS_FIFO_INTR_MASK;
+	writel(val, priv->regs + INTERRUPT_MASK);
+
+	writel(priv->cfg_params.fifo_threshold, priv->regs + INTERRUPT_THRES);
+
+	/* Initialize control reg1 */
+	val = 0;
+	val |= priv->cfg_params.scanning_period << SCANNING_PERIOD_SHIFT;
+	val |= priv->cfg_params.debounce_timeout << DEBOUNCE_TIMEOUT_SHIFT;
+	val |= priv->cfg_params.settling_timeout << SETTLING_TIMEOUT_SHIFT;
+	val |= priv->cfg_params.touch_timeout << TOUCH_TIMEOUT_SHIFT;
+	writel(val, priv->regs + REGCTL1);
+
+	/* Try to clear all interrupt status */
+	val = readl(priv->regs + INTERRUPT_STATUS);
+	val |= TS_FIFO_INTR_MASK | TS_PEN_INTR_MASK;
+	writel(val, priv->regs + INTERRUPT_STATUS);
+
+	/* Initialize control reg2 */
+	val = readl(priv->regs + REGCTL2);
+	val |= TS_CONTROLLER_EN_BIT | TS_WIRE_MODE_BIT;
+
+	val &= ~(TS_CONTROLLER_AVGDATA_MASK);
+	val |= priv->cfg_params.average_data << TS_CONTROLLER_AVGDATA_SHIFT;
+
+	val &= ~(TS_CONTROLLER_PWR_LDO |	/* PWR up LDO */
+		   TS_CONTROLLER_PWR_ADC |	/* PWR up ADC */
+		   TS_CONTROLLER_PWR_BGP |	/* PWR up BGP */
+		   TS_CONTROLLER_PWR_TS);	/* PWR up TS */
+
+	writel(val, priv->regs + REGCTL2);
+
+	ts_reg_dump(priv);
+
+	return 0;
+}
+
+static void iproc_ts_stop(struct input_dev *dev)
+{
+	u32 val;
+	struct iproc_ts_priv *priv = input_get_drvdata(dev);
+
+	writel(0, priv->regs + INTERRUPT_MASK); /* Disable all interrupts */
+
+	/* Only power down touch screen controller */
+	val = readl(priv->regs + REGCTL2);
+	val |= TS_CONTROLLER_PWR_TS;
+	writel(val, priv->regs + REGCTL2);
+
+	clk_disable(priv->tsc_clk);
+}
+
+static int get_tsc_config(struct device_node *np, struct iproc_ts_priv *priv)
+{
+	u32 val;
+	struct device *dev = &priv->pdev->dev;
+
+	priv->cfg_params = default_config;
+
+	if (of_property_read_u32(np, "scanning_period", &val) >= 0) {
+		if (val < 1 || val > 256) {
+			dev_err(dev, "scanning_period must be [1-256]\n");
+			return -EINVAL;
+		}
+		priv->cfg_params.scanning_period = val;
+	}
+
+	if (of_property_read_u32(np, "debounce_timeout", &val) >= 0) {
+		if (val < 0 || val > 255) {
+			dev_err(dev, "debounce_timeout must be [0-255]\n");
+			return -EINVAL;
+		}
+		priv->cfg_params.debounce_timeout = val;
+	}
+
+	if (of_property_read_u32(np, "settling_timeout", &val) >= 0) {
+		if (val < 0 || val > 11) {
+			dev_err(dev, "settling_timeout must be [0-11]\n");
+			return -EINVAL;
+		}
+		priv->cfg_params.settling_timeout = val;
+	}
+
+	if (of_property_read_u32(np, "touch_timeout", &val) >= 0) {
+		if (val < 0 || val > 255) {
+			dev_err(dev, "touch_timeout must be [0-255]\n");
+			return -EINVAL;
+		}
+		priv->cfg_params.touch_timeout = val;
+	}
+
+	if (of_property_read_u32(np, "average_data", &val) >= 0) {
+		if (val < 0 || val > 8) {
+			dev_err(dev, "average_data must be [0-8]\n");
+			return -EINVAL;
+		}
+		priv->cfg_params.average_data = val;
+	}
+
+	if (of_property_read_u32(np, "fifo_threshold", &val) >= 0) {
+		if (val < 0 || val > 31) {
+			dev_err(dev, "fifo_threshold must be [0-31]\n");
+			return -EINVAL;
+		}
+		priv->cfg_params.fifo_threshold = val;
+	}
+
+	/* Parse optional properties. */
+	of_property_read_u32(np, "touchscreen-size-x", &priv->cfg_params.max_x);
+	of_property_read_u32(np, "touchscreen-size-y", &priv->cfg_params.max_y);
+
+	of_property_read_u32(np, "touchscreen-fuzz-x",
+		&priv->cfg_params.fuzz_x);
+	of_property_read_u32(np, "touchscreen-fuzz-y",
+		&priv->cfg_params.fuzz_y);
+
+	priv->cfg_params.invert_x = of_property_read_bool(np,
+		"touchscreen-inverted-x");
+	priv->cfg_params.invert_y = of_property_read_bool(np,
+		"touchscreen-inverted-y");
+
+	return 0;
+}
+
+static int iproc_ts_probe(struct platform_device *pdev)
+{
+	struct iproc_ts_priv *priv;
+	struct input_dev *idev;
+	struct resource *res;
+	int ret;
+	int irq;
+
+	priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
+	if (!priv)
+		return -ENOMEM;
+
+	/* touchscreen controller memory mapped regs */
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	priv->regs = devm_ioremap_resource(&pdev->dev, res);
+	if (IS_ERR(priv->regs)) {
+		dev_err(&pdev->dev, "unable to map I/O memory\n");
+		return PTR_ERR(priv->regs);
+	}
+
+	priv->tsc_clk = devm_clk_get(&pdev->dev, "tsc_clk");
+	if (IS_ERR(priv->tsc_clk)) {
+		dev_err(&pdev->dev,
+			"%s Failed getting clock tsc_clk\n", __func__);
+		return PTR_ERR(priv->tsc_clk);
+	}
+
+	ret = get_tsc_config(pdev->dev.of_node, priv);
+	if (ret != 0) {
+		dev_err(&pdev->dev, "%s get_tsc_config failed\n", __func__);
+		return ret;
+	}
+
+	idev = devm_input_allocate_device(&pdev->dev);
+	if (!idev) {
+		dev_err(&pdev->dev,
+			"%s Allocate input device failed\n", __func__);
+		return -ENOMEM;
+	}
+
+	priv->idev = idev;
+	priv->pdev = pdev;
+
+	priv->pen_status = PEN_UP_STATUS;
+
+	/* Set input device info  */
+	idev->name = IPROC_TS_NAME;
+	idev->dev.parent = &pdev->dev;
+
+	idev->id.bustype = BUS_HOST;
+	idev->id.vendor = SERIO_UNKNOWN;
+	idev->id.product = 0;
+	idev->id.version = 0;
+
+	idev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS);
+	set_bit(BTN_TOUCH, idev->keybit);
+
+	input_set_abs_params(idev, ABS_X, X_MIN, priv->cfg_params.max_x,
+		priv->cfg_params.fuzz_x, 0);
+	input_set_abs_params(idev, ABS_Y, Y_MIN, priv->cfg_params.max_y,
+		priv->cfg_params.fuzz_y, 0);
+
+	idev->open = iproc_ts_start;
+	idev->close = iproc_ts_stop;
+
+	input_set_drvdata(idev, priv);
+	platform_set_drvdata(pdev, priv);
+
+	/* get interrupt */
+	irq = platform_get_irq(pdev, 0);
+	if (irq < 0) {
+		dev_err(&pdev->dev, "%s platform_get_irq failed\n", __func__);
+		return irq;
+	}
+
+	ret = devm_request_irq(&pdev->dev, irq,
+		iproc_touchscreen_interrupt,
+		IRQF_SHARED, IPROC_TS_NAME, pdev);
+	if (ret)
+		return ret;
+
+	ret = input_register_device(priv->idev);
+	if (ret) {
+		dev_err(&pdev->dev,
+			"%s register input device failed %d\n", __func__, ret);
+		return ret;
+	}
+
+	return 0;
+}
+
+static const struct of_device_id iproc_ts_of_match[] = {
+	{.compatible = "brcm,iproc-touchscreen", },
+	{ },
+};
+MODULE_DEVICE_TABLE(of, iproc_ts_of_match);
+
+static struct platform_driver iproc_ts_driver = {
+	.probe = iproc_ts_probe,
+	.driver = {
+		.name	= IPROC_TS_NAME,
+		.of_match_table = of_match_ptr(iproc_ts_of_match),
+	},
+};
+
+module_platform_driver(iproc_ts_driver);
+
+MODULE_DESCRIPTION("IPROC Touchscreen driver");
+MODULE_AUTHOR("Broadcom");
+MODULE_LICENSE("GPL v2");
-- 
1.7.9.5


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

* [PATCH v3 2/2] Input: touchscreen-iproc: add device tree bindings
  2015-03-11  1:17 ` [PATCH v3 0/2] Add support for Broadcom iProc touchscreen Jonathan Richardson
  2015-03-11  1:17   ` [PATCH v3 1/2] Input: touchscreen-iproc: Add Broadcom iProc touchscreen driver Jonathan Richardson
@ 2015-03-11  1:17   ` Jonathan Richardson
  1 sibling, 0 replies; 92+ messages in thread
From: Jonathan Richardson @ 2015-03-11  1:17 UTC (permalink / raw)
  To: Dmitry Torokhov, Anatol Pomazau
  Cc: Jonathan Richardson, Scott Branden, Grant Likely, Rob Herring,
	Ray Jui, linux-kernel, linux-input, bcm-kernel-feedback-list,
	devicetree, Joe Perches, Pawel Moll, Mark Rutland, Ian Campbell,
	Kumar Gala

Documents the touchscreen device tree binding for Broadcom iProc family
of SoCs.

Reviewed-by: Scott Branden <sbranden@broadcom.com>
Tested-by: Scott Branden <sbranden@broadcom.com>
Signed-off-by: Jonathan Richardson <jonathar@broadcom.com>
---
 .../input/touchscreen/brcm,iproc-touchscreen.txt   |   76 ++++++++++++++++++++
 1 file changed, 76 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/input/touchscreen/brcm,iproc-touchscreen.txt

diff --git a/Documentation/devicetree/bindings/input/touchscreen/brcm,iproc-touchscreen.txt b/Documentation/devicetree/bindings/input/touchscreen/brcm,iproc-touchscreen.txt
new file mode 100644
index 0000000..34e3382
--- /dev/null
+++ b/Documentation/devicetree/bindings/input/touchscreen/brcm,iproc-touchscreen.txt
@@ -0,0 +1,76 @@
+* Broadcom's IPROC Touchscreen Controller
+
+Required properties:
+- compatible: must be "brcm,iproc-touchscreen"
+- reg: physical base address of the controller and length of memory mapped
+  region.
+- clocks:  The clock provided by the SOC to driver the tsc
+- clock-name:  name for the clock
+- interrupts: The touchscreen controller's interrupt
+
+Optional properties:
+- scanning_period: Time between scans. Each step is 1024 us.  Valid 1-256.
+- debounce_timeout: Each step is 512 us.  Valid 0-255
+- settling_timeout: The settling duration (in ms) is the amount of time
+                    the tsc waits to allow the voltage to settle after
+                    turning on the drivers in detection mode.
+                    Valid values: 0-11
+                    0 =  0.008 ms
+                    1 =  0.01 ms
+                    2 =  0.02 ms
+                    3 =  0.04 ms
+                    4 =  0.08 ms
+                    5 =  0.16 ms
+                    6 =  0.32 ms
+                    7 =  0.64 ms
+                    8 =  1.28 ms
+                    9 =  2.56 ms
+                   10 =  5.12 ms
+                   11 = 10.24 ms
+- touch_timeout: The continuous number of scan periods in which touch is
+                not detected before the controller returns to idle state.
+                Valid values 0-255.
+- average_data: Number of data samples which are averaged before a final
+                data point is placed into the FIFO
+                Valid values 0-7
+                0 =   1 sample
+                1 =   2 samples
+                2 =   4 samples
+                3 =   8 samples
+                4 =  16 samples
+                5 =  32 samples
+                6 =  64 samples
+                7 = 128 samples
+- fifo_threshold: Interrupt is generated whenever the number of fifo
+                entries exceeds this value
+                Valid values 0-31
+- touchscreen-size-x: horizontal resolution of touchscreen (in pixels)
+- touchscreen-size-y: vertical resolution of touchscreen (in pixels)
+- touchscreen-fuzz-x: horizontal noise value of the absolute input
+                      device (in pixels)
+- touchscreen-fuzz-y: vertical noise value of the absolute input
+                      device (in pixels)
+- touchscreen-inverted-x: X axis is inverted (boolean)
+- touchscreen-inverted-y: Y axis is inverted (boolean)
+
+Example:
+
+	touchscreen: tsc@0x180A6000 {
+		compatible = "brcm,iproc-touchscreen";
+		#address-cells = <1>;
+		#size-cells = <1>;
+		reg = <0x180A6000 0x40>;
+		clocks = <&adc_clk>;
+		clock-names = "tsc_clk";
+		interrupts = <GIC_SPI 164 IRQ_TYPE_LEVEL_HIGH>;
+
+		scanning_period = <5>;
+		debounce_timeout = <40>;
+		settling_timeout = <7>;
+		touch_timeout = <10>;
+		average_data = <5>;
+		fifo_threshold = <1>;
+		/* Touchscreen is rotated 180 degrees. */
+		touchscreen-inverted-x;
+		touchscreen-inverted-y;
+	};
-- 
1.7.9.5


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

* Re: [PATCH v3 1/2] Input: touchscreen-iproc: Add Broadcom iProc touchscreen driver
  2015-03-11  1:17   ` [PATCH v3 1/2] Input: touchscreen-iproc: Add Broadcom iProc touchscreen driver Jonathan Richardson
@ 2015-03-11  9:46     ` Paul Bolle
  2015-03-11 17:05       ` Jonathan Richardson
  0 siblings, 1 reply; 92+ messages in thread
From: Paul Bolle @ 2015-03-11  9:46 UTC (permalink / raw)
  To: Jonathan Richardson
  Cc: Dmitry Torokhov, Anatol Pomazau, Scott Branden, Grant Likely,
	Rob Herring, Ray Jui, linux-kernel, linux-input,
	bcm-kernel-feedback-list, devicetree, Joe Perches, Pawel Moll,
	Mark Rutland, Ian Campbell, Kumar Gala

One nit is all I can report.

On Tue, 2015-03-10 at 18:17 -0700, Jonathan Richardson wrote:
> --- a/drivers/input/touchscreen/Kconfig
> +++ b/drivers/input/touchscreen/Kconfig
 
> +config TOUCHSCREEN_IPROC
> +	tristate "IPROC touch panel driver support"
> +	help
> +	  Say Y here if you want to add support for the IPROC touch
> +	  controller to your system.
> +
> +	  If unsure, say N.
> +
> +	  To compile this driver as a module, choose M here: the
> +	  module will be called iproc-ts.

The module will be called "bcm_iproc_tsc", won't it?

> --- a/drivers/input/touchscreen/Makefile
> +++ b/drivers/input/touchscreen/Makefile

> +obj-$(CONFIG_TOUCHSCREEN_IPROC)		+= bcm_iproc_tsc.o


Paul Bolle


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

* Re: [PATCH v3 1/2] Input: touchscreen-iproc: Add Broadcom iProc touchscreen driver
  2015-03-11  9:46     ` Paul Bolle
@ 2015-03-11 17:05       ` Jonathan Richardson
  0 siblings, 0 replies; 92+ messages in thread
From: Jonathan Richardson @ 2015-03-11 17:05 UTC (permalink / raw)
  To: Paul Bolle
  Cc: Dmitry Torokhov, Anatol Pomazau, Scott Branden, Grant Likely,
	Rob Herring, Ray Jui, linux-kernel, linux-input,
	bcm-kernel-feedback-list, devicetree, Joe Perches, Pawel Moll,
	Mark Rutland, Ian Campbell, Kumar Gala

Hi Paul,

Yes, I didn't notice that. I'll include it in the next patch. Thanks for
the review.

Jon

On 15-03-11 02:46 AM, Paul Bolle wrote:
> One nit is all I can report.
> 
> On Tue, 2015-03-10 at 18:17 -0700, Jonathan Richardson wrote:
>> --- a/drivers/input/touchscreen/Kconfig
>> +++ b/drivers/input/touchscreen/Kconfig
>  
>> +config TOUCHSCREEN_IPROC
>> +	tristate "IPROC touch panel driver support"
>> +	help
>> +	  Say Y here if you want to add support for the IPROC touch
>> +	  controller to your system.
>> +
>> +	  If unsure, say N.
>> +
>> +	  To compile this driver as a module, choose M here: the
>> +	  module will be called iproc-ts.
> 
> The module will be called "bcm_iproc_tsc", won't it?
> 
>> --- a/drivers/input/touchscreen/Makefile
>> +++ b/drivers/input/touchscreen/Makefile
> 
>> +obj-$(CONFIG_TOUCHSCREEN_IPROC)		+= bcm_iproc_tsc.o
> 
> 
> Paul Bolle
> 


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

* [PATCH v4 0/2] Add support for Broadcom iProc touchscreen
       [not found] <Jonathan Richardson <jonathar@broadcom.com>
                   ` (12 preceding siblings ...)
  2015-03-11  1:17 ` [PATCH v3 0/2] Add support for Broadcom iProc touchscreen Jonathan Richardson
@ 2015-03-12 17:45 ` Jonathan Richardson
  2015-03-12 17:45   ` [PATCH v4 1/2] Input: touchscreen-iproc: Add Broadcom iProc touchscreen driver Jonathan Richardson
  2015-03-12 17:45   ` [PATCH v4 2/2] Input: touchscreen-iproc: add device tree bindings Jonathan Richardson
  13 siblings, 2 replies; 92+ messages in thread
From: Jonathan Richardson @ 2015-03-12 17:45 UTC (permalink / raw)
  To: Dmitry Torokhov, Anatol Pomazau
  Cc: Jonathan Richardson, Scott Branden, Grant Likely, Rob Herring,
	Ray Jui, linux-kernel, linux-input, bcm-kernel-feedback-list,
	devicetree, Joe Perches, Pawel Moll, Mark Rutland, Ian Campbell,
	Kumar Gala

This patchset contains initial support for the touchscreen on the Broadcom
iProc family of SoCs. This driver has been validated with Cygnus and is expected
to work on other iProc family of SoCs that use the same touchscreen controller.

Changes from v3:
- Fixed typo in Kconfig.

Changes from v2:
- Misc style changes.
- Removed assumptions about interrupts generated in ISR. It now emits all
  events and then syncs if necessary.
- Removed our rotation property and replaced with the latest
  touchscreen-inverted-x/y. Also added support for the standard optional
  properties touchscreen-size-x/y and touchscreen-fuzz-x/y. Did not add support
  for inverted-x/y at this time as our touchscreen is currently only oriented
  180 degres.

Changes from v1:
- Add missing newlines to debug messages
- Use BIT macro for defines
- Fix logic in get_tsc_config to improve readability
- Get rid of unnecessary remove() function

Jonathan Richardson (2):
  Input: touchscreen-iproc: Add Broadcom iProc touchscreen driver
  Input: touchscreen-iproc: add device tree bindings

 .../input/touchscreen/brcm,iproc-touchscreen.txt   |   76 +++
 drivers/input/touchscreen/Kconfig                  |   11 +
 drivers/input/touchscreen/Makefile                 |    1 +
 drivers/input/touchscreen/bcm_iproc_tsc.c          |  527 ++++++++++++++++++++
 4 files changed, 615 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/input/touchscreen/brcm,iproc-touchscreen.txt
 create mode 100644 drivers/input/touchscreen/bcm_iproc_tsc.c

-- 
1.7.9.5


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

* [PATCH v4 1/2] Input: touchscreen-iproc: Add Broadcom iProc touchscreen driver
  2015-03-12 17:45 ` [PATCH v4 0/2] Add support for Broadcom iProc touchscreen Jonathan Richardson
@ 2015-03-12 17:45   ` Jonathan Richardson
  2015-03-12 17:59     ` Joe Perches
  2015-03-12 17:45   ` [PATCH v4 2/2] Input: touchscreen-iproc: add device tree bindings Jonathan Richardson
  1 sibling, 1 reply; 92+ messages in thread
From: Jonathan Richardson @ 2015-03-12 17:45 UTC (permalink / raw)
  To: Dmitry Torokhov, Anatol Pomazau
  Cc: Jonathan Richardson, Scott Branden, Grant Likely, Rob Herring,
	Ray Jui, linux-kernel, linux-input, bcm-kernel-feedback-list,
	devicetree, Joe Perches, Pawel Moll, Mark Rutland, Ian Campbell,
	Kumar Gala

Add initial version of the Broadcom touchscreen driver.

Reviewed-by: Ray Jui <rjui@broadcom.com>
Reviewed-by: Scott Branden <sbranden@broadcom.com>
Tested-by: Scott Branden <sbranden@broadcom.com>
Signed-off-by: Jonathan Richardson <jonathar@broadcom.com>
---
 drivers/input/touchscreen/Kconfig         |   11 +
 drivers/input/touchscreen/Makefile        |    1 +
 drivers/input/touchscreen/bcm_iproc_tsc.c |  527 +++++++++++++++++++++++++++++
 3 files changed, 539 insertions(+)
 create mode 100644 drivers/input/touchscreen/bcm_iproc_tsc.c

diff --git a/drivers/input/touchscreen/Kconfig b/drivers/input/touchscreen/Kconfig
index 6261fd6..4a8b0e5 100644
--- a/drivers/input/touchscreen/Kconfig
+++ b/drivers/input/touchscreen/Kconfig
@@ -323,6 +323,17 @@ config TOUCHSCREEN_ILI210X
 	  To compile this driver as a module, choose M here: the
 	  module will be called ili210x.
 
+config TOUCHSCREEN_IPROC
+	tristate "IPROC touch panel driver support"
+	help
+	  Say Y here if you want to add support for the IPROC touch
+	  controller to your system.
+
+	  If unsure, say N.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called bcm_iproc_tsc.
+
 config TOUCHSCREEN_S3C2410
 	tristate "Samsung S3C2410/generic touchscreen input driver"
 	depends on ARCH_S3C24XX || SAMSUNG_DEV_TS
diff --git a/drivers/input/touchscreen/Makefile b/drivers/input/touchscreen/Makefile
index 0242fea..68f69bc 100644
--- a/drivers/input/touchscreen/Makefile
+++ b/drivers/input/touchscreen/Makefile
@@ -39,6 +39,7 @@ obj-$(CONFIG_TOUCHSCREEN_GOODIX)	+= goodix.o
 obj-$(CONFIG_TOUCHSCREEN_ILI210X)	+= ili210x.o
 obj-$(CONFIG_TOUCHSCREEN_INEXIO)	+= inexio.o
 obj-$(CONFIG_TOUCHSCREEN_INTEL_MID)	+= intel-mid-touch.o
+obj-$(CONFIG_TOUCHSCREEN_IPROC)		+= bcm_iproc_tsc.o
 obj-$(CONFIG_TOUCHSCREEN_LPC32XX)	+= lpc32xx_ts.o
 obj-$(CONFIG_TOUCHSCREEN_MAX11801)	+= max11801_ts.o
 obj-$(CONFIG_TOUCHSCREEN_MC13783)	+= mc13783_ts.o
diff --git a/drivers/input/touchscreen/bcm_iproc_tsc.c b/drivers/input/touchscreen/bcm_iproc_tsc.c
new file mode 100644
index 0000000..54c4dd1
--- /dev/null
+++ b/drivers/input/touchscreen/bcm_iproc_tsc.c
@@ -0,0 +1,527 @@
+/*
+* Copyright (C) 2015 Broadcom Corporation
+*
+* This program is free software; you can redistribute it and/or
+* modify it under the terms of the GNU General Public License as
+* published by the Free Software Foundation version 2.
+*
+* This program is distributed "as is" WITHOUT ANY WARRANTY of any
+* kind, whether express or implied; without even the implied warranty
+* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*/
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/input.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/keyboard.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/of.h>
+#include <asm/irq.h>
+#include <linux/io.h>
+#include <linux/clk.h>
+#include <linux/serio.h>
+
+#define IPROC_TS_NAME "iproc-ts"
+
+#define PEN_DOWN_STATUS     1
+#define PEN_UP_STATUS       0
+
+#define X_MIN               0
+#define Y_MIN               0
+#define X_MAX               0xFFF
+#define Y_MAX               0xFFF
+
+/* Value given by controller for invalid coordinate. */
+#define INVALID_COORD       0xFFFFFFFF
+
+/* Register offsets */
+#define REGCTL1             0x00
+#define REGCTL2             0x04
+#define INTERRUPT_THRES     0x08
+#define INTERRUPT_MASK      0x0c
+
+#define INTERRUPT_STATUS    0x10
+#define CONTROLLER_STATUS   0x14
+#define FIFO_DATA           0x18
+#define FIFO_DATA_X_Y_MASK  0xFFFF
+#define ANALOG_CONTROL      0x1c
+
+#define AUX_DATA            0x20
+#define DEBOUNCE_CNTR_STAT  0x24
+#define SCAN_CNTR_STAT      0x28
+#define REM_CNTR_STAT       0x2c
+
+#define SETTLING_TIMER_STAT 0x30
+#define SPARE_REG           0x34
+#define SOFT_BYPASS_CONTROL 0x38
+#define SOFT_BYPASS_DATA    0x3c
+
+
+/* Bit values for INTERRUPT_MASK and INTERRUPT_STATUS regs */
+#define TS_PEN_INTR_MASK        BIT(0)
+#define TS_FIFO_INTR_MASK       BIT(2)
+
+/* Bit values for CONTROLLER_STATUS reg1 */
+#define TS_PEN_DOWN             BIT(0)
+
+/* Shift values for control reg1 */
+#define SCANNING_PERIOD_SHIFT   24
+#define DEBOUNCE_TIMEOUT_SHIFT  16
+#define SETTLING_TIMEOUT_SHIFT  8
+#define TOUCH_TIMEOUT_SHIFT     0
+
+/* Shift values for coordinates from fifo */
+#define X_COORD_SHIFT  0
+#define Y_COORD_SHIFT  16
+
+/* Bit values for REGCTL2 */
+#define TS_CONTROLLER_EN_BIT    BIT(16)
+#define TS_CONTROLLER_AVGDATA_SHIFT 8
+#define TS_CONTROLLER_AVGDATA_MASK (0x7 << TS_CONTROLLER_AVGDATA_SHIFT)
+#define TS_CONTROLLER_PWR_LDO   BIT(5)
+#define TS_CONTROLLER_PWR_ADC   BIT(4)
+#define TS_CONTROLLER_PWR_BGP   BIT(3)
+#define TS_CONTROLLER_PWR_TS    BIT(2)
+#define TS_WIRE_MODE_BIT        BIT(1)
+
+struct tsc_param {
+	/* Each step is 1024 us.  Valid 1-256 */
+	u32 scanning_period;
+
+	/*  Each step is 512 us.  Valid 0-255 */
+	u32 debounce_timeout;
+
+	/*
+	 * The settling duration (in ms) is the amount of time the tsc
+	 * waits to allow the voltage to settle after turning on the
+	 * drivers in detection mode. Valid values: 0-11
+	 *   0 =  0.008 ms
+	 *   1 =  0.01 ms
+	 *   2 =  0.02 ms
+	 *   3 =  0.04 ms
+	 *   4 =  0.08 ms
+	 *   5 =  0.16 ms
+	 *   6 =  0.32 ms
+	 *   7 =  0.64 ms
+	 *   8 =  1.28 ms
+	 *   9 =  2.56 ms
+	 *   10 = 5.12 ms
+	 *   11 = 10.24 ms
+	 */
+	u32 settling_timeout;
+
+	/* touch timeout in sample counts */
+	u32 touch_timeout;
+
+	/*
+	 * Number of data samples which are averaged before a final data point
+	 * is placed into the FIFO
+	 */
+	u32 average_data;
+
+	/* FIFO threshold */
+	u32 fifo_threshold;
+
+	/* Optional standard touchscreen properties. */
+	u32 max_x;
+	u32 max_y;
+	u32 fuzz_x;
+	u32 fuzz_y;
+	bool invert_x;
+	bool invert_y;
+};
+
+struct iproc_ts_priv {
+	struct platform_device *pdev;
+	struct input_dev *idev;
+
+	void __iomem *regs;
+	struct clk *tsc_clk;
+
+	int  pen_status;
+	struct tsc_param cfg_params;
+};
+
+/*
+ * Set default values the same as hardware reset values
+ * except for fifo_threshold with is set to 1.
+ */
+static struct tsc_param default_config = {
+	.scanning_period  = 0x5,  /* 1 to 256 */
+	.debounce_timeout = 0x28, /* 0 to 255 */
+	.settling_timeout = 0x7,  /* 0 to 11 */
+	.touch_timeout    = 0xa,  /* 0 to 255 */
+	.average_data     = 5,    /* entry 5 = 32 pts */
+	.fifo_threshold   = 1,    /* 0 to 31 */
+	.max_x            = X_MAX,
+	.max_y            = Y_MAX,
+};
+
+static void ts_reg_dump(struct iproc_ts_priv *priv)
+{
+	struct device *dev = &priv->pdev->dev;
+
+	dev_dbg(dev, "regCtl1             = 0x%08x\n",
+				readl(priv->regs + REGCTL1));
+	dev_dbg(dev, "regCtl2             = 0x%08x\n",
+				readl(priv->regs + REGCTL2));
+	dev_dbg(dev, "interrupt_Thres     = 0x%08x\n",
+				readl(priv->regs + INTERRUPT_THRES));
+	dev_dbg(dev, "interrupt_Mask      = 0x%08x\n",
+				readl(priv->regs + INTERRUPT_MASK));
+	dev_dbg(dev, "interrupt_Status    = 0x%08x\n",
+				readl(priv->regs + INTERRUPT_STATUS));
+	dev_dbg(dev, "controller_Status   = 0x%08x\n",
+				readl(priv->regs + CONTROLLER_STATUS));
+	dev_dbg(dev, "FIFO_Data           = 0x%08x\n",
+				readl(priv->regs + FIFO_DATA));
+	dev_dbg(dev, "analog_Control      = 0x%08x\n",
+				readl(priv->regs + ANALOG_CONTROL));
+	dev_dbg(dev, "aux_Data            = 0x%08x\n",
+				readl(priv->regs + AUX_DATA));
+	dev_dbg(dev, "debounce_Cntr_Stat  = 0x%08x\n",
+				readl(priv->regs + DEBOUNCE_CNTR_STAT));
+	dev_dbg(dev, "scan_Cntr_Stat      = 0x%08x\n",
+				readl(priv->regs + SCAN_CNTR_STAT));
+	dev_dbg(dev, "rem_Cntr_Stat       = 0x%08x\n",
+				readl(priv->regs + REM_CNTR_STAT));
+	dev_dbg(dev, "settling_Timer_Stat = 0x%08x\n",
+				readl(priv->regs + SETTLING_TIMER_STAT));
+	dev_dbg(dev, "spare_Reg           = 0x%08x\n",
+				readl(priv->regs + SPARE_REG));
+	dev_dbg(dev, "soft_Bypass_Control = 0x%08x\n",
+				readl(priv->regs + SOFT_BYPASS_CONTROL));
+	dev_dbg(dev, "soft_Bypass_Data    = 0x%08x\n",
+				readl(priv->regs + SOFT_BYPASS_DATA));
+}
+
+static irqreturn_t iproc_touchscreen_interrupt(int irq, void *data)
+{
+	struct platform_device *pdev = data;
+	struct iproc_ts_priv *priv = platform_get_drvdata(pdev);
+	u32 intr_status;
+	u32 raw_coordinate;
+	u16 x;
+	u16 y;
+	int i;
+	bool needs_sync = false;
+
+	intr_status = readl(priv->regs + INTERRUPT_STATUS);
+	intr_status &= (TS_PEN_INTR_MASK | TS_FIFO_INTR_MASK);
+	if (intr_status == 0)
+		return IRQ_NONE;
+
+	/* Clear all interrupt status bits, write-1-clear */
+	writel(intr_status, priv->regs + INTERRUPT_STATUS);
+
+	/* Pen up/down */
+	if (intr_status & TS_PEN_INTR_MASK) {
+		if (readl(priv->regs + CONTROLLER_STATUS) & TS_PEN_DOWN)
+			priv->pen_status = PEN_DOWN_STATUS;
+		else
+			priv->pen_status = PEN_UP_STATUS;
+
+		input_report_key(priv->idev, BTN_TOUCH,	priv->pen_status);
+		needs_sync = true;
+
+		dev_dbg(&priv->pdev->dev,
+			"pen up-down (%d)\n", priv->pen_status);
+	}
+
+	/* coordinates in FIFO exceed the theshold */
+	if (intr_status & TS_FIFO_INTR_MASK) {
+		for (i = 0; i < priv->cfg_params.fifo_threshold; i++) {
+			raw_coordinate = readl(priv->regs + FIFO_DATA);
+			if (raw_coordinate == INVALID_COORD)
+				continue;
+
+			/*
+			 * The x and y coordinate are 16 bits each
+			 * with the x in the lower 16 bits and y in the
+			 * upper 16 bits.
+			 */
+			x = (raw_coordinate >> X_COORD_SHIFT) &
+				FIFO_DATA_X_Y_MASK;
+			y = (raw_coordinate >> Y_COORD_SHIFT) &
+				FIFO_DATA_X_Y_MASK;
+
+			/* We only want to retain the 12 msb of the 16 */
+			x = (x >> 4) & 0x0FFF;
+			y = (y >> 4) & 0x0FFF;
+
+			/* adjust x y according to lcd tsc mount angle */
+			if (priv->cfg_params.invert_x)
+				x = priv->cfg_params.max_x - x;
+
+			if (priv->cfg_params.invert_y)
+				y = priv->cfg_params.max_y - y;
+
+			input_report_abs(priv->idev, ABS_X, x);
+			input_report_abs(priv->idev, ABS_Y, y);
+			needs_sync = true;
+
+			dev_dbg(&priv->pdev->dev, "xy (0x%x 0x%x)\n", x, y);
+		}
+	}
+
+	if (needs_sync)
+		input_sync(priv->idev);
+
+	return IRQ_HANDLED;
+}
+
+static int iproc_ts_start(struct input_dev *idev)
+{
+	u32 val;
+	int ret;
+	struct iproc_ts_priv *priv = input_get_drvdata(idev);
+
+	/* Enable clock */
+	ret = clk_prepare_enable(priv->tsc_clk);
+	if (ret) {
+		dev_err(&priv->pdev->dev, "%s clk_prepare_enable failed %d\n",
+			__func__, ret);
+		return ret;
+	}
+
+	/*
+	 * Interrupt is generated when:
+	 *  FIFO reaches the int_th value, and pen event(up/down)
+	 */
+	val = TS_PEN_INTR_MASK | TS_FIFO_INTR_MASK;
+	writel(val, priv->regs + INTERRUPT_MASK);
+
+	writel(priv->cfg_params.fifo_threshold, priv->regs + INTERRUPT_THRES);
+
+	/* Initialize control reg1 */
+	val = 0;
+	val |= priv->cfg_params.scanning_period << SCANNING_PERIOD_SHIFT;
+	val |= priv->cfg_params.debounce_timeout << DEBOUNCE_TIMEOUT_SHIFT;
+	val |= priv->cfg_params.settling_timeout << SETTLING_TIMEOUT_SHIFT;
+	val |= priv->cfg_params.touch_timeout << TOUCH_TIMEOUT_SHIFT;
+	writel(val, priv->regs + REGCTL1);
+
+	/* Try to clear all interrupt status */
+	val = readl(priv->regs + INTERRUPT_STATUS);
+	val |= TS_FIFO_INTR_MASK | TS_PEN_INTR_MASK;
+	writel(val, priv->regs + INTERRUPT_STATUS);
+
+	/* Initialize control reg2 */
+	val = readl(priv->regs + REGCTL2);
+	val |= TS_CONTROLLER_EN_BIT | TS_WIRE_MODE_BIT;
+
+	val &= ~(TS_CONTROLLER_AVGDATA_MASK);
+	val |= priv->cfg_params.average_data << TS_CONTROLLER_AVGDATA_SHIFT;
+
+	val &= ~(TS_CONTROLLER_PWR_LDO |	/* PWR up LDO */
+		   TS_CONTROLLER_PWR_ADC |	/* PWR up ADC */
+		   TS_CONTROLLER_PWR_BGP |	/* PWR up BGP */
+		   TS_CONTROLLER_PWR_TS);	/* PWR up TS */
+
+	writel(val, priv->regs + REGCTL2);
+
+	ts_reg_dump(priv);
+
+	return 0;
+}
+
+static void iproc_ts_stop(struct input_dev *dev)
+{
+	u32 val;
+	struct iproc_ts_priv *priv = input_get_drvdata(dev);
+
+	writel(0, priv->regs + INTERRUPT_MASK); /* Disable all interrupts */
+
+	/* Only power down touch screen controller */
+	val = readl(priv->regs + REGCTL2);
+	val |= TS_CONTROLLER_PWR_TS;
+	writel(val, priv->regs + REGCTL2);
+
+	clk_disable(priv->tsc_clk);
+}
+
+static int get_tsc_config(struct device_node *np, struct iproc_ts_priv *priv)
+{
+	u32 val;
+	struct device *dev = &priv->pdev->dev;
+
+	priv->cfg_params = default_config;
+
+	if (of_property_read_u32(np, "scanning_period", &val) >= 0) {
+		if (val < 1 || val > 256) {
+			dev_err(dev, "scanning_period must be [1-256]\n");
+			return -EINVAL;
+		}
+		priv->cfg_params.scanning_period = val;
+	}
+
+	if (of_property_read_u32(np, "debounce_timeout", &val) >= 0) {
+		if (val < 0 || val > 255) {
+			dev_err(dev, "debounce_timeout must be [0-255]\n");
+			return -EINVAL;
+		}
+		priv->cfg_params.debounce_timeout = val;
+	}
+
+	if (of_property_read_u32(np, "settling_timeout", &val) >= 0) {
+		if (val < 0 || val > 11) {
+			dev_err(dev, "settling_timeout must be [0-11]\n");
+			return -EINVAL;
+		}
+		priv->cfg_params.settling_timeout = val;
+	}
+
+	if (of_property_read_u32(np, "touch_timeout", &val) >= 0) {
+		if (val < 0 || val > 255) {
+			dev_err(dev, "touch_timeout must be [0-255]\n");
+			return -EINVAL;
+		}
+		priv->cfg_params.touch_timeout = val;
+	}
+
+	if (of_property_read_u32(np, "average_data", &val) >= 0) {
+		if (val < 0 || val > 8) {
+			dev_err(dev, "average_data must be [0-8]\n");
+			return -EINVAL;
+		}
+		priv->cfg_params.average_data = val;
+	}
+
+	if (of_property_read_u32(np, "fifo_threshold", &val) >= 0) {
+		if (val < 0 || val > 31) {
+			dev_err(dev, "fifo_threshold must be [0-31]\n");
+			return -EINVAL;
+		}
+		priv->cfg_params.fifo_threshold = val;
+	}
+
+	/* Parse optional properties. */
+	of_property_read_u32(np, "touchscreen-size-x", &priv->cfg_params.max_x);
+	of_property_read_u32(np, "touchscreen-size-y", &priv->cfg_params.max_y);
+
+	of_property_read_u32(np, "touchscreen-fuzz-x",
+		&priv->cfg_params.fuzz_x);
+	of_property_read_u32(np, "touchscreen-fuzz-y",
+		&priv->cfg_params.fuzz_y);
+
+	priv->cfg_params.invert_x = of_property_read_bool(np,
+		"touchscreen-inverted-x");
+	priv->cfg_params.invert_y = of_property_read_bool(np,
+		"touchscreen-inverted-y");
+
+	return 0;
+}
+
+static int iproc_ts_probe(struct platform_device *pdev)
+{
+	struct iproc_ts_priv *priv;
+	struct input_dev *idev;
+	struct resource *res;
+	int ret;
+	int irq;
+
+	priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
+	if (!priv)
+		return -ENOMEM;
+
+	/* touchscreen controller memory mapped regs */
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	priv->regs = devm_ioremap_resource(&pdev->dev, res);
+	if (IS_ERR(priv->regs)) {
+		dev_err(&pdev->dev, "unable to map I/O memory\n");
+		return PTR_ERR(priv->regs);
+	}
+
+	priv->tsc_clk = devm_clk_get(&pdev->dev, "tsc_clk");
+	if (IS_ERR(priv->tsc_clk)) {
+		dev_err(&pdev->dev,
+			"%s Failed getting clock tsc_clk\n", __func__);
+		return PTR_ERR(priv->tsc_clk);
+	}
+
+	ret = get_tsc_config(pdev->dev.of_node, priv);
+	if (ret != 0) {
+		dev_err(&pdev->dev, "%s get_tsc_config failed\n", __func__);
+		return ret;
+	}
+
+	idev = devm_input_allocate_device(&pdev->dev);
+	if (!idev) {
+		dev_err(&pdev->dev,
+			"%s Allocate input device failed\n", __func__);
+		return -ENOMEM;
+	}
+
+	priv->idev = idev;
+	priv->pdev = pdev;
+
+	priv->pen_status = PEN_UP_STATUS;
+
+	/* Set input device info  */
+	idev->name = IPROC_TS_NAME;
+	idev->dev.parent = &pdev->dev;
+
+	idev->id.bustype = BUS_HOST;
+	idev->id.vendor = SERIO_UNKNOWN;
+	idev->id.product = 0;
+	idev->id.version = 0;
+
+	idev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS);
+	set_bit(BTN_TOUCH, idev->keybit);
+
+	input_set_abs_params(idev, ABS_X, X_MIN, priv->cfg_params.max_x,
+		priv->cfg_params.fuzz_x, 0);
+	input_set_abs_params(idev, ABS_Y, Y_MIN, priv->cfg_params.max_y,
+		priv->cfg_params.fuzz_y, 0);
+
+	idev->open = iproc_ts_start;
+	idev->close = iproc_ts_stop;
+
+	input_set_drvdata(idev, priv);
+	platform_set_drvdata(pdev, priv);
+
+	/* get interrupt */
+	irq = platform_get_irq(pdev, 0);
+	if (irq < 0) {
+		dev_err(&pdev->dev, "%s platform_get_irq failed\n", __func__);
+		return irq;
+	}
+
+	ret = devm_request_irq(&pdev->dev, irq,
+		iproc_touchscreen_interrupt,
+		IRQF_SHARED, IPROC_TS_NAME, pdev);
+	if (ret)
+		return ret;
+
+	ret = input_register_device(priv->idev);
+	if (ret) {
+		dev_err(&pdev->dev,
+			"%s register input device failed %d\n", __func__, ret);
+		return ret;
+	}
+
+	return 0;
+}
+
+static const struct of_device_id iproc_ts_of_match[] = {
+	{.compatible = "brcm,iproc-touchscreen", },
+	{ },
+};
+MODULE_DEVICE_TABLE(of, iproc_ts_of_match);
+
+static struct platform_driver iproc_ts_driver = {
+	.probe = iproc_ts_probe,
+	.driver = {
+		.name	= IPROC_TS_NAME,
+		.of_match_table = of_match_ptr(iproc_ts_of_match),
+	},
+};
+
+module_platform_driver(iproc_ts_driver);
+
+MODULE_DESCRIPTION("IPROC Touchscreen driver");
+MODULE_AUTHOR("Broadcom");
+MODULE_LICENSE("GPL v2");
-- 
1.7.9.5


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

* [PATCH v4 2/2] Input: touchscreen-iproc: add device tree bindings
  2015-03-12 17:45 ` [PATCH v4 0/2] Add support for Broadcom iProc touchscreen Jonathan Richardson
  2015-03-12 17:45   ` [PATCH v4 1/2] Input: touchscreen-iproc: Add Broadcom iProc touchscreen driver Jonathan Richardson
@ 2015-03-12 17:45   ` Jonathan Richardson
  1 sibling, 0 replies; 92+ messages in thread
From: Jonathan Richardson @ 2015-03-12 17:45 UTC (permalink / raw)
  To: Dmitry Torokhov, Anatol Pomazau
  Cc: Jonathan Richardson, Scott Branden, Grant Likely, Rob Herring,
	Ray Jui, linux-kernel, linux-input, bcm-kernel-feedback-list,
	devicetree, Joe Perches, Pawel Moll, Mark Rutland, Ian Campbell,
	Kumar Gala

Documents the touchscreen device tree binding for Broadcom iProc family
of SoCs.

Reviewed-by: Scott Branden <sbranden@broadcom.com>
Tested-by: Scott Branden <sbranden@broadcom.com>
Signed-off-by: Jonathan Richardson <jonathar@broadcom.com>
---
 .../input/touchscreen/brcm,iproc-touchscreen.txt   |   76 ++++++++++++++++++++
 1 file changed, 76 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/input/touchscreen/brcm,iproc-touchscreen.txt

diff --git a/Documentation/devicetree/bindings/input/touchscreen/brcm,iproc-touchscreen.txt b/Documentation/devicetree/bindings/input/touchscreen/brcm,iproc-touchscreen.txt
new file mode 100644
index 0000000..34e3382
--- /dev/null
+++ b/Documentation/devicetree/bindings/input/touchscreen/brcm,iproc-touchscreen.txt
@@ -0,0 +1,76 @@
+* Broadcom's IPROC Touchscreen Controller
+
+Required properties:
+- compatible: must be "brcm,iproc-touchscreen"
+- reg: physical base address of the controller and length of memory mapped
+  region.
+- clocks:  The clock provided by the SOC to driver the tsc
+- clock-name:  name for the clock
+- interrupts: The touchscreen controller's interrupt
+
+Optional properties:
+- scanning_period: Time between scans. Each step is 1024 us.  Valid 1-256.
+- debounce_timeout: Each step is 512 us.  Valid 0-255
+- settling_timeout: The settling duration (in ms) is the amount of time
+                    the tsc waits to allow the voltage to settle after
+                    turning on the drivers in detection mode.
+                    Valid values: 0-11
+                    0 =  0.008 ms
+                    1 =  0.01 ms
+                    2 =  0.02 ms
+                    3 =  0.04 ms
+                    4 =  0.08 ms
+                    5 =  0.16 ms
+                    6 =  0.32 ms
+                    7 =  0.64 ms
+                    8 =  1.28 ms
+                    9 =  2.56 ms
+                   10 =  5.12 ms
+                   11 = 10.24 ms
+- touch_timeout: The continuous number of scan periods in which touch is
+                not detected before the controller returns to idle state.
+                Valid values 0-255.
+- average_data: Number of data samples which are averaged before a final
+                data point is placed into the FIFO
+                Valid values 0-7
+                0 =   1 sample
+                1 =   2 samples
+                2 =   4 samples
+                3 =   8 samples
+                4 =  16 samples
+                5 =  32 samples
+                6 =  64 samples
+                7 = 128 samples
+- fifo_threshold: Interrupt is generated whenever the number of fifo
+                entries exceeds this value
+                Valid values 0-31
+- touchscreen-size-x: horizontal resolution of touchscreen (in pixels)
+- touchscreen-size-y: vertical resolution of touchscreen (in pixels)
+- touchscreen-fuzz-x: horizontal noise value of the absolute input
+                      device (in pixels)
+- touchscreen-fuzz-y: vertical noise value of the absolute input
+                      device (in pixels)
+- touchscreen-inverted-x: X axis is inverted (boolean)
+- touchscreen-inverted-y: Y axis is inverted (boolean)
+
+Example:
+
+	touchscreen: tsc@0x180A6000 {
+		compatible = "brcm,iproc-touchscreen";
+		#address-cells = <1>;
+		#size-cells = <1>;
+		reg = <0x180A6000 0x40>;
+		clocks = <&adc_clk>;
+		clock-names = "tsc_clk";
+		interrupts = <GIC_SPI 164 IRQ_TYPE_LEVEL_HIGH>;
+
+		scanning_period = <5>;
+		debounce_timeout = <40>;
+		settling_timeout = <7>;
+		touch_timeout = <10>;
+		average_data = <5>;
+		fifo_threshold = <1>;
+		/* Touchscreen is rotated 180 degrees. */
+		touchscreen-inverted-x;
+		touchscreen-inverted-y;
+	};
-- 
1.7.9.5


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

* Re: [PATCH v4 1/2] Input: touchscreen-iproc: Add Broadcom iProc touchscreen driver
  2015-03-12 17:45   ` [PATCH v4 1/2] Input: touchscreen-iproc: Add Broadcom iProc touchscreen driver Jonathan Richardson
@ 2015-03-12 17:59     ` Joe Perches
  2015-03-12 22:44       ` Jonathan Richardson
  0 siblings, 1 reply; 92+ messages in thread
From: Joe Perches @ 2015-03-12 17:59 UTC (permalink / raw)
  To: Jonathan Richardson
  Cc: Dmitry Torokhov, Anatol Pomazau, Scott Branden, Grant Likely,
	Rob Herring, Ray Jui, linux-kernel, linux-input,
	bcm-kernel-feedback-list, devicetree, Pawel Moll, Mark Rutland,
	Ian Campbell, Kumar Gala

On Thu, 2015-03-12 at 10:45 -0700, Jonathan Richardson wrote:
> Add initial version of the Broadcom touchscreen driver.

style trivia:
(any of which could be fixed/improved/ignored later)

> diff --git a/drivers/input/touchscreen/bcm_iproc_tsc.c b/drivers/input/touchscreen/bcm_iproc_tsc.c
[]
> +static void ts_reg_dump(struct iproc_ts_priv *priv)
> +{
> +	struct device *dev = &priv->pdev->dev;
> +
> +	dev_dbg(dev, "regCtl1             = 0x%08x\n",
> +				readl(priv->regs + REGCTL1));

The output case here generally isn't very important so
sometimes it's better to use a macro like:

#define dbg_reg(dev, priv, reg)						\
	dev_dbg(dev, "%20s= 0x%08x\n", #reg, readl((priv)->regs + reg))

> +	dev_dbg(dev, "regCtl2             = 0x%08x\n",
> +				readl(priv->regs + REGCTL2));

so these become
	dbg_reg(dev, priv, INTERRUPT_THRES);
	dbg_reg(dev, priv, INTERRUPT_MASK);

etc...

This style can reduce typo and copy/paste defects.

> +	dev_dbg(dev, "interrupt_Thres     = 0x%08x\n",
> +				readl(priv->regs + INTERRUPT_THRES));
> +	dev_dbg(dev, "interrupt_Mask      = 0x%08x\n",
> +				readl(priv->regs + INTERRUPT_MASK));
> +	dev_dbg(dev, "interrupt_Status    = 0x%08x\n",
> +				readl(priv->regs + INTERRUPT_STATUS));
> +	dev_dbg(dev, "controller_Status   = 0x%08x\n",
> +				readl(priv->regs + CONTROLLER_STATUS));
> +	dev_dbg(dev, "FIFO_Data           = 0x%08x\n",
> +				readl(priv->regs + FIFO_DATA));
> +	dev_dbg(dev, "analog_Control      = 0x%08x\n",
> +				readl(priv->regs + ANALOG_CONTROL));
> +	dev_dbg(dev, "aux_Data            = 0x%08x\n",
> +				readl(priv->regs + AUX_DATA));
> +	dev_dbg(dev, "debounce_Cntr_Stat  = 0x%08x\n",
> +				readl(priv->regs + DEBOUNCE_CNTR_STAT));
> +	dev_dbg(dev, "scan_Cntr_Stat      = 0x%08x\n",
> +				readl(priv->regs + SCAN_CNTR_STAT));
> +	dev_dbg(dev, "rem_Cntr_Stat       = 0x%08x\n",
> +				readl(priv->regs + REM_CNTR_STAT));
> +	dev_dbg(dev, "settling_Timer_Stat = 0x%08x\n",
> +				readl(priv->regs + SETTLING_TIMER_STAT));
> +	dev_dbg(dev, "spare_Reg           = 0x%08x\n",
> +				readl(priv->regs + SPARE_REG));
> +	dev_dbg(dev, "soft_Bypass_Control = 0x%08x\n",
> +				readl(priv->regs + SOFT_BYPASS_CONTROL));
> +	dev_dbg(dev, "soft_Bypass_Data    = 0x%08x\n",
> +				readl(priv->regs + SOFT_BYPASS_DATA));
> +}

[]

> +static int get_tsc_config(struct device_node *np, struct iproc_ts_priv *priv)
> +{
> +	u32 val;
[]
> +	if (of_property_read_u32(np, "debounce_timeout", &val) >= 0) {
> +		if (val < 0 || val > 255) {

testing u32 < 0 isn't necessary.

Maybe it'd be better to emit the out of range value too

> +			dev_err(dev, "debounce_timeout must be [0-255]\n");

			dev_err(dev, "debounce_timeout (%u) must be [0-255]\n", val);



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

* Re: [PATCH v4 1/2] Input: touchscreen-iproc: Add Broadcom iProc touchscreen driver
  2015-03-12 17:59     ` Joe Perches
@ 2015-03-12 22:44       ` Jonathan Richardson
  0 siblings, 0 replies; 92+ messages in thread
From: Jonathan Richardson @ 2015-03-12 22:44 UTC (permalink / raw)
  To: Joe Perches
  Cc: Dmitry Torokhov, Anatol Pomazau, Scott Branden, Grant Likely,
	Rob Herring, Ray Jui, linux-kernel, linux-input,
	bcm-kernel-feedback-list, devicetree, Pawel Moll, Mark Rutland,
	Ian Campbell, Kumar Gala

On 15-03-12 10:59 AM, Joe Perches wrote:
> On Thu, 2015-03-12 at 10:45 -0700, Jonathan Richardson wrote:
>> Add initial version of the Broadcom touchscreen driver.
> 
> style trivia:
> (any of which could be fixed/improved/ignored later)
> 
>> diff --git a/drivers/input/touchscreen/bcm_iproc_tsc.c b/drivers/input/touchscreen/bcm_iproc_tsc.c
> []
>> +static void ts_reg_dump(struct iproc_ts_priv *priv)
>> +{
>> +	struct device *dev = &priv->pdev->dev;
>> +
>> +	dev_dbg(dev, "regCtl1             = 0x%08x\n",
>> +				readl(priv->regs + REGCTL1));
> 
> The output case here generally isn't very important so
> sometimes it's better to use a macro like:
> 
> #define dbg_reg(dev, priv, reg)						\
> 	dev_dbg(dev, "%20s= 0x%08x\n", #reg, readl((priv)->regs + reg))
> 
>> +	dev_dbg(dev, "regCtl2             = 0x%08x\n",
>> +				readl(priv->regs + REGCTL2));
> 
> so these become
> 	dbg_reg(dev, priv, INTERRUPT_THRES);
> 	dbg_reg(dev, priv, INTERRUPT_MASK);
> 
> etc...
> 
> This style can reduce typo and copy/paste defects.
> 
>> +	dev_dbg(dev, "interrupt_Thres     = 0x%08x\n",
>> +				readl(priv->regs + INTERRUPT_THRES));
>> +	dev_dbg(dev, "interrupt_Mask      = 0x%08x\n",
>> +				readl(priv->regs + INTERRUPT_MASK));
>> +	dev_dbg(dev, "interrupt_Status    = 0x%08x\n",
>> +				readl(priv->regs + INTERRUPT_STATUS));
>> +	dev_dbg(dev, "controller_Status   = 0x%08x\n",
>> +				readl(priv->regs + CONTROLLER_STATUS));
>> +	dev_dbg(dev, "FIFO_Data           = 0x%08x\n",
>> +				readl(priv->regs + FIFO_DATA));
>> +	dev_dbg(dev, "analog_Control      = 0x%08x\n",
>> +				readl(priv->regs + ANALOG_CONTROL));
>> +	dev_dbg(dev, "aux_Data            = 0x%08x\n",
>> +				readl(priv->regs + AUX_DATA));
>> +	dev_dbg(dev, "debounce_Cntr_Stat  = 0x%08x\n",
>> +				readl(priv->regs + DEBOUNCE_CNTR_STAT));
>> +	dev_dbg(dev, "scan_Cntr_Stat      = 0x%08x\n",
>> +				readl(priv->regs + SCAN_CNTR_STAT));
>> +	dev_dbg(dev, "rem_Cntr_Stat       = 0x%08x\n",
>> +				readl(priv->regs + REM_CNTR_STAT));
>> +	dev_dbg(dev, "settling_Timer_Stat = 0x%08x\n",
>> +				readl(priv->regs + SETTLING_TIMER_STAT));
>> +	dev_dbg(dev, "spare_Reg           = 0x%08x\n",
>> +				readl(priv->regs + SPARE_REG));
>> +	dev_dbg(dev, "soft_Bypass_Control = 0x%08x\n",
>> +				readl(priv->regs + SOFT_BYPASS_CONTROL));
>> +	dev_dbg(dev, "soft_Bypass_Data    = 0x%08x\n",
>> +				readl(priv->regs + SOFT_BYPASS_DATA));
>> +}
> 
> []
> 
>> +static int get_tsc_config(struct device_node *np, struct iproc_ts_priv *priv)
>> +{
>> +	u32 val;
> []
>> +	if (of_property_read_u32(np, "debounce_timeout", &val) >= 0) {
>> +		if (val < 0 || val > 255) {
> 
> testing u32 < 0 isn't necessary.
> 
> Maybe it'd be better to emit the out of range value too
> 
>> +			dev_err(dev, "debounce_timeout must be [0-255]\n");
> 
> 			dev_err(dev, "debounce_timeout (%u) must be [0-255]\n", val);
> 
> 

Thanks. I'll make the suggested changes and send out a new patch.

Jon




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

end of thread, other threads:[~2015-03-12 22:44 UTC | newest]

Thread overview: 92+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
     [not found] <Jonathan Richardson <jonathar@broadcom.com>
2014-09-16 19:58 ` [PATCH 0/6] Add initial support for Broadcom Cygnus SoC Jonathan Richardson
2014-09-16 19:58   ` [PATCH 1/6] ARM: cygnus: Initial " Jonathan Richardson
2014-09-17  0:00     ` Mark Rutland
2014-09-18 23:33       ` Jonathan Richardson
2014-09-16 19:58   ` [PATCH 2/6] clk: Clock driver " Jonathan Richardson
2014-09-17  0:47     ` Mark Rutland
2014-09-18 23:43       ` Jonathan Richardson
2014-09-16 19:58   ` [PATCH 3/6] dt-bindings: Document Broadcom Cygnus SoC and clock driver Jonathan Richardson
2014-09-16 19:58   ` [PATCH 4/6] ARM: dts: Enable Broadcom Cygnus SoC Jonathan Richardson
2014-09-16 19:58   ` [PATCH 5/6] ARM: cygnus defconfig : Initial defconfig for " Jonathan Richardson
2014-09-16 19:58   ` [PATCH 6/6] MAINTAINERS: Entry for Cygnus/iproc arm architecture and clock drivers Jonathan Richardson
2014-09-18 22:31   ` [PATCH 0/6] Add initial support for Broadcom Cygnus SoC Hauke Mehrtens
2014-09-18 22:39     ` Florian Fainelli
2014-09-18 22:54       ` Hauke Mehrtens
2014-09-19  0:58         ` Scott Branden
2014-09-23 21:17 ` [PATCH v2 " Jonathan Richardson
2014-09-23 21:17   ` [PATCH v2 1/6] ARM: cygnus: Initial " Jonathan Richardson
2014-09-23 21:17   ` [PATCH v2 2/6] clk: Clock driver " Jonathan Richardson
2014-09-23 21:17   ` [PATCH v2 3/6] dt-bindings: Document Broadcom Cygnus SoC and clock driver Jonathan Richardson
2014-09-23 21:17   ` [PATCH v2 4/6] ARM: dts: Enable Broadcom Cygnus SoC Jonathan Richardson
2014-09-23 21:17   ` [PATCH v2 5/6] ARM: cygnus defconfig : Initial defconfig for " Jonathan Richardson
2014-09-23 21:17   ` [PATCH v2 6/6] MAINTAINERS: Entry for Cygnus/iproc arm architecture and clock drivers Jonathan Richardson
2014-09-25 21:04   ` [PATCH v2 0/6] Add initial support for Broadcom Cygnus SoC Scott Branden
2014-09-25 21:22     ` Florian Fainelli
2014-09-26  0:14       ` Florian Fainelli
2014-09-26  0:28         ` Jonathan Richardson
2014-09-26  0:34           ` Florian Fainelli
2014-12-11  1:07 ` [PATCH v2 1/2] pwm: kona: Fix incorrect enable, config, and disable procedures Jonathan Richardson
2014-12-11  1:07   ` [PATCH v2 2/2] pwm: kona: Remove setting default smooth type and polarity for all channels Jonathan Richardson
2014-12-15  7:18   ` [PATCH v2 1/2] pwm: kona: Fix incorrect enable, config, and disable procedures Tim Kryger
2014-12-16 19:36     ` Jonathan Richardson
2014-12-17 18:46 ` [PATCH v3 " Jonathan Richardson
2014-12-17 18:46   ` [PATCH v3 2/2] pwm: kona: Remove setting default smooth type and polarity for all channels Jonathan Richardson
2014-12-20 22:38   ` [PATCH v3 1/2] pwm: kona: Fix incorrect enable, config, and disable procedures Tim Kryger
2014-12-22 22:49     ` Jonathan Richardson
2014-12-18  1:59 ` [PATCH 0/2] Add support for Broadcom iProc touchscreen Jonathan Richardson
2014-12-18  1:59   ` [PATCH 1/2] Input: touchscreen-iproc: Add Broadcom iProc touchscreen driver Jonathan Richardson
2014-12-18  2:14     ` Joe Perches
2014-12-19 19:51       ` Jonathan Richardson
2014-12-19 19:56         ` Dmitry Torokhov
2014-12-18  1:59   ` [PATCH 2/2] Input: touchscreen-iproc: add device tree bindings Jonathan Richardson
2014-12-19 22:17 ` [PATCH v2 0/2] Add support for Broadcom iProc touchscreen Jonathan Richardson
2014-12-19 22:17   ` [PATCH v2 1/2] Input: touchscreen-iproc: Add Broadcom iProc touchscreen driver Jonathan Richardson
2014-12-19 22:26     ` Joe Perches
2014-12-19 23:03       ` Jonathan Richardson
2015-01-01  0:55         ` Jonathan Richardson
2015-01-15  1:08         ` Florian Fainelli
2015-01-15 19:19           ` Jonathan Richardson
2015-01-15  1:02     ` Dmitry Torokhov
2015-01-15  5:44       ` Scott Branden
2015-01-15  6:07         ` Dmitry Torokhov
2015-01-15 19:51           ` Jonathan Richardson
2015-02-11 18:45             ` Jonathan Richardson
2015-02-24 23:18               ` Dmitry Torokhov
2015-02-27  1:02                 ` Jonathan Richardson
2015-02-24 23:29     ` Dmitry Torokhov
2015-03-02 19:13       ` Jonathan Richardson
2014-12-19 22:17   ` [PATCH v2 2/2] Input: touchscreen-iproc: add device tree bindings Jonathan Richardson
2014-12-30 22:43 ` [PATCH v4 0/3] Fix bugs in kona pwm driver and pwm core Jonathan Richardson
2014-12-30 22:43   ` [PATCH v4 1/3] pwm: kona: Fix incorrect config, disable, and polarity procedures Jonathan Richardson
2014-12-30 22:43   ` [PATCH v4 2/3] pwm: kona: Remove setting default smooth type and polarity for all channels Jonathan Richardson
2015-01-05  1:12     ` Tim Kryger
2015-01-05  1:33       ` Tim Kryger
2014-12-30 22:43   ` [PATCH v4 3/3] pwm: core: Set enable state properly on failed call to enable Jonathan Richardson
2015-01-07 19:42 ` [PATCH v5 0/2] Fix bugs in kona pwm driver and pwm core Jonathan Richardson
2015-01-07 19:42   ` [PATCH v5 1/2] pwm: kona: Fix incorrect config, disable, and polarity procedures Jonathan Richardson
2015-01-07 19:42   ` [PATCH v5 2/2] pwm: core: Set enable state properly on failed call to enable Jonathan Richardson
2015-02-11 23:59     ` Dmitry Torokhov
2015-02-24 19:13 ` [PATCH 0/1] Enable Broadcom Cygnus BCM958305K Jonathan Richardson
2015-02-24 19:13   ` [PATCH 1/1] ARM: dts: " Jonathan Richardson
2015-02-25 19:04 ` [PATCH 0/1] Synopsis 8250 serial port driver fix Jonathan Richardson
2015-02-25 19:04   ` [PATCH 1/1] serial: 8250_dw: Fix get_mctrl behaviour Jonathan Richardson
2015-02-25 19:21     ` Arnd Bergmann
2015-02-25 20:00       ` Jonathan Richardson
2015-02-25 20:07         ` Arnd Bergmann
2015-02-27  0:35 ` [PATCH v2 0/1] Synopsis 8250 serial port driver fix Jonathan Richardson
2015-02-27  0:35   ` [PATCH v2 1/1] serial: 8250_dw: Fix get_mctrl behaviour Jonathan Richardson
2015-03-09 18:40     ` Dmitry Torokhov
2015-03-09 18:51       ` Jonathan Richardson
2015-03-02 22:41 ` [PATCH RESEND 0/1] Enable Broadcom Cygnus BCM958305K Jonathan Richardson
2015-03-02 22:41   ` [PATCH RESEND 1/1] ARM: dts: " Jonathan Richardson
2015-03-02 23:45     ` Florian Fainelli
2015-03-11  1:17 ` [PATCH v3 0/2] Add support for Broadcom iProc touchscreen Jonathan Richardson
2015-03-11  1:17   ` [PATCH v3 1/2] Input: touchscreen-iproc: Add Broadcom iProc touchscreen driver Jonathan Richardson
2015-03-11  9:46     ` Paul Bolle
2015-03-11 17:05       ` Jonathan Richardson
2015-03-11  1:17   ` [PATCH v3 2/2] Input: touchscreen-iproc: add device tree bindings Jonathan Richardson
2015-03-12 17:45 ` [PATCH v4 0/2] Add support for Broadcom iProc touchscreen Jonathan Richardson
2015-03-12 17:45   ` [PATCH v4 1/2] Input: touchscreen-iproc: Add Broadcom iProc touchscreen driver Jonathan Richardson
2015-03-12 17:59     ` Joe Perches
2015-03-12 22:44       ` Jonathan Richardson
2015-03-12 17:45   ` [PATCH v4 2/2] Input: touchscreen-iproc: add device tree bindings Jonathan Richardson

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