* [PATCH v4 0/5] Clk drivers for NXP LPC18xx family
@ 2015-05-28 20:31 ` Joachim Eastwood
0 siblings, 0 replies; 30+ messages in thread
From: Joachim Eastwood @ 2015-05-28 20:31 UTC (permalink / raw)
To: mturquette-QSEj5FYQhm4dnm+yROfE0A, sboyd-sgV2jX0FEOL9JmXXK+q4OQ
Cc: Joachim Eastwood, linux-clk-u79uwXL29TY76Z2rM5mHXA,
devicetree-u79uwXL29TY76Z2rM5mHXA,
linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r
This patch set adds support for the two main clock peripherals in the
LPC18xx/43xx MCU family.
The Clock Generation Unit (CGU) is the base source of all clocks. It has
five external inputs and contains PLLs, dividers and muxes. The outputs
from the CGU are then routed to a Clock Control Unit (CCU) and a few
peripherals directly. There are two CCUs in the MCU. The CCU is a
collection of gates and a few dividers that sits between the CGU and
most of the peripherals. These clock drivers are needed by the timer at
early boot so both are using CLK_OF_DECLARE.
Which clocks that are available depends on the specific device and it's
peripherals. It's possible in DT to setup the routing between the CGU
and the CCUs.
The biggest change in v4 is the way parent names for CCU clocks are
stored and how clock branches are selected for registration in the
CCU driver.
* Parent clock names are now stored together with branch name in the
clk_branches[] table.
* Selection of which branch clock to register on the two CCU instances
is determined by the 'clock-names' property. If a clock name matches
with the parent name in the clk_branches[] table that branch clock is
registered on the CCU.
Alternativly the clk_branches[] table could be split between the CCUs,
but there would still be a need to identify the CCU instance. For
example by using different compatability stings in DT or adding an id
property to DT.
I belive the best solution is to let the driver decide which branch
clocks to register based on the clock routing information already
provided in DT. As mentioned above this is now done by using the
'clock-names' property and matching strings in the clk_branches[]
table.
Clock tree can be found here: http://slexy.org/raw/s2I3bIFJxg
Changes since v3:
- put CCU parent clock names directly in clk_branches[] table
- use 'clock-names' property to find figure out which branch
clocks to register in CCU driver as oppose to clk id
- remove CCU clock list from doc and refer to lpc18xx-ccu.h
- remove patch with of_clk_get_index
Changes since v2:
- use 'clock-controller' as node name in doc
- add patch with of_clk_get_index function
- drop 'clock-indices' and 'clock-output-names' from cgu node
- move base clock names into cgu driver
- use of_clk_get/__clk_get_name in ccu to get parent name for
composite clocks.
- other misc fixes to ccu driver and cgu doc
Changes since v1:
- reorganize cgu clk structs
- macros to create cgu clk structs
- move drivers to nxp subdir
- rebase on v4.1-rc1
The last patch (dts changes) are only included in this patch set for
illustration purposes. DTS changes will be sent separately to the ARM
SoC team later.
Base support for LPC18xx is now in arm-soc next. Pinctrl, gpio, reset
and ethernet drivers are also upstream.
Joachim Eastwood (5):
clk: add lpc18xx cgu clk driver
doc: dt: add documentation for lpc1850-cgu clk driver
clk: add lpc18xx ccu clk driver
doc: dt: add documentation for lpc1850-ccu clk driver
ARM: dts: lpc18xx: add clock nodes for cgu and ccu
.../devicetree/bindings/clock/lpc1850-ccu.txt | 77 +++
.../devicetree/bindings/clock/lpc1850-cgu.txt | 131 +++++
arch/arm/boot/dts/lpc18xx.dtsi | 85 ++-
arch/arm/boot/dts/lpc4350-hitex-eval.dts | 4 -
drivers/clk/Makefile | 1 +
drivers/clk/nxp/Makefile | 2 +
drivers/clk/nxp/clk-lpc18xx-ccu.c | 293 ++++++++++
drivers/clk/nxp/clk-lpc18xx-cgu.c | 635 +++++++++++++++++++++
include/dt-bindings/clock/lpc18xx-ccu.h | 74 +++
include/dt-bindings/clock/lpc18xx-cgu.h | 41 ++
10 files changed, 1325 insertions(+), 18 deletions(-)
create mode 100644 Documentation/devicetree/bindings/clock/lpc1850-ccu.txt
create mode 100644 Documentation/devicetree/bindings/clock/lpc1850-cgu.txt
create mode 100644 drivers/clk/nxp/Makefile
create mode 100644 drivers/clk/nxp/clk-lpc18xx-ccu.c
create mode 100644 drivers/clk/nxp/clk-lpc18xx-cgu.c
create mode 100644 include/dt-bindings/clock/lpc18xx-ccu.h
create mode 100644 include/dt-bindings/clock/lpc18xx-cgu.h
--
1.8.0
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply [flat|nested] 30+ messages in thread
* [PATCH v4 0/5] Clk drivers for NXP LPC18xx family
@ 2015-05-28 20:31 ` Joachim Eastwood
0 siblings, 0 replies; 30+ messages in thread
From: Joachim Eastwood @ 2015-05-28 20:31 UTC (permalink / raw)
To: mturquette, sboyd
Cc: Joachim Eastwood, linux-clk, devicetree, linux-arm-kernel
This patch set adds support for the two main clock peripherals in the
LPC18xx/43xx MCU family.
The Clock Generation Unit (CGU) is the base source of all clocks. It has
five external inputs and contains PLLs, dividers and muxes. The outputs
from the CGU are then routed to a Clock Control Unit (CCU) and a few
peripherals directly. There are two CCUs in the MCU. The CCU is a
collection of gates and a few dividers that sits between the CGU and
most of the peripherals. These clock drivers are needed by the timer at
early boot so both are using CLK_OF_DECLARE.
Which clocks that are available depends on the specific device and it's
peripherals. It's possible in DT to setup the routing between the CGU
and the CCUs.
The biggest change in v4 is the way parent names for CCU clocks are
stored and how clock branches are selected for registration in the
CCU driver.
* Parent clock names are now stored together with branch name in the
clk_branches[] table.
* Selection of which branch clock to register on the two CCU instances
is determined by the 'clock-names' property. If a clock name matches
with the parent name in the clk_branches[] table that branch clock is
registered on the CCU.
Alternativly the clk_branches[] table could be split between the CCUs,
but there would still be a need to identify the CCU instance. For
example by using different compatability stings in DT or adding an id
property to DT.
I belive the best solution is to let the driver decide which branch
clocks to register based on the clock routing information already
provided in DT. As mentioned above this is now done by using the
'clock-names' property and matching strings in the clk_branches[]
table.
Clock tree can be found here: http://slexy.org/raw/s2I3bIFJxg
Changes since v3:
- put CCU parent clock names directly in clk_branches[] table
- use 'clock-names' property to find figure out which branch
clocks to register in CCU driver as oppose to clk id
- remove CCU clock list from doc and refer to lpc18xx-ccu.h
- remove patch with of_clk_get_index
Changes since v2:
- use 'clock-controller' as node name in doc
- add patch with of_clk_get_index function
- drop 'clock-indices' and 'clock-output-names' from cgu node
- move base clock names into cgu driver
- use of_clk_get/__clk_get_name in ccu to get parent name for
composite clocks.
- other misc fixes to ccu driver and cgu doc
Changes since v1:
- reorganize cgu clk structs
- macros to create cgu clk structs
- move drivers to nxp subdir
- rebase on v4.1-rc1
The last patch (dts changes) are only included in this patch set for
illustration purposes. DTS changes will be sent separately to the ARM
SoC team later.
Base support for LPC18xx is now in arm-soc next. Pinctrl, gpio, reset
and ethernet drivers are also upstream.
Joachim Eastwood (5):
clk: add lpc18xx cgu clk driver
doc: dt: add documentation for lpc1850-cgu clk driver
clk: add lpc18xx ccu clk driver
doc: dt: add documentation for lpc1850-ccu clk driver
ARM: dts: lpc18xx: add clock nodes for cgu and ccu
.../devicetree/bindings/clock/lpc1850-ccu.txt | 77 +++
.../devicetree/bindings/clock/lpc1850-cgu.txt | 131 +++++
arch/arm/boot/dts/lpc18xx.dtsi | 85 ++-
arch/arm/boot/dts/lpc4350-hitex-eval.dts | 4 -
drivers/clk/Makefile | 1 +
drivers/clk/nxp/Makefile | 2 +
drivers/clk/nxp/clk-lpc18xx-ccu.c | 293 ++++++++++
drivers/clk/nxp/clk-lpc18xx-cgu.c | 635 +++++++++++++++++++++
include/dt-bindings/clock/lpc18xx-ccu.h | 74 +++
include/dt-bindings/clock/lpc18xx-cgu.h | 41 ++
10 files changed, 1325 insertions(+), 18 deletions(-)
create mode 100644 Documentation/devicetree/bindings/clock/lpc1850-ccu.txt
create mode 100644 Documentation/devicetree/bindings/clock/lpc1850-cgu.txt
create mode 100644 drivers/clk/nxp/Makefile
create mode 100644 drivers/clk/nxp/clk-lpc18xx-ccu.c
create mode 100644 drivers/clk/nxp/clk-lpc18xx-cgu.c
create mode 100644 include/dt-bindings/clock/lpc18xx-ccu.h
create mode 100644 include/dt-bindings/clock/lpc18xx-cgu.h
--
1.8.0
^ permalink raw reply [flat|nested] 30+ messages in thread
* [PATCH v4 0/5] Clk drivers for NXP LPC18xx family
@ 2015-05-28 20:31 ` Joachim Eastwood
0 siblings, 0 replies; 30+ messages in thread
From: Joachim Eastwood @ 2015-05-28 20:31 UTC (permalink / raw)
To: linux-arm-kernel
This patch set adds support for the two main clock peripherals in the
LPC18xx/43xx MCU family.
The Clock Generation Unit (CGU) is the base source of all clocks. It has
five external inputs and contains PLLs, dividers and muxes. The outputs
from the CGU are then routed to a Clock Control Unit (CCU) and a few
peripherals directly. There are two CCUs in the MCU. The CCU is a
collection of gates and a few dividers that sits between the CGU and
most of the peripherals. These clock drivers are needed by the timer at
early boot so both are using CLK_OF_DECLARE.
Which clocks that are available depends on the specific device and it's
peripherals. It's possible in DT to setup the routing between the CGU
and the CCUs.
The biggest change in v4 is the way parent names for CCU clocks are
stored and how clock branches are selected for registration in the
CCU driver.
* Parent clock names are now stored together with branch name in the
clk_branches[] table.
* Selection of which branch clock to register on the two CCU instances
is determined by the 'clock-names' property. If a clock name matches
with the parent name in the clk_branches[] table that branch clock is
registered on the CCU.
Alternativly the clk_branches[] table could be split between the CCUs,
but there would still be a need to identify the CCU instance. For
example by using different compatability stings in DT or adding an id
property to DT.
I belive the best solution is to let the driver decide which branch
clocks to register based on the clock routing information already
provided in DT. As mentioned above this is now done by using the
'clock-names' property and matching strings in the clk_branches[]
table.
Clock tree can be found here: http://slexy.org/raw/s2I3bIFJxg
Changes since v3:
- put CCU parent clock names directly in clk_branches[] table
- use 'clock-names' property to find figure out which branch
clocks to register in CCU driver as oppose to clk id
- remove CCU clock list from doc and refer to lpc18xx-ccu.h
- remove patch with of_clk_get_index
Changes since v2:
- use 'clock-controller' as node name in doc
- add patch with of_clk_get_index function
- drop 'clock-indices' and 'clock-output-names' from cgu node
- move base clock names into cgu driver
- use of_clk_get/__clk_get_name in ccu to get parent name for
composite clocks.
- other misc fixes to ccu driver and cgu doc
Changes since v1:
- reorganize cgu clk structs
- macros to create cgu clk structs
- move drivers to nxp subdir
- rebase on v4.1-rc1
The last patch (dts changes) are only included in this patch set for
illustration purposes. DTS changes will be sent separately to the ARM
SoC team later.
Base support for LPC18xx is now in arm-soc next. Pinctrl, gpio, reset
and ethernet drivers are also upstream.
Joachim Eastwood (5):
clk: add lpc18xx cgu clk driver
doc: dt: add documentation for lpc1850-cgu clk driver
clk: add lpc18xx ccu clk driver
doc: dt: add documentation for lpc1850-ccu clk driver
ARM: dts: lpc18xx: add clock nodes for cgu and ccu
.../devicetree/bindings/clock/lpc1850-ccu.txt | 77 +++
.../devicetree/bindings/clock/lpc1850-cgu.txt | 131 +++++
arch/arm/boot/dts/lpc18xx.dtsi | 85 ++-
arch/arm/boot/dts/lpc4350-hitex-eval.dts | 4 -
drivers/clk/Makefile | 1 +
drivers/clk/nxp/Makefile | 2 +
drivers/clk/nxp/clk-lpc18xx-ccu.c | 293 ++++++++++
drivers/clk/nxp/clk-lpc18xx-cgu.c | 635 +++++++++++++++++++++
include/dt-bindings/clock/lpc18xx-ccu.h | 74 +++
include/dt-bindings/clock/lpc18xx-cgu.h | 41 ++
10 files changed, 1325 insertions(+), 18 deletions(-)
create mode 100644 Documentation/devicetree/bindings/clock/lpc1850-ccu.txt
create mode 100644 Documentation/devicetree/bindings/clock/lpc1850-cgu.txt
create mode 100644 drivers/clk/nxp/Makefile
create mode 100644 drivers/clk/nxp/clk-lpc18xx-ccu.c
create mode 100644 drivers/clk/nxp/clk-lpc18xx-cgu.c
create mode 100644 include/dt-bindings/clock/lpc18xx-ccu.h
create mode 100644 include/dt-bindings/clock/lpc18xx-cgu.h
--
1.8.0
^ permalink raw reply [flat|nested] 30+ messages in thread
* [PATCH v4 1/5] clk: add lpc18xx cgu clk driver
2015-05-28 20:31 ` Joachim Eastwood
(?)
@ 2015-05-28 20:31 ` Joachim Eastwood
-1 siblings, 0 replies; 30+ messages in thread
From: Joachim Eastwood @ 2015-05-28 20:31 UTC (permalink / raw)
To: mturquette-QSEj5FYQhm4dnm+yROfE0A, sboyd-sgV2jX0FEOL9JmXXK+q4OQ
Cc: Joachim Eastwood, linux-clk-u79uwXL29TY76Z2rM5mHXA,
devicetree-u79uwXL29TY76Z2rM5mHXA,
linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r
Add driver for NXP LPC18xx/43xx Clock Generation Unit (CGU). The CGU
contains several clock generators and output stages that route the
clocks either directly to peripherals or to a Clock Control Unit
(CCU).
Signed-off-by: Joachim Eastwood <manabian-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
---
drivers/clk/Makefile | 1 +
drivers/clk/nxp/Makefile | 1 +
drivers/clk/nxp/clk-lpc18xx-cgu.c | 635 ++++++++++++++++++++++++++++++++
include/dt-bindings/clock/lpc18xx-cgu.h | 41 +++
4 files changed, 678 insertions(+)
create mode 100644 drivers/clk/nxp/Makefile
create mode 100644 drivers/clk/nxp/clk-lpc18xx-cgu.c
create mode 100644 include/dt-bindings/clock/lpc18xx-cgu.h
diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile
index 3d00c25382c5..4a34419c1da1 100644
--- a/drivers/clk/Makefile
+++ b/drivers/clk/Makefile
@@ -56,6 +56,7 @@ obj-$(CONFIG_ARCH_MMP) += mmp/
endif
obj-$(CONFIG_PLAT_ORION) += mvebu/
obj-$(CONFIG_ARCH_MXS) += mxs/
+obj-$(CONFIG_ARCH_LPC18XX) += nxp/
obj-$(CONFIG_MACH_PISTACHIO) += pistachio/
obj-$(CONFIG_COMMON_CLK_PXA) += pxa/
obj-$(CONFIG_COMMON_CLK_QCOM) += qcom/
diff --git a/drivers/clk/nxp/Makefile b/drivers/clk/nxp/Makefile
new file mode 100644
index 000000000000..aca9d3e4f7fe
--- /dev/null
+++ b/drivers/clk/nxp/Makefile
@@ -0,0 +1 @@
+obj-$(CONFIG_ARCH_LPC18XX) += clk-lpc18xx-cgu.o
diff --git a/drivers/clk/nxp/clk-lpc18xx-cgu.c b/drivers/clk/nxp/clk-lpc18xx-cgu.c
new file mode 100644
index 000000000000..81e9e1c788f4
--- /dev/null
+++ b/drivers/clk/nxp/clk-lpc18xx-cgu.c
@@ -0,0 +1,635 @@
+/*
+ * Clk driver for NXP LPC18xx/LPC43xx Clock Generation Unit (CGU)
+ *
+ * Copyright (C) 2015 Joachim Eastwood <manabian-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2. This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+#include <linux/clk.h>
+#include <linux/clk-provider.h>
+#include <linux/delay.h>
+#include <linux/kernel.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+
+#include <dt-bindings/clock/lpc18xx-cgu.h>
+
+/* Clock Generation Unit (CGU) registers */
+#define LPC18XX_CGU_XTAL_OSC_CTRL 0x018
+#define LPC18XX_CGU_PLL0USB_STAT 0x01c
+#define LPC18XX_CGU_PLL0USB_CTRL 0x020
+#define LPC18XX_CGU_PLL0USB_MDIV 0x024
+#define LPC18XX_CGU_PLL0USB_NP_DIV 0x028
+#define LPC18XX_CGU_PLL0AUDIO_STAT 0x02c
+#define LPC18XX_CGU_PLL0AUDIO_CTRL 0x030
+#define LPC18XX_CGU_PLL0AUDIO_MDIV 0x034
+#define LPC18XX_CGU_PLL0AUDIO_NP_DIV 0x038
+#define LPC18XX_CGU_PLL0AUDIO_FRAC 0x03c
+#define LPC18XX_CGU_PLL1_STAT 0x040
+#define LPC18XX_CGU_PLL1_CTRL 0x044
+#define LPC18XX_PLL1_CTRL_FBSEL BIT(6)
+#define LPC18XX_PLL1_CTRL_DIRECT BIT(7)
+#define LPC18XX_CGU_IDIV_CTRL(n) (0x048 + (n) * sizeof(u32))
+#define LPC18XX_CGU_BASE_CLK(id) (0x05c + (id) * sizeof(u32))
+#define LPC18XX_CGU_PLL_CTRL_OFFSET 0x4
+
+/* PLL0 bits common to both audio and USB PLL */
+#define LPC18XX_PLL0_STAT_LOCK BIT(0)
+#define LPC18XX_PLL0_CTRL_PD BIT(0)
+#define LPC18XX_PLL0_CTRL_BYPASS BIT(1)
+#define LPC18XX_PLL0_CTRL_DIRECTI BIT(2)
+#define LPC18XX_PLL0_CTRL_DIRECTO BIT(3)
+#define LPC18XX_PLL0_CTRL_CLKEN BIT(4)
+#define LPC18XX_PLL0_MDIV_MDEC_MASK 0x1ffff
+#define LPC18XX_PLL0_MDIV_SELP_SHIFT 17
+#define LPC18XX_PLL0_MDIV_SELI_SHIFT 22
+#define LPC18XX_PLL0_MSEL_MAX BIT(15)
+
+/* Register value that gives PLL0 post/pre dividers equal to 1 */
+#define LPC18XX_PLL0_NP_DIVS_1 0x00302062
+
+enum {
+ CLK_SRC_OSC32,
+ CLK_SRC_IRC,
+ CLK_SRC_ENET_RX_CLK,
+ CLK_SRC_ENET_TX_CLK,
+ CLK_SRC_GP_CLKIN,
+ CLK_SRC_RESERVED1,
+ CLK_SRC_OSC,
+ CLK_SRC_PLL0USB,
+ CLK_SRC_PLL0AUDIO,
+ CLK_SRC_PLL1,
+ CLK_SRC_RESERVED2,
+ CLK_SRC_RESERVED3,
+ CLK_SRC_IDIVA,
+ CLK_SRC_IDIVB,
+ CLK_SRC_IDIVC,
+ CLK_SRC_IDIVD,
+ CLK_SRC_IDIVE,
+ CLK_SRC_MAX
+};
+
+static const char *clk_src_names[CLK_SRC_MAX] = {
+ [CLK_SRC_OSC32] = "osc32",
+ [CLK_SRC_IRC] = "irc",
+ [CLK_SRC_ENET_RX_CLK] = "enet_rx_clk",
+ [CLK_SRC_ENET_TX_CLK] = "enet_tx_clk",
+ [CLK_SRC_GP_CLKIN] = "gp_clkin",
+ [CLK_SRC_OSC] = "osc",
+ [CLK_SRC_PLL0USB] = "pll0usb",
+ [CLK_SRC_PLL0AUDIO] = "pll0audio",
+ [CLK_SRC_PLL1] = "pll1",
+ [CLK_SRC_IDIVA] = "idiva",
+ [CLK_SRC_IDIVB] = "idivb",
+ [CLK_SRC_IDIVC] = "idivc",
+ [CLK_SRC_IDIVD] = "idivd",
+ [CLK_SRC_IDIVE] = "idive",
+};
+
+static const char *clk_base_names[BASE_CLK_MAX] = {
+ [BASE_SAFE_CLK] = "base_safe_clk",
+ [BASE_USB0_CLK] = "base_usb0_clk",
+ [BASE_PERIPH_CLK] = "base_periph_clk",
+ [BASE_USB1_CLK] = "base_usb1_clk",
+ [BASE_CPU_CLK] = "base_cpu_clk",
+ [BASE_SPIFI_CLK] = "base_spifi_clk",
+ [BASE_SPI_CLK] = "base_spi_clk",
+ [BASE_PHY_RX_CLK] = "base_phy_rx_clk",
+ [BASE_PHY_TX_CLK] = "base_phy_tx_clk",
+ [BASE_APB1_CLK] = "base_apb1_clk",
+ [BASE_APB3_CLK] = "base_apb3_clk",
+ [BASE_LCD_CLK] = "base_lcd_clk",
+ [BASE_ADCHS_CLK] = "base_adchs_clk",
+ [BASE_SDIO_CLK] = "base_sdio_clk",
+ [BASE_SSP0_CLK] = "base_ssp0_clk",
+ [BASE_SSP1_CLK] = "base_ssp1_clk",
+ [BASE_UART0_CLK] = "base_uart0_clk",
+ [BASE_UART1_CLK] = "base_uart1_clk",
+ [BASE_UART2_CLK] = "base_uart2_clk",
+ [BASE_UART3_CLK] = "base_uart3_clk",
+ [BASE_OUT_CLK] = "base_out_clk",
+ [BASE_AUDIO_CLK] = "base_audio_clk",
+ [BASE_CGU_OUT0_CLK] = "base_cgu_out0_clk",
+ [BASE_CGU_OUT1_CLK] = "base_cgu_out1_clk",
+};
+
+static u32 lpc18xx_cgu_pll0_src_ids[] = {
+ CLK_SRC_OSC32, CLK_SRC_IRC, CLK_SRC_ENET_RX_CLK,
+ CLK_SRC_ENET_TX_CLK, CLK_SRC_GP_CLKIN, CLK_SRC_OSC,
+ CLK_SRC_PLL1, CLK_SRC_IDIVA, CLK_SRC_IDIVB, CLK_SRC_IDIVC,
+ CLK_SRC_IDIVD, CLK_SRC_IDIVE,
+};
+
+static u32 lpc18xx_cgu_pll1_src_ids[] = {
+ CLK_SRC_OSC32, CLK_SRC_IRC, CLK_SRC_ENET_RX_CLK,
+ CLK_SRC_ENET_TX_CLK, CLK_SRC_GP_CLKIN, CLK_SRC_OSC,
+ CLK_SRC_PLL0USB, CLK_SRC_PLL0AUDIO, CLK_SRC_IDIVA,
+ CLK_SRC_IDIVB, CLK_SRC_IDIVC, CLK_SRC_IDIVD, CLK_SRC_IDIVE,
+};
+
+static u32 lpc18xx_cgu_idiva_src_ids[] = {
+ CLK_SRC_OSC32, CLK_SRC_IRC, CLK_SRC_ENET_RX_CLK,
+ CLK_SRC_ENET_TX_CLK, CLK_SRC_GP_CLKIN, CLK_SRC_OSC,
+ CLK_SRC_PLL0USB, CLK_SRC_PLL0AUDIO, CLK_SRC_PLL1
+};
+
+static u32 lpc18xx_cgu_idivbcde_src_ids[] = {
+ CLK_SRC_OSC32, CLK_SRC_IRC, CLK_SRC_ENET_RX_CLK,
+ CLK_SRC_ENET_TX_CLK, CLK_SRC_GP_CLKIN, CLK_SRC_OSC,
+ CLK_SRC_PLL0AUDIO, CLK_SRC_PLL1, CLK_SRC_IDIVA,
+};
+
+static u32 lpc18xx_cgu_base_irc_src_ids[] = {CLK_SRC_IRC};
+
+static u32 lpc18xx_cgu_base_usb0_src_ids[] = {CLK_SRC_PLL0USB};
+
+static u32 lpc18xx_cgu_base_common_src_ids[] = {
+ CLK_SRC_OSC32, CLK_SRC_IRC, CLK_SRC_ENET_RX_CLK,
+ CLK_SRC_ENET_TX_CLK, CLK_SRC_GP_CLKIN, CLK_SRC_OSC,
+ CLK_SRC_PLL0AUDIO, CLK_SRC_PLL1, CLK_SRC_IDIVA,
+ CLK_SRC_IDIVB, CLK_SRC_IDIVC, CLK_SRC_IDIVD, CLK_SRC_IDIVE,
+};
+
+static u32 lpc18xx_cgu_base_all_src_ids[] = {
+ CLK_SRC_OSC32, CLK_SRC_IRC, CLK_SRC_ENET_RX_CLK,
+ CLK_SRC_ENET_TX_CLK, CLK_SRC_GP_CLKIN, CLK_SRC_OSC,
+ CLK_SRC_PLL0USB, CLK_SRC_PLL0AUDIO, CLK_SRC_PLL1,
+ CLK_SRC_IDIVA, CLK_SRC_IDIVB, CLK_SRC_IDIVC,
+ CLK_SRC_IDIVD, CLK_SRC_IDIVE,
+};
+
+struct lpc18xx_cgu_src_clk_div {
+ u8 clk_id;
+ u8 n_parents;
+ struct clk_divider div;
+ struct clk_mux mux;
+ struct clk_gate gate;
+};
+
+#define LPC1XX_CGU_SRC_CLK_DIV(_id, _width, _table) \
+{ \
+ .clk_id = CLK_SRC_ ##_id, \
+ .n_parents = ARRAY_SIZE(lpc18xx_cgu_ ##_table), \
+ .div = { \
+ .shift = 2, \
+ .width = _width, \
+ }, \
+ .mux = { \
+ .mask = 0x1f, \
+ .shift = 24, \
+ .table = lpc18xx_cgu_ ##_table, \
+ }, \
+ .gate = { \
+ .bit_idx = 0, \
+ .flags = CLK_GATE_SET_TO_DISABLE, \
+ }, \
+}
+
+static struct lpc18xx_cgu_src_clk_div lpc18xx_cgu_src_clk_divs[] = {
+ LPC1XX_CGU_SRC_CLK_DIV(IDIVA, 2, idiva_src_ids),
+ LPC1XX_CGU_SRC_CLK_DIV(IDIVB, 4, idivbcde_src_ids),
+ LPC1XX_CGU_SRC_CLK_DIV(IDIVC, 4, idivbcde_src_ids),
+ LPC1XX_CGU_SRC_CLK_DIV(IDIVD, 4, idivbcde_src_ids),
+ LPC1XX_CGU_SRC_CLK_DIV(IDIVE, 8, idivbcde_src_ids),
+};
+
+struct lpc18xx_cgu_base_clk {
+ u8 clk_id;
+ u8 n_parents;
+ struct clk_mux mux;
+ struct clk_gate gate;
+};
+
+#define LPC1XX_CGU_BASE_CLK(_id, _table, _flags) \
+{ \
+ .clk_id = BASE_ ##_id ##_CLK, \
+ .n_parents = ARRAY_SIZE(lpc18xx_cgu_ ##_table), \
+ .mux = { \
+ .mask = 0x1f, \
+ .shift = 24, \
+ .table = lpc18xx_cgu_ ##_table, \
+ .flags = _flags, \
+ }, \
+ .gate = { \
+ .bit_idx = 0, \
+ .flags = CLK_GATE_SET_TO_DISABLE, \
+ }, \
+}
+
+static struct lpc18xx_cgu_base_clk lpc18xx_cgu_base_clks[] = {
+ LPC1XX_CGU_BASE_CLK(SAFE, base_irc_src_ids, CLK_MUX_READ_ONLY),
+ LPC1XX_CGU_BASE_CLK(USB0, base_usb0_src_ids, 0),
+ LPC1XX_CGU_BASE_CLK(PERIPH, base_common_src_ids, 0),
+ LPC1XX_CGU_BASE_CLK(USB1, base_all_src_ids, 0),
+ LPC1XX_CGU_BASE_CLK(CPU, base_common_src_ids, 0),
+ LPC1XX_CGU_BASE_CLK(SPIFI, base_common_src_ids, 0),
+ LPC1XX_CGU_BASE_CLK(SPI, base_common_src_ids, 0),
+ LPC1XX_CGU_BASE_CLK(PHY_RX, base_common_src_ids, 0),
+ LPC1XX_CGU_BASE_CLK(PHY_TX, base_common_src_ids, 0),
+ LPC1XX_CGU_BASE_CLK(APB1, base_common_src_ids, 0),
+ LPC1XX_CGU_BASE_CLK(APB3, base_common_src_ids, 0),
+ LPC1XX_CGU_BASE_CLK(LCD, base_common_src_ids, 0),
+ LPC1XX_CGU_BASE_CLK(ADCHS, base_common_src_ids, 0),
+ LPC1XX_CGU_BASE_CLK(SDIO, base_common_src_ids, 0),
+ LPC1XX_CGU_BASE_CLK(SSP0, base_common_src_ids, 0),
+ LPC1XX_CGU_BASE_CLK(SSP1, base_common_src_ids, 0),
+ LPC1XX_CGU_BASE_CLK(UART0, base_common_src_ids, 0),
+ LPC1XX_CGU_BASE_CLK(UART1, base_common_src_ids, 0),
+ LPC1XX_CGU_BASE_CLK(UART2, base_common_src_ids, 0),
+ LPC1XX_CGU_BASE_CLK(UART3, base_common_src_ids, 0),
+ LPC1XX_CGU_BASE_CLK(OUT, base_all_src_ids, 0),
+ { /* 21 reserved */ },
+ { /* 22 reserved */ },
+ { /* 23 reserved */ },
+ { /* 24 reserved */ },
+ LPC1XX_CGU_BASE_CLK(AUDIO, base_common_src_ids, 0),
+ LPC1XX_CGU_BASE_CLK(CGU_OUT0, base_all_src_ids, 0),
+ LPC1XX_CGU_BASE_CLK(CGU_OUT1, base_all_src_ids, 0),
+};
+
+struct lpc18xx_pll {
+ struct clk_hw hw;
+ void __iomem *reg;
+ spinlock_t *lock;
+ u8 flags;
+};
+
+#define to_lpc_pll(hw) container_of(hw, struct lpc18xx_pll, hw)
+
+struct lpc18xx_cgu_pll_clk {
+ u8 clk_id;
+ u8 n_parents;
+ u8 reg_offset;
+ struct clk_mux mux;
+ struct clk_gate gate;
+ struct lpc18xx_pll pll;
+ const struct clk_ops *pll_ops;
+};
+
+#define LPC1XX_CGU_CLK_PLL(_id, _table, _pll_ops) \
+{ \
+ .clk_id = CLK_SRC_ ##_id, \
+ .n_parents = ARRAY_SIZE(lpc18xx_cgu_ ##_table), \
+ .reg_offset = LPC18XX_CGU_ ##_id ##_STAT, \
+ .mux = { \
+ .mask = 0x1f, \
+ .shift = 24, \
+ .table = lpc18xx_cgu_ ##_table, \
+ }, \
+ .gate = { \
+ .bit_idx = 0, \
+ .flags = CLK_GATE_SET_TO_DISABLE, \
+ }, \
+ .pll_ops = &lpc18xx_ ##_pll_ops, \
+}
+
+/*
+ * PLL0 uses a special register value encoding. The compute functions below
+ * are taken or derived from the LPC1850 user manual (section 12.6.3.3).
+ */
+
+/* Compute PLL0 multiplier from decoded version */
+static u32 lpc18xx_pll0_mdec2msel(u32 x)
+{
+ int i;
+
+ switch (x) {
+ case 0x18003: return 1;
+ case 0x10003: return 2;
+ default:
+ for (i = LPC18XX_PLL0_MSEL_MAX + 1; x != 0x4000 && i > 0; i--)
+ x = ((x ^ x >> 14) & 1) | (x << 1 & 0x7fff);
+ return i;
+ }
+}
+/* Compute PLL0 decoded multiplier from binary version */
+static u32 lpc18xx_pll0_msel2mdec(u32 msel)
+{
+ u32 i, x = 0x4000;
+
+ switch (msel) {
+ case 0: return 0;
+ case 1: return 0x18003;
+ case 2: return 0x10003;
+ default:
+ for (i = msel; i <= LPC18XX_PLL0_MSEL_MAX; i++)
+ x = ((x ^ x >> 1) & 1) << 14 | (x >> 1 & 0xffff);
+ return x;
+ }
+}
+
+/* Compute PLL0 bandwidth SELI reg from multiplier */
+static u32 lpc18xx_pll0_msel2seli(u32 msel)
+{
+ u32 tmp;
+
+ if (msel > 16384) return 1;
+ if (msel > 8192) return 2;
+ if (msel > 2048) return 4;
+ if (msel >= 501) return 8;
+ if (msel >= 60) {
+ tmp = 1024 / (msel + 9);
+ return ((1024 == (tmp * (msel + 9))) == 0) ? tmp * 4 : (tmp + 1) * 4;
+ }
+
+ return (msel & 0x3c) + 4;
+}
+
+/* Compute PLL0 bandwidth SELP reg from multiplier */
+static u32 lpc18xx_pll0_msel2selp(u32 msel)
+{
+ if (msel < 60)
+ return (msel >> 1) + 1;
+
+ return 31;
+}
+
+static unsigned long lpc18xx_pll0_recalc_rate(struct clk_hw *hw,
+ unsigned long parent_rate)
+{
+ struct lpc18xx_pll *pll = to_lpc_pll(hw);
+ u32 ctrl, mdiv, msel, npdiv;
+
+ ctrl = clk_readl(pll->reg + LPC18XX_CGU_PLL0USB_CTRL);
+ mdiv = clk_readl(pll->reg + LPC18XX_CGU_PLL0USB_MDIV);
+ npdiv = clk_readl(pll->reg + LPC18XX_CGU_PLL0USB_NP_DIV);
+
+ if (ctrl & LPC18XX_PLL0_CTRL_BYPASS)
+ return parent_rate;
+
+ if (npdiv != LPC18XX_PLL0_NP_DIVS_1) {
+ pr_warn("%s: pre/post dividers not supported\n", __func__);
+ return 0;
+ }
+
+ msel = lpc18xx_pll0_mdec2msel(mdiv & LPC18XX_PLL0_MDIV_MDEC_MASK);
+ if (msel)
+ return 2 * msel * parent_rate;
+
+ pr_warn("%s: unable to calculate rate\n", __func__);
+
+ return 0;
+}
+
+static long lpc18xx_pll0_round_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long *prate)
+{
+ unsigned long m;
+
+ if (*prate < rate) {
+ pr_warn("%s: pll dividers not supported\n", __func__);
+ return -EINVAL;
+ }
+
+ m = DIV_ROUND_UP_ULL(*prate, rate * 2);
+ if (m <= 0 && m > LPC18XX_PLL0_MSEL_MAX) {
+ pr_warn("%s: unable to support rate %lu\n", __func__, rate);
+ return -EINVAL;
+ }
+
+ return 2 * *prate * m;
+}
+
+static int lpc18xx_pll0_set_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long parent_rate)
+{
+ struct lpc18xx_pll *pll = to_lpc_pll(hw);
+ u32 ctrl, stat, m;
+ int retry = 3;
+
+ if (parent_rate < rate) {
+ pr_warn("%s: pll dividers not supported\n", __func__);
+ return -EINVAL;
+ }
+
+ m = DIV_ROUND_UP_ULL(parent_rate, rate * 2);
+ if (m <= 0 && m > LPC18XX_PLL0_MSEL_MAX) {
+ pr_warn("%s: unable to support rate %lu\n", __func__, rate);
+ return -EINVAL;
+ }
+
+ m = lpc18xx_pll0_msel2mdec(m);
+ m |= lpc18xx_pll0_msel2selp(m) << LPC18XX_PLL0_MDIV_SELP_SHIFT;
+ m |= lpc18xx_pll0_msel2seli(m) << LPC18XX_PLL0_MDIV_SELI_SHIFT;
+
+ /* Power down PLL, disable clk output and dividers */
+ ctrl = clk_readl(pll->reg + LPC18XX_CGU_PLL0USB_CTRL);
+ ctrl |= LPC18XX_PLL0_CTRL_PD;
+ ctrl &= ~(LPC18XX_PLL0_CTRL_BYPASS | LPC18XX_PLL0_CTRL_DIRECTI |
+ LPC18XX_PLL0_CTRL_DIRECTO | LPC18XX_PLL0_CTRL_CLKEN);
+ clk_writel(ctrl, pll->reg + LPC18XX_CGU_PLL0USB_CTRL);
+
+ /* Configure new PLL settings */
+ clk_writel(m, pll->reg + LPC18XX_CGU_PLL0USB_MDIV);
+ clk_writel(LPC18XX_PLL0_NP_DIVS_1, pll->reg + LPC18XX_CGU_PLL0USB_NP_DIV);
+
+ /* Power up PLL and wait for lock */
+ ctrl &= ~LPC18XX_PLL0_CTRL_PD;
+ clk_writel(ctrl, pll->reg + LPC18XX_CGU_PLL0USB_CTRL);
+ do {
+ udelay(10);
+ stat = clk_readl(pll->reg + LPC18XX_CGU_PLL0USB_STAT);
+ if (stat & LPC18XX_PLL0_STAT_LOCK) {
+ ctrl |= LPC18XX_PLL0_CTRL_CLKEN;
+ clk_writel(ctrl, pll->reg + LPC18XX_CGU_PLL0USB_CTRL);
+
+ return 0;
+ }
+ } while (retry--);
+
+ pr_warn("%s: unable to lock pll\n", __func__);
+
+ return -EINVAL;
+}
+
+static const struct clk_ops lpc18xx_pll0_ops = {
+ .recalc_rate = lpc18xx_pll0_recalc_rate,
+ .round_rate = lpc18xx_pll0_round_rate,
+ .set_rate = lpc18xx_pll0_set_rate,
+};
+
+static unsigned long lpc18xx_pll1_recalc_rate(struct clk_hw *hw,
+ unsigned long parent_rate)
+{
+ struct lpc18xx_pll *pll = to_lpc_pll(hw);
+ u16 msel, nsel, psel;
+ bool direct, fbsel;
+ u32 stat, ctrl;
+
+ stat = clk_readl(pll->reg + LPC18XX_CGU_PLL1_STAT);
+ ctrl = clk_readl(pll->reg + LPC18XX_CGU_PLL1_CTRL);
+
+ direct = (ctrl & LPC18XX_PLL1_CTRL_DIRECT) ? true : false;
+ fbsel = (ctrl & LPC18XX_PLL1_CTRL_FBSEL) ? true : false;
+
+ msel = ((ctrl >> 16) & 0xff) + 1;
+ nsel = ((ctrl >> 12) & 0x3) + 1;
+
+ if (direct || fbsel)
+ return msel * (parent_rate / nsel);
+
+ psel = (ctrl >> 8) & 0x3;
+ psel = 1 << psel;
+
+ return (msel / (2 * psel)) * (parent_rate / nsel);
+}
+
+static const struct clk_ops lpc18xx_pll1_ops = {
+ .recalc_rate = lpc18xx_pll1_recalc_rate,
+};
+
+static struct lpc18xx_cgu_pll_clk lpc18xx_cgu_src_clk_plls[] = {
+ LPC1XX_CGU_CLK_PLL(PLL0USB, pll0_src_ids, pll0_ops),
+ LPC1XX_CGU_CLK_PLL(PLL0AUDIO, pll0_src_ids, pll0_ops),
+ LPC1XX_CGU_CLK_PLL(PLL1, pll1_src_ids, pll1_ops),
+};
+
+static void lpc18xx_fill_parent_names(const char **parent, u32 *id, int size)
+{
+ int i;
+
+ for (i = 0; i < size; i++)
+ parent[i] = clk_src_names[id[i]];
+}
+
+static struct clk *lpc18xx_cgu_register_div(struct lpc18xx_cgu_src_clk_div *clk,
+ void __iomem *base, int n)
+{
+ void __iomem *reg = base + LPC18XX_CGU_IDIV_CTRL(n);
+ const char *name = clk_src_names[clk->clk_id];
+ const char *parents[CLK_SRC_MAX];
+
+ clk->div.reg = reg;
+ clk->mux.reg = reg;
+ clk->gate.reg = reg;
+
+ lpc18xx_fill_parent_names(parents, clk->mux.table, clk->n_parents);
+
+ return clk_register_composite(NULL, name, parents, clk->n_parents,
+ &clk->mux.hw, &clk_mux_ops,
+ &clk->div.hw, &clk_divider_ops,
+ &clk->gate.hw, &clk_gate_ops, 0);
+}
+
+
+static struct clk *lpc18xx_register_base_clk(struct lpc18xx_cgu_base_clk *clk,
+ void __iomem *reg_base, int n)
+{
+ void __iomem *reg = reg_base + LPC18XX_CGU_BASE_CLK(n);
+ const char *name = clk_base_names[clk->clk_id];
+ const char *parents[CLK_SRC_MAX];
+
+ if (clk->n_parents == 0)
+ return ERR_PTR(-ENOENT);
+
+ clk->mux.reg = reg;
+ clk->gate.reg = reg;
+
+ lpc18xx_fill_parent_names(parents, clk->mux.table, clk->n_parents);
+
+ /* SAFE_CLK can not be turned off */
+ if (n == BASE_SAFE_CLK)
+ return clk_register_composite(NULL, name, parents, clk->n_parents,
+ &clk->mux.hw, &clk_mux_ops,
+ NULL, NULL, NULL, NULL, 0);
+
+ return clk_register_composite(NULL, name, parents, clk->n_parents,
+ &clk->mux.hw, &clk_mux_ops,
+ NULL, NULL,
+ &clk->gate.hw, &clk_gate_ops, 0);
+}
+
+
+static struct clk *lpc18xx_cgu_register_pll(struct lpc18xx_cgu_pll_clk *clk,
+ void __iomem *base)
+{
+ const char *name = clk_src_names[clk->clk_id];
+ const char *parents[CLK_SRC_MAX];
+
+ clk->pll.reg = base;
+ clk->mux.reg = base + clk->reg_offset + LPC18XX_CGU_PLL_CTRL_OFFSET;
+ clk->gate.reg = base + clk->reg_offset + LPC18XX_CGU_PLL_CTRL_OFFSET;
+
+ lpc18xx_fill_parent_names(parents, clk->mux.table, clk->n_parents);
+
+ return clk_register_composite(NULL, name, parents, clk->n_parents,
+ &clk->mux.hw, &clk_mux_ops,
+ &clk->pll.hw, clk->pll_ops,
+ &clk->gate.hw, &clk_gate_ops, 0);
+}
+
+static void __init lpc18xx_cgu_register_source_clks(struct device_node *np,
+ void __iomem *base)
+{
+ const char *parents[CLK_SRC_MAX];
+ struct clk *clk;
+ int i;
+
+ /* Register the internal 12 MHz RC oscillator (IRC) */
+ clk = clk_register_fixed_rate(NULL, clk_src_names[CLK_SRC_IRC],
+ NULL, CLK_IS_ROOT, 12000000);
+ if (IS_ERR(clk))
+ pr_warn("%s: failed to register irc clk\n", __func__);
+
+ /* Register crystal oscillator controlller */
+ parents[0] = of_clk_get_parent_name(np, 0);
+ clk = clk_register_gate(NULL, clk_src_names[CLK_SRC_OSC], parents[0],
+ 0, base + LPC18XX_CGU_XTAL_OSC_CTRL,
+ 0, CLK_GATE_SET_TO_DISABLE, NULL);
+ if (IS_ERR(clk))
+ pr_warn("%s: failed to register osc clk\n", __func__);
+
+ /* Register all PLLs */
+ for (i = 0; i < ARRAY_SIZE(lpc18xx_cgu_src_clk_plls); i++) {
+ clk = lpc18xx_cgu_register_pll(&lpc18xx_cgu_src_clk_plls[i],
+ base);
+ if (IS_ERR(clk))
+ pr_warn("%s: failed to register pll (%d)\n", __func__, i);
+ }
+
+ /* Register all clock dividers A-E */
+ for (i = 0; i < ARRAY_SIZE(lpc18xx_cgu_src_clk_divs); i++) {
+ clk = lpc18xx_cgu_register_div(&lpc18xx_cgu_src_clk_divs[i],
+ base, i);
+ if (IS_ERR(clk))
+ pr_warn("%s: failed to register div %d\n", __func__, i);
+ }
+}
+
+static struct clk *clk_base[BASE_CLK_MAX];
+static struct clk_onecell_data clk_base_data = {
+ .clks = clk_base,
+ .clk_num = BASE_CLK_MAX,
+};
+
+static void __init lpc18xx_cgu_register_base_clks(void __iomem *reg_base)
+{
+ int i;
+
+ for (i = BASE_SAFE_CLK; i < BASE_CLK_MAX; i++) {
+ clk_base[i] = lpc18xx_register_base_clk(&lpc18xx_cgu_base_clks[i],
+ reg_base, i);
+ if (IS_ERR(clk_base[i]) && PTR_ERR(clk_base[i]) != -ENOENT)
+ pr_warn("%s: register base clk %d failed\n", __func__, i);
+ }
+}
+
+static void __init lpc18xx_cgu_init(struct device_node *np)
+{
+ void __iomem *reg_base;
+
+ reg_base = of_iomap(np, 0);
+ if (!reg_base) {
+ pr_warn("%s: failed to map address range\n", __func__);
+ return;
+ }
+
+ lpc18xx_cgu_register_source_clks(np, reg_base);
+ lpc18xx_cgu_register_base_clks(reg_base);
+
+ of_clk_add_provider(np, of_clk_src_onecell_get, &clk_base_data);
+}
+CLK_OF_DECLARE(lpc18xx_cgu, "nxp,lpc1850-cgu", lpc18xx_cgu_init);
diff --git a/include/dt-bindings/clock/lpc18xx-cgu.h b/include/dt-bindings/clock/lpc18xx-cgu.h
new file mode 100644
index 000000000000..6e57c6d2ca66
--- /dev/null
+++ b/include/dt-bindings/clock/lpc18xx-cgu.h
@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) 2015 Joachim Eastwood <manabian-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
+ *
+ * This code is released using a dual license strategy: BSD/GPL
+ * You can choose the licence that better fits your requirements.
+ *
+ * Released under the terms of 3-clause BSD License
+ * Released under the terms of GNU General Public License Version 2.0
+ *
+ */
+
+/* LPC18xx/43xx base clock ids */
+#define BASE_SAFE_CLK 0
+#define BASE_USB0_CLK 1
+#define BASE_PERIPH_CLK 2
+#define BASE_USB1_CLK 3
+#define BASE_CPU_CLK 4
+#define BASE_SPIFI_CLK 5
+#define BASE_SPI_CLK 6
+#define BASE_PHY_RX_CLK 7
+#define BASE_PHY_TX_CLK 8
+#define BASE_APB1_CLK 9
+#define BASE_APB3_CLK 10
+#define BASE_LCD_CLK 11
+#define BASE_ADCHS_CLK 12
+#define BASE_SDIO_CLK 13
+#define BASE_SSP0_CLK 14
+#define BASE_SSP1_CLK 15
+#define BASE_UART0_CLK 16
+#define BASE_UART1_CLK 17
+#define BASE_UART2_CLK 18
+#define BASE_UART3_CLK 19
+#define BASE_OUT_CLK 20
+#define BASE_RES1_CLK 21
+#define BASE_RES2_CLK 22
+#define BASE_RES3_CLK 23
+#define BASE_RES4_CLK 24
+#define BASE_AUDIO_CLK 25
+#define BASE_CGU_OUT0_CLK 26
+#define BASE_CGU_OUT1_CLK 27
+#define BASE_CLK_MAX (BASE_CGU_OUT1_CLK + 1)
--
1.8.0
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply related [flat|nested] 30+ messages in thread
* [PATCH v4 1/5] clk: add lpc18xx cgu clk driver
@ 2015-05-28 20:31 ` Joachim Eastwood
0 siblings, 0 replies; 30+ messages in thread
From: Joachim Eastwood @ 2015-05-28 20:31 UTC (permalink / raw)
To: mturquette, sboyd
Cc: Joachim Eastwood, linux-clk, devicetree, linux-arm-kernel
Add driver for NXP LPC18xx/43xx Clock Generation Unit (CGU). The CGU
contains several clock generators and output stages that route the
clocks either directly to peripherals or to a Clock Control Unit
(CCU).
Signed-off-by: Joachim Eastwood <manabian@gmail.com>
---
drivers/clk/Makefile | 1 +
drivers/clk/nxp/Makefile | 1 +
drivers/clk/nxp/clk-lpc18xx-cgu.c | 635 ++++++++++++++++++++++++++++++++
include/dt-bindings/clock/lpc18xx-cgu.h | 41 +++
4 files changed, 678 insertions(+)
create mode 100644 drivers/clk/nxp/Makefile
create mode 100644 drivers/clk/nxp/clk-lpc18xx-cgu.c
create mode 100644 include/dt-bindings/clock/lpc18xx-cgu.h
diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile
index 3d00c25382c5..4a34419c1da1 100644
--- a/drivers/clk/Makefile
+++ b/drivers/clk/Makefile
@@ -56,6 +56,7 @@ obj-$(CONFIG_ARCH_MMP) += mmp/
endif
obj-$(CONFIG_PLAT_ORION) += mvebu/
obj-$(CONFIG_ARCH_MXS) += mxs/
+obj-$(CONFIG_ARCH_LPC18XX) += nxp/
obj-$(CONFIG_MACH_PISTACHIO) += pistachio/
obj-$(CONFIG_COMMON_CLK_PXA) += pxa/
obj-$(CONFIG_COMMON_CLK_QCOM) += qcom/
diff --git a/drivers/clk/nxp/Makefile b/drivers/clk/nxp/Makefile
new file mode 100644
index 000000000000..aca9d3e4f7fe
--- /dev/null
+++ b/drivers/clk/nxp/Makefile
@@ -0,0 +1 @@
+obj-$(CONFIG_ARCH_LPC18XX) += clk-lpc18xx-cgu.o
diff --git a/drivers/clk/nxp/clk-lpc18xx-cgu.c b/drivers/clk/nxp/clk-lpc18xx-cgu.c
new file mode 100644
index 000000000000..81e9e1c788f4
--- /dev/null
+++ b/drivers/clk/nxp/clk-lpc18xx-cgu.c
@@ -0,0 +1,635 @@
+/*
+ * Clk driver for NXP LPC18xx/LPC43xx Clock Generation Unit (CGU)
+ *
+ * Copyright (C) 2015 Joachim Eastwood <manabian@gmail.com>
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2. This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+#include <linux/clk.h>
+#include <linux/clk-provider.h>
+#include <linux/delay.h>
+#include <linux/kernel.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+
+#include <dt-bindings/clock/lpc18xx-cgu.h>
+
+/* Clock Generation Unit (CGU) registers */
+#define LPC18XX_CGU_XTAL_OSC_CTRL 0x018
+#define LPC18XX_CGU_PLL0USB_STAT 0x01c
+#define LPC18XX_CGU_PLL0USB_CTRL 0x020
+#define LPC18XX_CGU_PLL0USB_MDIV 0x024
+#define LPC18XX_CGU_PLL0USB_NP_DIV 0x028
+#define LPC18XX_CGU_PLL0AUDIO_STAT 0x02c
+#define LPC18XX_CGU_PLL0AUDIO_CTRL 0x030
+#define LPC18XX_CGU_PLL0AUDIO_MDIV 0x034
+#define LPC18XX_CGU_PLL0AUDIO_NP_DIV 0x038
+#define LPC18XX_CGU_PLL0AUDIO_FRAC 0x03c
+#define LPC18XX_CGU_PLL1_STAT 0x040
+#define LPC18XX_CGU_PLL1_CTRL 0x044
+#define LPC18XX_PLL1_CTRL_FBSEL BIT(6)
+#define LPC18XX_PLL1_CTRL_DIRECT BIT(7)
+#define LPC18XX_CGU_IDIV_CTRL(n) (0x048 + (n) * sizeof(u32))
+#define LPC18XX_CGU_BASE_CLK(id) (0x05c + (id) * sizeof(u32))
+#define LPC18XX_CGU_PLL_CTRL_OFFSET 0x4
+
+/* PLL0 bits common to both audio and USB PLL */
+#define LPC18XX_PLL0_STAT_LOCK BIT(0)
+#define LPC18XX_PLL0_CTRL_PD BIT(0)
+#define LPC18XX_PLL0_CTRL_BYPASS BIT(1)
+#define LPC18XX_PLL0_CTRL_DIRECTI BIT(2)
+#define LPC18XX_PLL0_CTRL_DIRECTO BIT(3)
+#define LPC18XX_PLL0_CTRL_CLKEN BIT(4)
+#define LPC18XX_PLL0_MDIV_MDEC_MASK 0x1ffff
+#define LPC18XX_PLL0_MDIV_SELP_SHIFT 17
+#define LPC18XX_PLL0_MDIV_SELI_SHIFT 22
+#define LPC18XX_PLL0_MSEL_MAX BIT(15)
+
+/* Register value that gives PLL0 post/pre dividers equal to 1 */
+#define LPC18XX_PLL0_NP_DIVS_1 0x00302062
+
+enum {
+ CLK_SRC_OSC32,
+ CLK_SRC_IRC,
+ CLK_SRC_ENET_RX_CLK,
+ CLK_SRC_ENET_TX_CLK,
+ CLK_SRC_GP_CLKIN,
+ CLK_SRC_RESERVED1,
+ CLK_SRC_OSC,
+ CLK_SRC_PLL0USB,
+ CLK_SRC_PLL0AUDIO,
+ CLK_SRC_PLL1,
+ CLK_SRC_RESERVED2,
+ CLK_SRC_RESERVED3,
+ CLK_SRC_IDIVA,
+ CLK_SRC_IDIVB,
+ CLK_SRC_IDIVC,
+ CLK_SRC_IDIVD,
+ CLK_SRC_IDIVE,
+ CLK_SRC_MAX
+};
+
+static const char *clk_src_names[CLK_SRC_MAX] = {
+ [CLK_SRC_OSC32] = "osc32",
+ [CLK_SRC_IRC] = "irc",
+ [CLK_SRC_ENET_RX_CLK] = "enet_rx_clk",
+ [CLK_SRC_ENET_TX_CLK] = "enet_tx_clk",
+ [CLK_SRC_GP_CLKIN] = "gp_clkin",
+ [CLK_SRC_OSC] = "osc",
+ [CLK_SRC_PLL0USB] = "pll0usb",
+ [CLK_SRC_PLL0AUDIO] = "pll0audio",
+ [CLK_SRC_PLL1] = "pll1",
+ [CLK_SRC_IDIVA] = "idiva",
+ [CLK_SRC_IDIVB] = "idivb",
+ [CLK_SRC_IDIVC] = "idivc",
+ [CLK_SRC_IDIVD] = "idivd",
+ [CLK_SRC_IDIVE] = "idive",
+};
+
+static const char *clk_base_names[BASE_CLK_MAX] = {
+ [BASE_SAFE_CLK] = "base_safe_clk",
+ [BASE_USB0_CLK] = "base_usb0_clk",
+ [BASE_PERIPH_CLK] = "base_periph_clk",
+ [BASE_USB1_CLK] = "base_usb1_clk",
+ [BASE_CPU_CLK] = "base_cpu_clk",
+ [BASE_SPIFI_CLK] = "base_spifi_clk",
+ [BASE_SPI_CLK] = "base_spi_clk",
+ [BASE_PHY_RX_CLK] = "base_phy_rx_clk",
+ [BASE_PHY_TX_CLK] = "base_phy_tx_clk",
+ [BASE_APB1_CLK] = "base_apb1_clk",
+ [BASE_APB3_CLK] = "base_apb3_clk",
+ [BASE_LCD_CLK] = "base_lcd_clk",
+ [BASE_ADCHS_CLK] = "base_adchs_clk",
+ [BASE_SDIO_CLK] = "base_sdio_clk",
+ [BASE_SSP0_CLK] = "base_ssp0_clk",
+ [BASE_SSP1_CLK] = "base_ssp1_clk",
+ [BASE_UART0_CLK] = "base_uart0_clk",
+ [BASE_UART1_CLK] = "base_uart1_clk",
+ [BASE_UART2_CLK] = "base_uart2_clk",
+ [BASE_UART3_CLK] = "base_uart3_clk",
+ [BASE_OUT_CLK] = "base_out_clk",
+ [BASE_AUDIO_CLK] = "base_audio_clk",
+ [BASE_CGU_OUT0_CLK] = "base_cgu_out0_clk",
+ [BASE_CGU_OUT1_CLK] = "base_cgu_out1_clk",
+};
+
+static u32 lpc18xx_cgu_pll0_src_ids[] = {
+ CLK_SRC_OSC32, CLK_SRC_IRC, CLK_SRC_ENET_RX_CLK,
+ CLK_SRC_ENET_TX_CLK, CLK_SRC_GP_CLKIN, CLK_SRC_OSC,
+ CLK_SRC_PLL1, CLK_SRC_IDIVA, CLK_SRC_IDIVB, CLK_SRC_IDIVC,
+ CLK_SRC_IDIVD, CLK_SRC_IDIVE,
+};
+
+static u32 lpc18xx_cgu_pll1_src_ids[] = {
+ CLK_SRC_OSC32, CLK_SRC_IRC, CLK_SRC_ENET_RX_CLK,
+ CLK_SRC_ENET_TX_CLK, CLK_SRC_GP_CLKIN, CLK_SRC_OSC,
+ CLK_SRC_PLL0USB, CLK_SRC_PLL0AUDIO, CLK_SRC_IDIVA,
+ CLK_SRC_IDIVB, CLK_SRC_IDIVC, CLK_SRC_IDIVD, CLK_SRC_IDIVE,
+};
+
+static u32 lpc18xx_cgu_idiva_src_ids[] = {
+ CLK_SRC_OSC32, CLK_SRC_IRC, CLK_SRC_ENET_RX_CLK,
+ CLK_SRC_ENET_TX_CLK, CLK_SRC_GP_CLKIN, CLK_SRC_OSC,
+ CLK_SRC_PLL0USB, CLK_SRC_PLL0AUDIO, CLK_SRC_PLL1
+};
+
+static u32 lpc18xx_cgu_idivbcde_src_ids[] = {
+ CLK_SRC_OSC32, CLK_SRC_IRC, CLK_SRC_ENET_RX_CLK,
+ CLK_SRC_ENET_TX_CLK, CLK_SRC_GP_CLKIN, CLK_SRC_OSC,
+ CLK_SRC_PLL0AUDIO, CLK_SRC_PLL1, CLK_SRC_IDIVA,
+};
+
+static u32 lpc18xx_cgu_base_irc_src_ids[] = {CLK_SRC_IRC};
+
+static u32 lpc18xx_cgu_base_usb0_src_ids[] = {CLK_SRC_PLL0USB};
+
+static u32 lpc18xx_cgu_base_common_src_ids[] = {
+ CLK_SRC_OSC32, CLK_SRC_IRC, CLK_SRC_ENET_RX_CLK,
+ CLK_SRC_ENET_TX_CLK, CLK_SRC_GP_CLKIN, CLK_SRC_OSC,
+ CLK_SRC_PLL0AUDIO, CLK_SRC_PLL1, CLK_SRC_IDIVA,
+ CLK_SRC_IDIVB, CLK_SRC_IDIVC, CLK_SRC_IDIVD, CLK_SRC_IDIVE,
+};
+
+static u32 lpc18xx_cgu_base_all_src_ids[] = {
+ CLK_SRC_OSC32, CLK_SRC_IRC, CLK_SRC_ENET_RX_CLK,
+ CLK_SRC_ENET_TX_CLK, CLK_SRC_GP_CLKIN, CLK_SRC_OSC,
+ CLK_SRC_PLL0USB, CLK_SRC_PLL0AUDIO, CLK_SRC_PLL1,
+ CLK_SRC_IDIVA, CLK_SRC_IDIVB, CLK_SRC_IDIVC,
+ CLK_SRC_IDIVD, CLK_SRC_IDIVE,
+};
+
+struct lpc18xx_cgu_src_clk_div {
+ u8 clk_id;
+ u8 n_parents;
+ struct clk_divider div;
+ struct clk_mux mux;
+ struct clk_gate gate;
+};
+
+#define LPC1XX_CGU_SRC_CLK_DIV(_id, _width, _table) \
+{ \
+ .clk_id = CLK_SRC_ ##_id, \
+ .n_parents = ARRAY_SIZE(lpc18xx_cgu_ ##_table), \
+ .div = { \
+ .shift = 2, \
+ .width = _width, \
+ }, \
+ .mux = { \
+ .mask = 0x1f, \
+ .shift = 24, \
+ .table = lpc18xx_cgu_ ##_table, \
+ }, \
+ .gate = { \
+ .bit_idx = 0, \
+ .flags = CLK_GATE_SET_TO_DISABLE, \
+ }, \
+}
+
+static struct lpc18xx_cgu_src_clk_div lpc18xx_cgu_src_clk_divs[] = {
+ LPC1XX_CGU_SRC_CLK_DIV(IDIVA, 2, idiva_src_ids),
+ LPC1XX_CGU_SRC_CLK_DIV(IDIVB, 4, idivbcde_src_ids),
+ LPC1XX_CGU_SRC_CLK_DIV(IDIVC, 4, idivbcde_src_ids),
+ LPC1XX_CGU_SRC_CLK_DIV(IDIVD, 4, idivbcde_src_ids),
+ LPC1XX_CGU_SRC_CLK_DIV(IDIVE, 8, idivbcde_src_ids),
+};
+
+struct lpc18xx_cgu_base_clk {
+ u8 clk_id;
+ u8 n_parents;
+ struct clk_mux mux;
+ struct clk_gate gate;
+};
+
+#define LPC1XX_CGU_BASE_CLK(_id, _table, _flags) \
+{ \
+ .clk_id = BASE_ ##_id ##_CLK, \
+ .n_parents = ARRAY_SIZE(lpc18xx_cgu_ ##_table), \
+ .mux = { \
+ .mask = 0x1f, \
+ .shift = 24, \
+ .table = lpc18xx_cgu_ ##_table, \
+ .flags = _flags, \
+ }, \
+ .gate = { \
+ .bit_idx = 0, \
+ .flags = CLK_GATE_SET_TO_DISABLE, \
+ }, \
+}
+
+static struct lpc18xx_cgu_base_clk lpc18xx_cgu_base_clks[] = {
+ LPC1XX_CGU_BASE_CLK(SAFE, base_irc_src_ids, CLK_MUX_READ_ONLY),
+ LPC1XX_CGU_BASE_CLK(USB0, base_usb0_src_ids, 0),
+ LPC1XX_CGU_BASE_CLK(PERIPH, base_common_src_ids, 0),
+ LPC1XX_CGU_BASE_CLK(USB1, base_all_src_ids, 0),
+ LPC1XX_CGU_BASE_CLK(CPU, base_common_src_ids, 0),
+ LPC1XX_CGU_BASE_CLK(SPIFI, base_common_src_ids, 0),
+ LPC1XX_CGU_BASE_CLK(SPI, base_common_src_ids, 0),
+ LPC1XX_CGU_BASE_CLK(PHY_RX, base_common_src_ids, 0),
+ LPC1XX_CGU_BASE_CLK(PHY_TX, base_common_src_ids, 0),
+ LPC1XX_CGU_BASE_CLK(APB1, base_common_src_ids, 0),
+ LPC1XX_CGU_BASE_CLK(APB3, base_common_src_ids, 0),
+ LPC1XX_CGU_BASE_CLK(LCD, base_common_src_ids, 0),
+ LPC1XX_CGU_BASE_CLK(ADCHS, base_common_src_ids, 0),
+ LPC1XX_CGU_BASE_CLK(SDIO, base_common_src_ids, 0),
+ LPC1XX_CGU_BASE_CLK(SSP0, base_common_src_ids, 0),
+ LPC1XX_CGU_BASE_CLK(SSP1, base_common_src_ids, 0),
+ LPC1XX_CGU_BASE_CLK(UART0, base_common_src_ids, 0),
+ LPC1XX_CGU_BASE_CLK(UART1, base_common_src_ids, 0),
+ LPC1XX_CGU_BASE_CLK(UART2, base_common_src_ids, 0),
+ LPC1XX_CGU_BASE_CLK(UART3, base_common_src_ids, 0),
+ LPC1XX_CGU_BASE_CLK(OUT, base_all_src_ids, 0),
+ { /* 21 reserved */ },
+ { /* 22 reserved */ },
+ { /* 23 reserved */ },
+ { /* 24 reserved */ },
+ LPC1XX_CGU_BASE_CLK(AUDIO, base_common_src_ids, 0),
+ LPC1XX_CGU_BASE_CLK(CGU_OUT0, base_all_src_ids, 0),
+ LPC1XX_CGU_BASE_CLK(CGU_OUT1, base_all_src_ids, 0),
+};
+
+struct lpc18xx_pll {
+ struct clk_hw hw;
+ void __iomem *reg;
+ spinlock_t *lock;
+ u8 flags;
+};
+
+#define to_lpc_pll(hw) container_of(hw, struct lpc18xx_pll, hw)
+
+struct lpc18xx_cgu_pll_clk {
+ u8 clk_id;
+ u8 n_parents;
+ u8 reg_offset;
+ struct clk_mux mux;
+ struct clk_gate gate;
+ struct lpc18xx_pll pll;
+ const struct clk_ops *pll_ops;
+};
+
+#define LPC1XX_CGU_CLK_PLL(_id, _table, _pll_ops) \
+{ \
+ .clk_id = CLK_SRC_ ##_id, \
+ .n_parents = ARRAY_SIZE(lpc18xx_cgu_ ##_table), \
+ .reg_offset = LPC18XX_CGU_ ##_id ##_STAT, \
+ .mux = { \
+ .mask = 0x1f, \
+ .shift = 24, \
+ .table = lpc18xx_cgu_ ##_table, \
+ }, \
+ .gate = { \
+ .bit_idx = 0, \
+ .flags = CLK_GATE_SET_TO_DISABLE, \
+ }, \
+ .pll_ops = &lpc18xx_ ##_pll_ops, \
+}
+
+/*
+ * PLL0 uses a special register value encoding. The compute functions below
+ * are taken or derived from the LPC1850 user manual (section 12.6.3.3).
+ */
+
+/* Compute PLL0 multiplier from decoded version */
+static u32 lpc18xx_pll0_mdec2msel(u32 x)
+{
+ int i;
+
+ switch (x) {
+ case 0x18003: return 1;
+ case 0x10003: return 2;
+ default:
+ for (i = LPC18XX_PLL0_MSEL_MAX + 1; x != 0x4000 && i > 0; i--)
+ x = ((x ^ x >> 14) & 1) | (x << 1 & 0x7fff);
+ return i;
+ }
+}
+/* Compute PLL0 decoded multiplier from binary version */
+static u32 lpc18xx_pll0_msel2mdec(u32 msel)
+{
+ u32 i, x = 0x4000;
+
+ switch (msel) {
+ case 0: return 0;
+ case 1: return 0x18003;
+ case 2: return 0x10003;
+ default:
+ for (i = msel; i <= LPC18XX_PLL0_MSEL_MAX; i++)
+ x = ((x ^ x >> 1) & 1) << 14 | (x >> 1 & 0xffff);
+ return x;
+ }
+}
+
+/* Compute PLL0 bandwidth SELI reg from multiplier */
+static u32 lpc18xx_pll0_msel2seli(u32 msel)
+{
+ u32 tmp;
+
+ if (msel > 16384) return 1;
+ if (msel > 8192) return 2;
+ if (msel > 2048) return 4;
+ if (msel >= 501) return 8;
+ if (msel >= 60) {
+ tmp = 1024 / (msel + 9);
+ return ((1024 == (tmp * (msel + 9))) == 0) ? tmp * 4 : (tmp + 1) * 4;
+ }
+
+ return (msel & 0x3c) + 4;
+}
+
+/* Compute PLL0 bandwidth SELP reg from multiplier */
+static u32 lpc18xx_pll0_msel2selp(u32 msel)
+{
+ if (msel < 60)
+ return (msel >> 1) + 1;
+
+ return 31;
+}
+
+static unsigned long lpc18xx_pll0_recalc_rate(struct clk_hw *hw,
+ unsigned long parent_rate)
+{
+ struct lpc18xx_pll *pll = to_lpc_pll(hw);
+ u32 ctrl, mdiv, msel, npdiv;
+
+ ctrl = clk_readl(pll->reg + LPC18XX_CGU_PLL0USB_CTRL);
+ mdiv = clk_readl(pll->reg + LPC18XX_CGU_PLL0USB_MDIV);
+ npdiv = clk_readl(pll->reg + LPC18XX_CGU_PLL0USB_NP_DIV);
+
+ if (ctrl & LPC18XX_PLL0_CTRL_BYPASS)
+ return parent_rate;
+
+ if (npdiv != LPC18XX_PLL0_NP_DIVS_1) {
+ pr_warn("%s: pre/post dividers not supported\n", __func__);
+ return 0;
+ }
+
+ msel = lpc18xx_pll0_mdec2msel(mdiv & LPC18XX_PLL0_MDIV_MDEC_MASK);
+ if (msel)
+ return 2 * msel * parent_rate;
+
+ pr_warn("%s: unable to calculate rate\n", __func__);
+
+ return 0;
+}
+
+static long lpc18xx_pll0_round_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long *prate)
+{
+ unsigned long m;
+
+ if (*prate < rate) {
+ pr_warn("%s: pll dividers not supported\n", __func__);
+ return -EINVAL;
+ }
+
+ m = DIV_ROUND_UP_ULL(*prate, rate * 2);
+ if (m <= 0 && m > LPC18XX_PLL0_MSEL_MAX) {
+ pr_warn("%s: unable to support rate %lu\n", __func__, rate);
+ return -EINVAL;
+ }
+
+ return 2 * *prate * m;
+}
+
+static int lpc18xx_pll0_set_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long parent_rate)
+{
+ struct lpc18xx_pll *pll = to_lpc_pll(hw);
+ u32 ctrl, stat, m;
+ int retry = 3;
+
+ if (parent_rate < rate) {
+ pr_warn("%s: pll dividers not supported\n", __func__);
+ return -EINVAL;
+ }
+
+ m = DIV_ROUND_UP_ULL(parent_rate, rate * 2);
+ if (m <= 0 && m > LPC18XX_PLL0_MSEL_MAX) {
+ pr_warn("%s: unable to support rate %lu\n", __func__, rate);
+ return -EINVAL;
+ }
+
+ m = lpc18xx_pll0_msel2mdec(m);
+ m |= lpc18xx_pll0_msel2selp(m) << LPC18XX_PLL0_MDIV_SELP_SHIFT;
+ m |= lpc18xx_pll0_msel2seli(m) << LPC18XX_PLL0_MDIV_SELI_SHIFT;
+
+ /* Power down PLL, disable clk output and dividers */
+ ctrl = clk_readl(pll->reg + LPC18XX_CGU_PLL0USB_CTRL);
+ ctrl |= LPC18XX_PLL0_CTRL_PD;
+ ctrl &= ~(LPC18XX_PLL0_CTRL_BYPASS | LPC18XX_PLL0_CTRL_DIRECTI |
+ LPC18XX_PLL0_CTRL_DIRECTO | LPC18XX_PLL0_CTRL_CLKEN);
+ clk_writel(ctrl, pll->reg + LPC18XX_CGU_PLL0USB_CTRL);
+
+ /* Configure new PLL settings */
+ clk_writel(m, pll->reg + LPC18XX_CGU_PLL0USB_MDIV);
+ clk_writel(LPC18XX_PLL0_NP_DIVS_1, pll->reg + LPC18XX_CGU_PLL0USB_NP_DIV);
+
+ /* Power up PLL and wait for lock */
+ ctrl &= ~LPC18XX_PLL0_CTRL_PD;
+ clk_writel(ctrl, pll->reg + LPC18XX_CGU_PLL0USB_CTRL);
+ do {
+ udelay(10);
+ stat = clk_readl(pll->reg + LPC18XX_CGU_PLL0USB_STAT);
+ if (stat & LPC18XX_PLL0_STAT_LOCK) {
+ ctrl |= LPC18XX_PLL0_CTRL_CLKEN;
+ clk_writel(ctrl, pll->reg + LPC18XX_CGU_PLL0USB_CTRL);
+
+ return 0;
+ }
+ } while (retry--);
+
+ pr_warn("%s: unable to lock pll\n", __func__);
+
+ return -EINVAL;
+}
+
+static const struct clk_ops lpc18xx_pll0_ops = {
+ .recalc_rate = lpc18xx_pll0_recalc_rate,
+ .round_rate = lpc18xx_pll0_round_rate,
+ .set_rate = lpc18xx_pll0_set_rate,
+};
+
+static unsigned long lpc18xx_pll1_recalc_rate(struct clk_hw *hw,
+ unsigned long parent_rate)
+{
+ struct lpc18xx_pll *pll = to_lpc_pll(hw);
+ u16 msel, nsel, psel;
+ bool direct, fbsel;
+ u32 stat, ctrl;
+
+ stat = clk_readl(pll->reg + LPC18XX_CGU_PLL1_STAT);
+ ctrl = clk_readl(pll->reg + LPC18XX_CGU_PLL1_CTRL);
+
+ direct = (ctrl & LPC18XX_PLL1_CTRL_DIRECT) ? true : false;
+ fbsel = (ctrl & LPC18XX_PLL1_CTRL_FBSEL) ? true : false;
+
+ msel = ((ctrl >> 16) & 0xff) + 1;
+ nsel = ((ctrl >> 12) & 0x3) + 1;
+
+ if (direct || fbsel)
+ return msel * (parent_rate / nsel);
+
+ psel = (ctrl >> 8) & 0x3;
+ psel = 1 << psel;
+
+ return (msel / (2 * psel)) * (parent_rate / nsel);
+}
+
+static const struct clk_ops lpc18xx_pll1_ops = {
+ .recalc_rate = lpc18xx_pll1_recalc_rate,
+};
+
+static struct lpc18xx_cgu_pll_clk lpc18xx_cgu_src_clk_plls[] = {
+ LPC1XX_CGU_CLK_PLL(PLL0USB, pll0_src_ids, pll0_ops),
+ LPC1XX_CGU_CLK_PLL(PLL0AUDIO, pll0_src_ids, pll0_ops),
+ LPC1XX_CGU_CLK_PLL(PLL1, pll1_src_ids, pll1_ops),
+};
+
+static void lpc18xx_fill_parent_names(const char **parent, u32 *id, int size)
+{
+ int i;
+
+ for (i = 0; i < size; i++)
+ parent[i] = clk_src_names[id[i]];
+}
+
+static struct clk *lpc18xx_cgu_register_div(struct lpc18xx_cgu_src_clk_div *clk,
+ void __iomem *base, int n)
+{
+ void __iomem *reg = base + LPC18XX_CGU_IDIV_CTRL(n);
+ const char *name = clk_src_names[clk->clk_id];
+ const char *parents[CLK_SRC_MAX];
+
+ clk->div.reg = reg;
+ clk->mux.reg = reg;
+ clk->gate.reg = reg;
+
+ lpc18xx_fill_parent_names(parents, clk->mux.table, clk->n_parents);
+
+ return clk_register_composite(NULL, name, parents, clk->n_parents,
+ &clk->mux.hw, &clk_mux_ops,
+ &clk->div.hw, &clk_divider_ops,
+ &clk->gate.hw, &clk_gate_ops, 0);
+}
+
+
+static struct clk *lpc18xx_register_base_clk(struct lpc18xx_cgu_base_clk *clk,
+ void __iomem *reg_base, int n)
+{
+ void __iomem *reg = reg_base + LPC18XX_CGU_BASE_CLK(n);
+ const char *name = clk_base_names[clk->clk_id];
+ const char *parents[CLK_SRC_MAX];
+
+ if (clk->n_parents == 0)
+ return ERR_PTR(-ENOENT);
+
+ clk->mux.reg = reg;
+ clk->gate.reg = reg;
+
+ lpc18xx_fill_parent_names(parents, clk->mux.table, clk->n_parents);
+
+ /* SAFE_CLK can not be turned off */
+ if (n == BASE_SAFE_CLK)
+ return clk_register_composite(NULL, name, parents, clk->n_parents,
+ &clk->mux.hw, &clk_mux_ops,
+ NULL, NULL, NULL, NULL, 0);
+
+ return clk_register_composite(NULL, name, parents, clk->n_parents,
+ &clk->mux.hw, &clk_mux_ops,
+ NULL, NULL,
+ &clk->gate.hw, &clk_gate_ops, 0);
+}
+
+
+static struct clk *lpc18xx_cgu_register_pll(struct lpc18xx_cgu_pll_clk *clk,
+ void __iomem *base)
+{
+ const char *name = clk_src_names[clk->clk_id];
+ const char *parents[CLK_SRC_MAX];
+
+ clk->pll.reg = base;
+ clk->mux.reg = base + clk->reg_offset + LPC18XX_CGU_PLL_CTRL_OFFSET;
+ clk->gate.reg = base + clk->reg_offset + LPC18XX_CGU_PLL_CTRL_OFFSET;
+
+ lpc18xx_fill_parent_names(parents, clk->mux.table, clk->n_parents);
+
+ return clk_register_composite(NULL, name, parents, clk->n_parents,
+ &clk->mux.hw, &clk_mux_ops,
+ &clk->pll.hw, clk->pll_ops,
+ &clk->gate.hw, &clk_gate_ops, 0);
+}
+
+static void __init lpc18xx_cgu_register_source_clks(struct device_node *np,
+ void __iomem *base)
+{
+ const char *parents[CLK_SRC_MAX];
+ struct clk *clk;
+ int i;
+
+ /* Register the internal 12 MHz RC oscillator (IRC) */
+ clk = clk_register_fixed_rate(NULL, clk_src_names[CLK_SRC_IRC],
+ NULL, CLK_IS_ROOT, 12000000);
+ if (IS_ERR(clk))
+ pr_warn("%s: failed to register irc clk\n", __func__);
+
+ /* Register crystal oscillator controlller */
+ parents[0] = of_clk_get_parent_name(np, 0);
+ clk = clk_register_gate(NULL, clk_src_names[CLK_SRC_OSC], parents[0],
+ 0, base + LPC18XX_CGU_XTAL_OSC_CTRL,
+ 0, CLK_GATE_SET_TO_DISABLE, NULL);
+ if (IS_ERR(clk))
+ pr_warn("%s: failed to register osc clk\n", __func__);
+
+ /* Register all PLLs */
+ for (i = 0; i < ARRAY_SIZE(lpc18xx_cgu_src_clk_plls); i++) {
+ clk = lpc18xx_cgu_register_pll(&lpc18xx_cgu_src_clk_plls[i],
+ base);
+ if (IS_ERR(clk))
+ pr_warn("%s: failed to register pll (%d)\n", __func__, i);
+ }
+
+ /* Register all clock dividers A-E */
+ for (i = 0; i < ARRAY_SIZE(lpc18xx_cgu_src_clk_divs); i++) {
+ clk = lpc18xx_cgu_register_div(&lpc18xx_cgu_src_clk_divs[i],
+ base, i);
+ if (IS_ERR(clk))
+ pr_warn("%s: failed to register div %d\n", __func__, i);
+ }
+}
+
+static struct clk *clk_base[BASE_CLK_MAX];
+static struct clk_onecell_data clk_base_data = {
+ .clks = clk_base,
+ .clk_num = BASE_CLK_MAX,
+};
+
+static void __init lpc18xx_cgu_register_base_clks(void __iomem *reg_base)
+{
+ int i;
+
+ for (i = BASE_SAFE_CLK; i < BASE_CLK_MAX; i++) {
+ clk_base[i] = lpc18xx_register_base_clk(&lpc18xx_cgu_base_clks[i],
+ reg_base, i);
+ if (IS_ERR(clk_base[i]) && PTR_ERR(clk_base[i]) != -ENOENT)
+ pr_warn("%s: register base clk %d failed\n", __func__, i);
+ }
+}
+
+static void __init lpc18xx_cgu_init(struct device_node *np)
+{
+ void __iomem *reg_base;
+
+ reg_base = of_iomap(np, 0);
+ if (!reg_base) {
+ pr_warn("%s: failed to map address range\n", __func__);
+ return;
+ }
+
+ lpc18xx_cgu_register_source_clks(np, reg_base);
+ lpc18xx_cgu_register_base_clks(reg_base);
+
+ of_clk_add_provider(np, of_clk_src_onecell_get, &clk_base_data);
+}
+CLK_OF_DECLARE(lpc18xx_cgu, "nxp,lpc1850-cgu", lpc18xx_cgu_init);
diff --git a/include/dt-bindings/clock/lpc18xx-cgu.h b/include/dt-bindings/clock/lpc18xx-cgu.h
new file mode 100644
index 000000000000..6e57c6d2ca66
--- /dev/null
+++ b/include/dt-bindings/clock/lpc18xx-cgu.h
@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) 2015 Joachim Eastwood <manabian@gmail.com>
+ *
+ * This code is released using a dual license strategy: BSD/GPL
+ * You can choose the licence that better fits your requirements.
+ *
+ * Released under the terms of 3-clause BSD License
+ * Released under the terms of GNU General Public License Version 2.0
+ *
+ */
+
+/* LPC18xx/43xx base clock ids */
+#define BASE_SAFE_CLK 0
+#define BASE_USB0_CLK 1
+#define BASE_PERIPH_CLK 2
+#define BASE_USB1_CLK 3
+#define BASE_CPU_CLK 4
+#define BASE_SPIFI_CLK 5
+#define BASE_SPI_CLK 6
+#define BASE_PHY_RX_CLK 7
+#define BASE_PHY_TX_CLK 8
+#define BASE_APB1_CLK 9
+#define BASE_APB3_CLK 10
+#define BASE_LCD_CLK 11
+#define BASE_ADCHS_CLK 12
+#define BASE_SDIO_CLK 13
+#define BASE_SSP0_CLK 14
+#define BASE_SSP1_CLK 15
+#define BASE_UART0_CLK 16
+#define BASE_UART1_CLK 17
+#define BASE_UART2_CLK 18
+#define BASE_UART3_CLK 19
+#define BASE_OUT_CLK 20
+#define BASE_RES1_CLK 21
+#define BASE_RES2_CLK 22
+#define BASE_RES3_CLK 23
+#define BASE_RES4_CLK 24
+#define BASE_AUDIO_CLK 25
+#define BASE_CGU_OUT0_CLK 26
+#define BASE_CGU_OUT1_CLK 27
+#define BASE_CLK_MAX (BASE_CGU_OUT1_CLK + 1)
--
1.8.0
^ permalink raw reply related [flat|nested] 30+ messages in thread
* [PATCH v4 1/5] clk: add lpc18xx cgu clk driver
@ 2015-05-28 20:31 ` Joachim Eastwood
0 siblings, 0 replies; 30+ messages in thread
From: Joachim Eastwood @ 2015-05-28 20:31 UTC (permalink / raw)
To: linux-arm-kernel
Add driver for NXP LPC18xx/43xx Clock Generation Unit (CGU). The CGU
contains several clock generators and output stages that route the
clocks either directly to peripherals or to a Clock Control Unit
(CCU).
Signed-off-by: Joachim Eastwood <manabian@gmail.com>
---
drivers/clk/Makefile | 1 +
drivers/clk/nxp/Makefile | 1 +
drivers/clk/nxp/clk-lpc18xx-cgu.c | 635 ++++++++++++++++++++++++++++++++
include/dt-bindings/clock/lpc18xx-cgu.h | 41 +++
4 files changed, 678 insertions(+)
create mode 100644 drivers/clk/nxp/Makefile
create mode 100644 drivers/clk/nxp/clk-lpc18xx-cgu.c
create mode 100644 include/dt-bindings/clock/lpc18xx-cgu.h
diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile
index 3d00c25382c5..4a34419c1da1 100644
--- a/drivers/clk/Makefile
+++ b/drivers/clk/Makefile
@@ -56,6 +56,7 @@ obj-$(CONFIG_ARCH_MMP) += mmp/
endif
obj-$(CONFIG_PLAT_ORION) += mvebu/
obj-$(CONFIG_ARCH_MXS) += mxs/
+obj-$(CONFIG_ARCH_LPC18XX) += nxp/
obj-$(CONFIG_MACH_PISTACHIO) += pistachio/
obj-$(CONFIG_COMMON_CLK_PXA) += pxa/
obj-$(CONFIG_COMMON_CLK_QCOM) += qcom/
diff --git a/drivers/clk/nxp/Makefile b/drivers/clk/nxp/Makefile
new file mode 100644
index 000000000000..aca9d3e4f7fe
--- /dev/null
+++ b/drivers/clk/nxp/Makefile
@@ -0,0 +1 @@
+obj-$(CONFIG_ARCH_LPC18XX) += clk-lpc18xx-cgu.o
diff --git a/drivers/clk/nxp/clk-lpc18xx-cgu.c b/drivers/clk/nxp/clk-lpc18xx-cgu.c
new file mode 100644
index 000000000000..81e9e1c788f4
--- /dev/null
+++ b/drivers/clk/nxp/clk-lpc18xx-cgu.c
@@ -0,0 +1,635 @@
+/*
+ * Clk driver for NXP LPC18xx/LPC43xx Clock Generation Unit (CGU)
+ *
+ * Copyright (C) 2015 Joachim Eastwood <manabian@gmail.com>
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2. This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+#include <linux/clk.h>
+#include <linux/clk-provider.h>
+#include <linux/delay.h>
+#include <linux/kernel.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+
+#include <dt-bindings/clock/lpc18xx-cgu.h>
+
+/* Clock Generation Unit (CGU) registers */
+#define LPC18XX_CGU_XTAL_OSC_CTRL 0x018
+#define LPC18XX_CGU_PLL0USB_STAT 0x01c
+#define LPC18XX_CGU_PLL0USB_CTRL 0x020
+#define LPC18XX_CGU_PLL0USB_MDIV 0x024
+#define LPC18XX_CGU_PLL0USB_NP_DIV 0x028
+#define LPC18XX_CGU_PLL0AUDIO_STAT 0x02c
+#define LPC18XX_CGU_PLL0AUDIO_CTRL 0x030
+#define LPC18XX_CGU_PLL0AUDIO_MDIV 0x034
+#define LPC18XX_CGU_PLL0AUDIO_NP_DIV 0x038
+#define LPC18XX_CGU_PLL0AUDIO_FRAC 0x03c
+#define LPC18XX_CGU_PLL1_STAT 0x040
+#define LPC18XX_CGU_PLL1_CTRL 0x044
+#define LPC18XX_PLL1_CTRL_FBSEL BIT(6)
+#define LPC18XX_PLL1_CTRL_DIRECT BIT(7)
+#define LPC18XX_CGU_IDIV_CTRL(n) (0x048 + (n) * sizeof(u32))
+#define LPC18XX_CGU_BASE_CLK(id) (0x05c + (id) * sizeof(u32))
+#define LPC18XX_CGU_PLL_CTRL_OFFSET 0x4
+
+/* PLL0 bits common to both audio and USB PLL */
+#define LPC18XX_PLL0_STAT_LOCK BIT(0)
+#define LPC18XX_PLL0_CTRL_PD BIT(0)
+#define LPC18XX_PLL0_CTRL_BYPASS BIT(1)
+#define LPC18XX_PLL0_CTRL_DIRECTI BIT(2)
+#define LPC18XX_PLL0_CTRL_DIRECTO BIT(3)
+#define LPC18XX_PLL0_CTRL_CLKEN BIT(4)
+#define LPC18XX_PLL0_MDIV_MDEC_MASK 0x1ffff
+#define LPC18XX_PLL0_MDIV_SELP_SHIFT 17
+#define LPC18XX_PLL0_MDIV_SELI_SHIFT 22
+#define LPC18XX_PLL0_MSEL_MAX BIT(15)
+
+/* Register value that gives PLL0 post/pre dividers equal to 1 */
+#define LPC18XX_PLL0_NP_DIVS_1 0x00302062
+
+enum {
+ CLK_SRC_OSC32,
+ CLK_SRC_IRC,
+ CLK_SRC_ENET_RX_CLK,
+ CLK_SRC_ENET_TX_CLK,
+ CLK_SRC_GP_CLKIN,
+ CLK_SRC_RESERVED1,
+ CLK_SRC_OSC,
+ CLK_SRC_PLL0USB,
+ CLK_SRC_PLL0AUDIO,
+ CLK_SRC_PLL1,
+ CLK_SRC_RESERVED2,
+ CLK_SRC_RESERVED3,
+ CLK_SRC_IDIVA,
+ CLK_SRC_IDIVB,
+ CLK_SRC_IDIVC,
+ CLK_SRC_IDIVD,
+ CLK_SRC_IDIVE,
+ CLK_SRC_MAX
+};
+
+static const char *clk_src_names[CLK_SRC_MAX] = {
+ [CLK_SRC_OSC32] = "osc32",
+ [CLK_SRC_IRC] = "irc",
+ [CLK_SRC_ENET_RX_CLK] = "enet_rx_clk",
+ [CLK_SRC_ENET_TX_CLK] = "enet_tx_clk",
+ [CLK_SRC_GP_CLKIN] = "gp_clkin",
+ [CLK_SRC_OSC] = "osc",
+ [CLK_SRC_PLL0USB] = "pll0usb",
+ [CLK_SRC_PLL0AUDIO] = "pll0audio",
+ [CLK_SRC_PLL1] = "pll1",
+ [CLK_SRC_IDIVA] = "idiva",
+ [CLK_SRC_IDIVB] = "idivb",
+ [CLK_SRC_IDIVC] = "idivc",
+ [CLK_SRC_IDIVD] = "idivd",
+ [CLK_SRC_IDIVE] = "idive",
+};
+
+static const char *clk_base_names[BASE_CLK_MAX] = {
+ [BASE_SAFE_CLK] = "base_safe_clk",
+ [BASE_USB0_CLK] = "base_usb0_clk",
+ [BASE_PERIPH_CLK] = "base_periph_clk",
+ [BASE_USB1_CLK] = "base_usb1_clk",
+ [BASE_CPU_CLK] = "base_cpu_clk",
+ [BASE_SPIFI_CLK] = "base_spifi_clk",
+ [BASE_SPI_CLK] = "base_spi_clk",
+ [BASE_PHY_RX_CLK] = "base_phy_rx_clk",
+ [BASE_PHY_TX_CLK] = "base_phy_tx_clk",
+ [BASE_APB1_CLK] = "base_apb1_clk",
+ [BASE_APB3_CLK] = "base_apb3_clk",
+ [BASE_LCD_CLK] = "base_lcd_clk",
+ [BASE_ADCHS_CLK] = "base_adchs_clk",
+ [BASE_SDIO_CLK] = "base_sdio_clk",
+ [BASE_SSP0_CLK] = "base_ssp0_clk",
+ [BASE_SSP1_CLK] = "base_ssp1_clk",
+ [BASE_UART0_CLK] = "base_uart0_clk",
+ [BASE_UART1_CLK] = "base_uart1_clk",
+ [BASE_UART2_CLK] = "base_uart2_clk",
+ [BASE_UART3_CLK] = "base_uart3_clk",
+ [BASE_OUT_CLK] = "base_out_clk",
+ [BASE_AUDIO_CLK] = "base_audio_clk",
+ [BASE_CGU_OUT0_CLK] = "base_cgu_out0_clk",
+ [BASE_CGU_OUT1_CLK] = "base_cgu_out1_clk",
+};
+
+static u32 lpc18xx_cgu_pll0_src_ids[] = {
+ CLK_SRC_OSC32, CLK_SRC_IRC, CLK_SRC_ENET_RX_CLK,
+ CLK_SRC_ENET_TX_CLK, CLK_SRC_GP_CLKIN, CLK_SRC_OSC,
+ CLK_SRC_PLL1, CLK_SRC_IDIVA, CLK_SRC_IDIVB, CLK_SRC_IDIVC,
+ CLK_SRC_IDIVD, CLK_SRC_IDIVE,
+};
+
+static u32 lpc18xx_cgu_pll1_src_ids[] = {
+ CLK_SRC_OSC32, CLK_SRC_IRC, CLK_SRC_ENET_RX_CLK,
+ CLK_SRC_ENET_TX_CLK, CLK_SRC_GP_CLKIN, CLK_SRC_OSC,
+ CLK_SRC_PLL0USB, CLK_SRC_PLL0AUDIO, CLK_SRC_IDIVA,
+ CLK_SRC_IDIVB, CLK_SRC_IDIVC, CLK_SRC_IDIVD, CLK_SRC_IDIVE,
+};
+
+static u32 lpc18xx_cgu_idiva_src_ids[] = {
+ CLK_SRC_OSC32, CLK_SRC_IRC, CLK_SRC_ENET_RX_CLK,
+ CLK_SRC_ENET_TX_CLK, CLK_SRC_GP_CLKIN, CLK_SRC_OSC,
+ CLK_SRC_PLL0USB, CLK_SRC_PLL0AUDIO, CLK_SRC_PLL1
+};
+
+static u32 lpc18xx_cgu_idivbcde_src_ids[] = {
+ CLK_SRC_OSC32, CLK_SRC_IRC, CLK_SRC_ENET_RX_CLK,
+ CLK_SRC_ENET_TX_CLK, CLK_SRC_GP_CLKIN, CLK_SRC_OSC,
+ CLK_SRC_PLL0AUDIO, CLK_SRC_PLL1, CLK_SRC_IDIVA,
+};
+
+static u32 lpc18xx_cgu_base_irc_src_ids[] = {CLK_SRC_IRC};
+
+static u32 lpc18xx_cgu_base_usb0_src_ids[] = {CLK_SRC_PLL0USB};
+
+static u32 lpc18xx_cgu_base_common_src_ids[] = {
+ CLK_SRC_OSC32, CLK_SRC_IRC, CLK_SRC_ENET_RX_CLK,
+ CLK_SRC_ENET_TX_CLK, CLK_SRC_GP_CLKIN, CLK_SRC_OSC,
+ CLK_SRC_PLL0AUDIO, CLK_SRC_PLL1, CLK_SRC_IDIVA,
+ CLK_SRC_IDIVB, CLK_SRC_IDIVC, CLK_SRC_IDIVD, CLK_SRC_IDIVE,
+};
+
+static u32 lpc18xx_cgu_base_all_src_ids[] = {
+ CLK_SRC_OSC32, CLK_SRC_IRC, CLK_SRC_ENET_RX_CLK,
+ CLK_SRC_ENET_TX_CLK, CLK_SRC_GP_CLKIN, CLK_SRC_OSC,
+ CLK_SRC_PLL0USB, CLK_SRC_PLL0AUDIO, CLK_SRC_PLL1,
+ CLK_SRC_IDIVA, CLK_SRC_IDIVB, CLK_SRC_IDIVC,
+ CLK_SRC_IDIVD, CLK_SRC_IDIVE,
+};
+
+struct lpc18xx_cgu_src_clk_div {
+ u8 clk_id;
+ u8 n_parents;
+ struct clk_divider div;
+ struct clk_mux mux;
+ struct clk_gate gate;
+};
+
+#define LPC1XX_CGU_SRC_CLK_DIV(_id, _width, _table) \
+{ \
+ .clk_id = CLK_SRC_ ##_id, \
+ .n_parents = ARRAY_SIZE(lpc18xx_cgu_ ##_table), \
+ .div = { \
+ .shift = 2, \
+ .width = _width, \
+ }, \
+ .mux = { \
+ .mask = 0x1f, \
+ .shift = 24, \
+ .table = lpc18xx_cgu_ ##_table, \
+ }, \
+ .gate = { \
+ .bit_idx = 0, \
+ .flags = CLK_GATE_SET_TO_DISABLE, \
+ }, \
+}
+
+static struct lpc18xx_cgu_src_clk_div lpc18xx_cgu_src_clk_divs[] = {
+ LPC1XX_CGU_SRC_CLK_DIV(IDIVA, 2, idiva_src_ids),
+ LPC1XX_CGU_SRC_CLK_DIV(IDIVB, 4, idivbcde_src_ids),
+ LPC1XX_CGU_SRC_CLK_DIV(IDIVC, 4, idivbcde_src_ids),
+ LPC1XX_CGU_SRC_CLK_DIV(IDIVD, 4, idivbcde_src_ids),
+ LPC1XX_CGU_SRC_CLK_DIV(IDIVE, 8, idivbcde_src_ids),
+};
+
+struct lpc18xx_cgu_base_clk {
+ u8 clk_id;
+ u8 n_parents;
+ struct clk_mux mux;
+ struct clk_gate gate;
+};
+
+#define LPC1XX_CGU_BASE_CLK(_id, _table, _flags) \
+{ \
+ .clk_id = BASE_ ##_id ##_CLK, \
+ .n_parents = ARRAY_SIZE(lpc18xx_cgu_ ##_table), \
+ .mux = { \
+ .mask = 0x1f, \
+ .shift = 24, \
+ .table = lpc18xx_cgu_ ##_table, \
+ .flags = _flags, \
+ }, \
+ .gate = { \
+ .bit_idx = 0, \
+ .flags = CLK_GATE_SET_TO_DISABLE, \
+ }, \
+}
+
+static struct lpc18xx_cgu_base_clk lpc18xx_cgu_base_clks[] = {
+ LPC1XX_CGU_BASE_CLK(SAFE, base_irc_src_ids, CLK_MUX_READ_ONLY),
+ LPC1XX_CGU_BASE_CLK(USB0, base_usb0_src_ids, 0),
+ LPC1XX_CGU_BASE_CLK(PERIPH, base_common_src_ids, 0),
+ LPC1XX_CGU_BASE_CLK(USB1, base_all_src_ids, 0),
+ LPC1XX_CGU_BASE_CLK(CPU, base_common_src_ids, 0),
+ LPC1XX_CGU_BASE_CLK(SPIFI, base_common_src_ids, 0),
+ LPC1XX_CGU_BASE_CLK(SPI, base_common_src_ids, 0),
+ LPC1XX_CGU_BASE_CLK(PHY_RX, base_common_src_ids, 0),
+ LPC1XX_CGU_BASE_CLK(PHY_TX, base_common_src_ids, 0),
+ LPC1XX_CGU_BASE_CLK(APB1, base_common_src_ids, 0),
+ LPC1XX_CGU_BASE_CLK(APB3, base_common_src_ids, 0),
+ LPC1XX_CGU_BASE_CLK(LCD, base_common_src_ids, 0),
+ LPC1XX_CGU_BASE_CLK(ADCHS, base_common_src_ids, 0),
+ LPC1XX_CGU_BASE_CLK(SDIO, base_common_src_ids, 0),
+ LPC1XX_CGU_BASE_CLK(SSP0, base_common_src_ids, 0),
+ LPC1XX_CGU_BASE_CLK(SSP1, base_common_src_ids, 0),
+ LPC1XX_CGU_BASE_CLK(UART0, base_common_src_ids, 0),
+ LPC1XX_CGU_BASE_CLK(UART1, base_common_src_ids, 0),
+ LPC1XX_CGU_BASE_CLK(UART2, base_common_src_ids, 0),
+ LPC1XX_CGU_BASE_CLK(UART3, base_common_src_ids, 0),
+ LPC1XX_CGU_BASE_CLK(OUT, base_all_src_ids, 0),
+ { /* 21 reserved */ },
+ { /* 22 reserved */ },
+ { /* 23 reserved */ },
+ { /* 24 reserved */ },
+ LPC1XX_CGU_BASE_CLK(AUDIO, base_common_src_ids, 0),
+ LPC1XX_CGU_BASE_CLK(CGU_OUT0, base_all_src_ids, 0),
+ LPC1XX_CGU_BASE_CLK(CGU_OUT1, base_all_src_ids, 0),
+};
+
+struct lpc18xx_pll {
+ struct clk_hw hw;
+ void __iomem *reg;
+ spinlock_t *lock;
+ u8 flags;
+};
+
+#define to_lpc_pll(hw) container_of(hw, struct lpc18xx_pll, hw)
+
+struct lpc18xx_cgu_pll_clk {
+ u8 clk_id;
+ u8 n_parents;
+ u8 reg_offset;
+ struct clk_mux mux;
+ struct clk_gate gate;
+ struct lpc18xx_pll pll;
+ const struct clk_ops *pll_ops;
+};
+
+#define LPC1XX_CGU_CLK_PLL(_id, _table, _pll_ops) \
+{ \
+ .clk_id = CLK_SRC_ ##_id, \
+ .n_parents = ARRAY_SIZE(lpc18xx_cgu_ ##_table), \
+ .reg_offset = LPC18XX_CGU_ ##_id ##_STAT, \
+ .mux = { \
+ .mask = 0x1f, \
+ .shift = 24, \
+ .table = lpc18xx_cgu_ ##_table, \
+ }, \
+ .gate = { \
+ .bit_idx = 0, \
+ .flags = CLK_GATE_SET_TO_DISABLE, \
+ }, \
+ .pll_ops = &lpc18xx_ ##_pll_ops, \
+}
+
+/*
+ * PLL0 uses a special register value encoding. The compute functions below
+ * are taken or derived from the LPC1850 user manual (section 12.6.3.3).
+ */
+
+/* Compute PLL0 multiplier from decoded version */
+static u32 lpc18xx_pll0_mdec2msel(u32 x)
+{
+ int i;
+
+ switch (x) {
+ case 0x18003: return 1;
+ case 0x10003: return 2;
+ default:
+ for (i = LPC18XX_PLL0_MSEL_MAX + 1; x != 0x4000 && i > 0; i--)
+ x = ((x ^ x >> 14) & 1) | (x << 1 & 0x7fff);
+ return i;
+ }
+}
+/* Compute PLL0 decoded multiplier from binary version */
+static u32 lpc18xx_pll0_msel2mdec(u32 msel)
+{
+ u32 i, x = 0x4000;
+
+ switch (msel) {
+ case 0: return 0;
+ case 1: return 0x18003;
+ case 2: return 0x10003;
+ default:
+ for (i = msel; i <= LPC18XX_PLL0_MSEL_MAX; i++)
+ x = ((x ^ x >> 1) & 1) << 14 | (x >> 1 & 0xffff);
+ return x;
+ }
+}
+
+/* Compute PLL0 bandwidth SELI reg from multiplier */
+static u32 lpc18xx_pll0_msel2seli(u32 msel)
+{
+ u32 tmp;
+
+ if (msel > 16384) return 1;
+ if (msel > 8192) return 2;
+ if (msel > 2048) return 4;
+ if (msel >= 501) return 8;
+ if (msel >= 60) {
+ tmp = 1024 / (msel + 9);
+ return ((1024 == (tmp * (msel + 9))) == 0) ? tmp * 4 : (tmp + 1) * 4;
+ }
+
+ return (msel & 0x3c) + 4;
+}
+
+/* Compute PLL0 bandwidth SELP reg from multiplier */
+static u32 lpc18xx_pll0_msel2selp(u32 msel)
+{
+ if (msel < 60)
+ return (msel >> 1) + 1;
+
+ return 31;
+}
+
+static unsigned long lpc18xx_pll0_recalc_rate(struct clk_hw *hw,
+ unsigned long parent_rate)
+{
+ struct lpc18xx_pll *pll = to_lpc_pll(hw);
+ u32 ctrl, mdiv, msel, npdiv;
+
+ ctrl = clk_readl(pll->reg + LPC18XX_CGU_PLL0USB_CTRL);
+ mdiv = clk_readl(pll->reg + LPC18XX_CGU_PLL0USB_MDIV);
+ npdiv = clk_readl(pll->reg + LPC18XX_CGU_PLL0USB_NP_DIV);
+
+ if (ctrl & LPC18XX_PLL0_CTRL_BYPASS)
+ return parent_rate;
+
+ if (npdiv != LPC18XX_PLL0_NP_DIVS_1) {
+ pr_warn("%s: pre/post dividers not supported\n", __func__);
+ return 0;
+ }
+
+ msel = lpc18xx_pll0_mdec2msel(mdiv & LPC18XX_PLL0_MDIV_MDEC_MASK);
+ if (msel)
+ return 2 * msel * parent_rate;
+
+ pr_warn("%s: unable to calculate rate\n", __func__);
+
+ return 0;
+}
+
+static long lpc18xx_pll0_round_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long *prate)
+{
+ unsigned long m;
+
+ if (*prate < rate) {
+ pr_warn("%s: pll dividers not supported\n", __func__);
+ return -EINVAL;
+ }
+
+ m = DIV_ROUND_UP_ULL(*prate, rate * 2);
+ if (m <= 0 && m > LPC18XX_PLL0_MSEL_MAX) {
+ pr_warn("%s: unable to support rate %lu\n", __func__, rate);
+ return -EINVAL;
+ }
+
+ return 2 * *prate * m;
+}
+
+static int lpc18xx_pll0_set_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long parent_rate)
+{
+ struct lpc18xx_pll *pll = to_lpc_pll(hw);
+ u32 ctrl, stat, m;
+ int retry = 3;
+
+ if (parent_rate < rate) {
+ pr_warn("%s: pll dividers not supported\n", __func__);
+ return -EINVAL;
+ }
+
+ m = DIV_ROUND_UP_ULL(parent_rate, rate * 2);
+ if (m <= 0 && m > LPC18XX_PLL0_MSEL_MAX) {
+ pr_warn("%s: unable to support rate %lu\n", __func__, rate);
+ return -EINVAL;
+ }
+
+ m = lpc18xx_pll0_msel2mdec(m);
+ m |= lpc18xx_pll0_msel2selp(m) << LPC18XX_PLL0_MDIV_SELP_SHIFT;
+ m |= lpc18xx_pll0_msel2seli(m) << LPC18XX_PLL0_MDIV_SELI_SHIFT;
+
+ /* Power down PLL, disable clk output and dividers */
+ ctrl = clk_readl(pll->reg + LPC18XX_CGU_PLL0USB_CTRL);
+ ctrl |= LPC18XX_PLL0_CTRL_PD;
+ ctrl &= ~(LPC18XX_PLL0_CTRL_BYPASS | LPC18XX_PLL0_CTRL_DIRECTI |
+ LPC18XX_PLL0_CTRL_DIRECTO | LPC18XX_PLL0_CTRL_CLKEN);
+ clk_writel(ctrl, pll->reg + LPC18XX_CGU_PLL0USB_CTRL);
+
+ /* Configure new PLL settings */
+ clk_writel(m, pll->reg + LPC18XX_CGU_PLL0USB_MDIV);
+ clk_writel(LPC18XX_PLL0_NP_DIVS_1, pll->reg + LPC18XX_CGU_PLL0USB_NP_DIV);
+
+ /* Power up PLL and wait for lock */
+ ctrl &= ~LPC18XX_PLL0_CTRL_PD;
+ clk_writel(ctrl, pll->reg + LPC18XX_CGU_PLL0USB_CTRL);
+ do {
+ udelay(10);
+ stat = clk_readl(pll->reg + LPC18XX_CGU_PLL0USB_STAT);
+ if (stat & LPC18XX_PLL0_STAT_LOCK) {
+ ctrl |= LPC18XX_PLL0_CTRL_CLKEN;
+ clk_writel(ctrl, pll->reg + LPC18XX_CGU_PLL0USB_CTRL);
+
+ return 0;
+ }
+ } while (retry--);
+
+ pr_warn("%s: unable to lock pll\n", __func__);
+
+ return -EINVAL;
+}
+
+static const struct clk_ops lpc18xx_pll0_ops = {
+ .recalc_rate = lpc18xx_pll0_recalc_rate,
+ .round_rate = lpc18xx_pll0_round_rate,
+ .set_rate = lpc18xx_pll0_set_rate,
+};
+
+static unsigned long lpc18xx_pll1_recalc_rate(struct clk_hw *hw,
+ unsigned long parent_rate)
+{
+ struct lpc18xx_pll *pll = to_lpc_pll(hw);
+ u16 msel, nsel, psel;
+ bool direct, fbsel;
+ u32 stat, ctrl;
+
+ stat = clk_readl(pll->reg + LPC18XX_CGU_PLL1_STAT);
+ ctrl = clk_readl(pll->reg + LPC18XX_CGU_PLL1_CTRL);
+
+ direct = (ctrl & LPC18XX_PLL1_CTRL_DIRECT) ? true : false;
+ fbsel = (ctrl & LPC18XX_PLL1_CTRL_FBSEL) ? true : false;
+
+ msel = ((ctrl >> 16) & 0xff) + 1;
+ nsel = ((ctrl >> 12) & 0x3) + 1;
+
+ if (direct || fbsel)
+ return msel * (parent_rate / nsel);
+
+ psel = (ctrl >> 8) & 0x3;
+ psel = 1 << psel;
+
+ return (msel / (2 * psel)) * (parent_rate / nsel);
+}
+
+static const struct clk_ops lpc18xx_pll1_ops = {
+ .recalc_rate = lpc18xx_pll1_recalc_rate,
+};
+
+static struct lpc18xx_cgu_pll_clk lpc18xx_cgu_src_clk_plls[] = {
+ LPC1XX_CGU_CLK_PLL(PLL0USB, pll0_src_ids, pll0_ops),
+ LPC1XX_CGU_CLK_PLL(PLL0AUDIO, pll0_src_ids, pll0_ops),
+ LPC1XX_CGU_CLK_PLL(PLL1, pll1_src_ids, pll1_ops),
+};
+
+static void lpc18xx_fill_parent_names(const char **parent, u32 *id, int size)
+{
+ int i;
+
+ for (i = 0; i < size; i++)
+ parent[i] = clk_src_names[id[i]];
+}
+
+static struct clk *lpc18xx_cgu_register_div(struct lpc18xx_cgu_src_clk_div *clk,
+ void __iomem *base, int n)
+{
+ void __iomem *reg = base + LPC18XX_CGU_IDIV_CTRL(n);
+ const char *name = clk_src_names[clk->clk_id];
+ const char *parents[CLK_SRC_MAX];
+
+ clk->div.reg = reg;
+ clk->mux.reg = reg;
+ clk->gate.reg = reg;
+
+ lpc18xx_fill_parent_names(parents, clk->mux.table, clk->n_parents);
+
+ return clk_register_composite(NULL, name, parents, clk->n_parents,
+ &clk->mux.hw, &clk_mux_ops,
+ &clk->div.hw, &clk_divider_ops,
+ &clk->gate.hw, &clk_gate_ops, 0);
+}
+
+
+static struct clk *lpc18xx_register_base_clk(struct lpc18xx_cgu_base_clk *clk,
+ void __iomem *reg_base, int n)
+{
+ void __iomem *reg = reg_base + LPC18XX_CGU_BASE_CLK(n);
+ const char *name = clk_base_names[clk->clk_id];
+ const char *parents[CLK_SRC_MAX];
+
+ if (clk->n_parents == 0)
+ return ERR_PTR(-ENOENT);
+
+ clk->mux.reg = reg;
+ clk->gate.reg = reg;
+
+ lpc18xx_fill_parent_names(parents, clk->mux.table, clk->n_parents);
+
+ /* SAFE_CLK can not be turned off */
+ if (n == BASE_SAFE_CLK)
+ return clk_register_composite(NULL, name, parents, clk->n_parents,
+ &clk->mux.hw, &clk_mux_ops,
+ NULL, NULL, NULL, NULL, 0);
+
+ return clk_register_composite(NULL, name, parents, clk->n_parents,
+ &clk->mux.hw, &clk_mux_ops,
+ NULL, NULL,
+ &clk->gate.hw, &clk_gate_ops, 0);
+}
+
+
+static struct clk *lpc18xx_cgu_register_pll(struct lpc18xx_cgu_pll_clk *clk,
+ void __iomem *base)
+{
+ const char *name = clk_src_names[clk->clk_id];
+ const char *parents[CLK_SRC_MAX];
+
+ clk->pll.reg = base;
+ clk->mux.reg = base + clk->reg_offset + LPC18XX_CGU_PLL_CTRL_OFFSET;
+ clk->gate.reg = base + clk->reg_offset + LPC18XX_CGU_PLL_CTRL_OFFSET;
+
+ lpc18xx_fill_parent_names(parents, clk->mux.table, clk->n_parents);
+
+ return clk_register_composite(NULL, name, parents, clk->n_parents,
+ &clk->mux.hw, &clk_mux_ops,
+ &clk->pll.hw, clk->pll_ops,
+ &clk->gate.hw, &clk_gate_ops, 0);
+}
+
+static void __init lpc18xx_cgu_register_source_clks(struct device_node *np,
+ void __iomem *base)
+{
+ const char *parents[CLK_SRC_MAX];
+ struct clk *clk;
+ int i;
+
+ /* Register the internal 12 MHz RC oscillator (IRC) */
+ clk = clk_register_fixed_rate(NULL, clk_src_names[CLK_SRC_IRC],
+ NULL, CLK_IS_ROOT, 12000000);
+ if (IS_ERR(clk))
+ pr_warn("%s: failed to register irc clk\n", __func__);
+
+ /* Register crystal oscillator controlller */
+ parents[0] = of_clk_get_parent_name(np, 0);
+ clk = clk_register_gate(NULL, clk_src_names[CLK_SRC_OSC], parents[0],
+ 0, base + LPC18XX_CGU_XTAL_OSC_CTRL,
+ 0, CLK_GATE_SET_TO_DISABLE, NULL);
+ if (IS_ERR(clk))
+ pr_warn("%s: failed to register osc clk\n", __func__);
+
+ /* Register all PLLs */
+ for (i = 0; i < ARRAY_SIZE(lpc18xx_cgu_src_clk_plls); i++) {
+ clk = lpc18xx_cgu_register_pll(&lpc18xx_cgu_src_clk_plls[i],
+ base);
+ if (IS_ERR(clk))
+ pr_warn("%s: failed to register pll (%d)\n", __func__, i);
+ }
+
+ /* Register all clock dividers A-E */
+ for (i = 0; i < ARRAY_SIZE(lpc18xx_cgu_src_clk_divs); i++) {
+ clk = lpc18xx_cgu_register_div(&lpc18xx_cgu_src_clk_divs[i],
+ base, i);
+ if (IS_ERR(clk))
+ pr_warn("%s: failed to register div %d\n", __func__, i);
+ }
+}
+
+static struct clk *clk_base[BASE_CLK_MAX];
+static struct clk_onecell_data clk_base_data = {
+ .clks = clk_base,
+ .clk_num = BASE_CLK_MAX,
+};
+
+static void __init lpc18xx_cgu_register_base_clks(void __iomem *reg_base)
+{
+ int i;
+
+ for (i = BASE_SAFE_CLK; i < BASE_CLK_MAX; i++) {
+ clk_base[i] = lpc18xx_register_base_clk(&lpc18xx_cgu_base_clks[i],
+ reg_base, i);
+ if (IS_ERR(clk_base[i]) && PTR_ERR(clk_base[i]) != -ENOENT)
+ pr_warn("%s: register base clk %d failed\n", __func__, i);
+ }
+}
+
+static void __init lpc18xx_cgu_init(struct device_node *np)
+{
+ void __iomem *reg_base;
+
+ reg_base = of_iomap(np, 0);
+ if (!reg_base) {
+ pr_warn("%s: failed to map address range\n", __func__);
+ return;
+ }
+
+ lpc18xx_cgu_register_source_clks(np, reg_base);
+ lpc18xx_cgu_register_base_clks(reg_base);
+
+ of_clk_add_provider(np, of_clk_src_onecell_get, &clk_base_data);
+}
+CLK_OF_DECLARE(lpc18xx_cgu, "nxp,lpc1850-cgu", lpc18xx_cgu_init);
diff --git a/include/dt-bindings/clock/lpc18xx-cgu.h b/include/dt-bindings/clock/lpc18xx-cgu.h
new file mode 100644
index 000000000000..6e57c6d2ca66
--- /dev/null
+++ b/include/dt-bindings/clock/lpc18xx-cgu.h
@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) 2015 Joachim Eastwood <manabian@gmail.com>
+ *
+ * This code is released using a dual license strategy: BSD/GPL
+ * You can choose the licence that better fits your requirements.
+ *
+ * Released under the terms of 3-clause BSD License
+ * Released under the terms of GNU General Public License Version 2.0
+ *
+ */
+
+/* LPC18xx/43xx base clock ids */
+#define BASE_SAFE_CLK 0
+#define BASE_USB0_CLK 1
+#define BASE_PERIPH_CLK 2
+#define BASE_USB1_CLK 3
+#define BASE_CPU_CLK 4
+#define BASE_SPIFI_CLK 5
+#define BASE_SPI_CLK 6
+#define BASE_PHY_RX_CLK 7
+#define BASE_PHY_TX_CLK 8
+#define BASE_APB1_CLK 9
+#define BASE_APB3_CLK 10
+#define BASE_LCD_CLK 11
+#define BASE_ADCHS_CLK 12
+#define BASE_SDIO_CLK 13
+#define BASE_SSP0_CLK 14
+#define BASE_SSP1_CLK 15
+#define BASE_UART0_CLK 16
+#define BASE_UART1_CLK 17
+#define BASE_UART2_CLK 18
+#define BASE_UART3_CLK 19
+#define BASE_OUT_CLK 20
+#define BASE_RES1_CLK 21
+#define BASE_RES2_CLK 22
+#define BASE_RES3_CLK 23
+#define BASE_RES4_CLK 24
+#define BASE_AUDIO_CLK 25
+#define BASE_CGU_OUT0_CLK 26
+#define BASE_CGU_OUT1_CLK 27
+#define BASE_CLK_MAX (BASE_CGU_OUT1_CLK + 1)
--
1.8.0
^ permalink raw reply related [flat|nested] 30+ messages in thread
* [PATCH v4 2/5] doc: dt: add documentation for lpc1850-cgu clk driver
2015-05-28 20:31 ` Joachim Eastwood
(?)
@ 2015-05-28 20:31 ` Joachim Eastwood
-1 siblings, 0 replies; 30+ messages in thread
From: Joachim Eastwood @ 2015-05-28 20:31 UTC (permalink / raw)
To: mturquette-QSEj5FYQhm4dnm+yROfE0A, sboyd-sgV2jX0FEOL9JmXXK+q4OQ
Cc: Joachim Eastwood, linux-clk-u79uwXL29TY76Z2rM5mHXA,
devicetree-u79uwXL29TY76Z2rM5mHXA,
linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r
Add DT binding documentation for lpc1850-cgu driver.
Signed-off-by: Joachim Eastwood <manabian-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
---
.../devicetree/bindings/clock/lpc1850-cgu.txt | 131 +++++++++++++++++++++
1 file changed, 131 insertions(+)
create mode 100644 Documentation/devicetree/bindings/clock/lpc1850-cgu.txt
diff --git a/Documentation/devicetree/bindings/clock/lpc1850-cgu.txt b/Documentation/devicetree/bindings/clock/lpc1850-cgu.txt
new file mode 100644
index 000000000000..2cc32a9a945a
--- /dev/null
+++ b/Documentation/devicetree/bindings/clock/lpc1850-cgu.txt
@@ -0,0 +1,131 @@
+* NXP LPC1850 Clock Generation Unit (CGU)
+
+The CGU generates multiple independent clocks for the core and the
+peripheral blocks of the LPC18xx. Each independent clock is called
+a base clock and itself is one of the inputs to the two Clock
+Control Units (CCUs) which control the branch clocks to the
+individual peripherals.
+
+The CGU selects the inputs to the clock generators from multiple
+clock sources, controls the clock generation, and routes the outputs
+of the clock generators through the clock source bus to the output
+stages. Each output stage provides an independent clock source and
+corresponds to one of the base clocks for the LPC18xx.
+
+ - Above text taken from NXP LPC1850 User Manual.
+
+
+This binding uses the common clock binding:
+ Documentation/devicetree/bindings/clock/clock-bindings.txt
+
+Required properties:
+- compatible:
+ Should be "nxp,lpc1850-cgu"
+- reg:
+ Shall define the base and range of the address space
+ containing clock control registers
+- #clock-cells:
+ Shall have value <1>. The permitted clock-specifier values
+ are the base clock numbers defined below.
+- clocks:
+ Shall contain a list of phandles for the external input
+ sources to the CGU. The list shall be in the following
+ order: xtal, 32khz, enet_rx_clk, enet_tx_clk, gp_clkin.
+- clock-indices:
+ Shall be an ordered list of numbers defining the base clock
+ number provided by the CGU.
+- clock-output-names:
+ Shall be an ordered list of strings defining the names of
+ the clocks provided by the CGU.
+
+Which base clocks that are available on the CGU depends on the
+specific LPC part. Base clocks are numbered from 0 to 27.
+
+Number: Name: Description:
+ 0 BASE_SAFE_CLK Base safe clock (always on) for WWDT
+ 1 BASE_USB0_CLK Base clock for USB0
+ 2 BASE_PERIPH_CLK Base clock for Cortex-M0SUB subsystem,
+ SPI, and SGPIO
+ 3 BASE_USB1_CLK Base clock for USB1
+ 4 BASE_CPU_CLK System base clock for ARM Cortex-M core
+ and APB peripheral blocks #0 and #2
+ 5 BASE_SPIFI_CLK Base clock for SPIFI
+ 6 BASE_SPI_CLK Base clock for SPI
+ 7 BASE_PHY_RX_CLK Base clock for Ethernet PHY Receive clock
+ 8 BASE_PHY_TX_CLK Base clock for Ethernet PHY Transmit clock
+ 9 BASE_APB1_CLK Base clock for APB peripheral block # 1
+10 BASE_APB3_CLK Base clock for APB peripheral block # 3
+11 BASE_LCD_CLK Base clock for LCD
+12 BASE_ADCHS_CLK Base clock for ADCHS
+13 BASE_SDIO_CLK Base clock for SD/MMC
+14 BASE_SSP0_CLK Base clock for SSP0
+15 BASE_SSP1_CLK Base clock for SSP1
+16 BASE_UART0_CLK Base clock for UART0
+17 BASE_UART1_CLK Base clock for UART1
+18 BASE_UART2_CLK Base clock for UART2
+19 BASE_UART3_CLK Base clock for UART3
+20 BASE_OUT_CLK Base clock for CLKOUT pin
+24-21 - Reserved
+25 BASE_AUDIO_CLK Base clock for audio system (I2S)
+26 BASE_CGU_OUT0_CLK Base clock for CGU_OUT0 clock output
+27 BASE_CGU_OUT1_CLK Base clock for CGU_OUT1 clock output
+
+BASE_PERIPH_CLK and BASE_SPI_CLK is only available on LPC43xx.
+BASE_ADCHS_CLK is only available on LPC4370.
+
+
+Example board file:
+
+/ {
+ clocks {
+ xtal: xtal {
+ compatible = "fixed-clock";
+ #clock-cells = <0>;
+ clock-frequency = <12000000>;
+ };
+
+ xtal32: xtal32 {
+ compatible = "fixed-clock";
+ #clock-cells = <0>;
+ clock-frequency = <32768>;
+ };
+
+ enet_rx_clk: enet_rx_clk {
+ compatible = "fixed-clock";
+ #clock-cells = <0>;
+ clock-frequency = <0>;
+ clock-output-names = "enet_rx_clk";
+ };
+
+ enet_tx_clk: enet_tx_clk {
+ compatible = "fixed-clock";
+ #clock-cells = <0>;
+ clock-frequency = <0>;
+ clock-output-names = "enet_tx_clk";
+ };
+
+ gp_clkin: gp_clkin {
+ compatible = "fixed-clock";
+ #clock-cells = <0>;
+ clock-frequency = <0>;
+ clock-output-names = "gp_clkin";
+ };
+ };
+
+ soc {
+ cgu: clock-controller@40050000 {
+ compatible = "nxp,lpc1850-cgu";
+ reg = <0x40050000 0x1000>;
+ #clock-cells = <1>;
+ clocks = <&xtal>, <&creg_clk 1>, <&enet_rx_clk>, <&enet_tx_clk>, <&gp_clkin>;
+ };
+
+ /* A CGU and CCU clock consumer */
+ lcdc: lcdc@40008000 {
+ ...
+ clocks = <&cgu BASE_LCD_CLK>, <&ccu1 CLK_CPU_LCD>;
+ clock-names = "clcdclk", "apb_pclk";
+ ...
+ };
+ };
+};
--
1.8.0
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply related [flat|nested] 30+ messages in thread
* [PATCH v4 2/5] doc: dt: add documentation for lpc1850-cgu clk driver
@ 2015-05-28 20:31 ` Joachim Eastwood
0 siblings, 0 replies; 30+ messages in thread
From: Joachim Eastwood @ 2015-05-28 20:31 UTC (permalink / raw)
To: mturquette, sboyd
Cc: Joachim Eastwood, linux-clk, devicetree, linux-arm-kernel
Add DT binding documentation for lpc1850-cgu driver.
Signed-off-by: Joachim Eastwood <manabian@gmail.com>
---
.../devicetree/bindings/clock/lpc1850-cgu.txt | 131 +++++++++++++++++++++
1 file changed, 131 insertions(+)
create mode 100644 Documentation/devicetree/bindings/clock/lpc1850-cgu.txt
diff --git a/Documentation/devicetree/bindings/clock/lpc1850-cgu.txt b/Documentation/devicetree/bindings/clock/lpc1850-cgu.txt
new file mode 100644
index 000000000000..2cc32a9a945a
--- /dev/null
+++ b/Documentation/devicetree/bindings/clock/lpc1850-cgu.txt
@@ -0,0 +1,131 @@
+* NXP LPC1850 Clock Generation Unit (CGU)
+
+The CGU generates multiple independent clocks for the core and the
+peripheral blocks of the LPC18xx. Each independent clock is called
+a base clock and itself is one of the inputs to the two Clock
+Control Units (CCUs) which control the branch clocks to the
+individual peripherals.
+
+The CGU selects the inputs to the clock generators from multiple
+clock sources, controls the clock generation, and routes the outputs
+of the clock generators through the clock source bus to the output
+stages. Each output stage provides an independent clock source and
+corresponds to one of the base clocks for the LPC18xx.
+
+ - Above text taken from NXP LPC1850 User Manual.
+
+
+This binding uses the common clock binding:
+ Documentation/devicetree/bindings/clock/clock-bindings.txt
+
+Required properties:
+- compatible:
+ Should be "nxp,lpc1850-cgu"
+- reg:
+ Shall define the base and range of the address space
+ containing clock control registers
+- #clock-cells:
+ Shall have value <1>. The permitted clock-specifier values
+ are the base clock numbers defined below.
+- clocks:
+ Shall contain a list of phandles for the external input
+ sources to the CGU. The list shall be in the following
+ order: xtal, 32khz, enet_rx_clk, enet_tx_clk, gp_clkin.
+- clock-indices:
+ Shall be an ordered list of numbers defining the base clock
+ number provided by the CGU.
+- clock-output-names:
+ Shall be an ordered list of strings defining the names of
+ the clocks provided by the CGU.
+
+Which base clocks that are available on the CGU depends on the
+specific LPC part. Base clocks are numbered from 0 to 27.
+
+Number: Name: Description:
+ 0 BASE_SAFE_CLK Base safe clock (always on) for WWDT
+ 1 BASE_USB0_CLK Base clock for USB0
+ 2 BASE_PERIPH_CLK Base clock for Cortex-M0SUB subsystem,
+ SPI, and SGPIO
+ 3 BASE_USB1_CLK Base clock for USB1
+ 4 BASE_CPU_CLK System base clock for ARM Cortex-M core
+ and APB peripheral blocks #0 and #2
+ 5 BASE_SPIFI_CLK Base clock for SPIFI
+ 6 BASE_SPI_CLK Base clock for SPI
+ 7 BASE_PHY_RX_CLK Base clock for Ethernet PHY Receive clock
+ 8 BASE_PHY_TX_CLK Base clock for Ethernet PHY Transmit clock
+ 9 BASE_APB1_CLK Base clock for APB peripheral block # 1
+10 BASE_APB3_CLK Base clock for APB peripheral block # 3
+11 BASE_LCD_CLK Base clock for LCD
+12 BASE_ADCHS_CLK Base clock for ADCHS
+13 BASE_SDIO_CLK Base clock for SD/MMC
+14 BASE_SSP0_CLK Base clock for SSP0
+15 BASE_SSP1_CLK Base clock for SSP1
+16 BASE_UART0_CLK Base clock for UART0
+17 BASE_UART1_CLK Base clock for UART1
+18 BASE_UART2_CLK Base clock for UART2
+19 BASE_UART3_CLK Base clock for UART3
+20 BASE_OUT_CLK Base clock for CLKOUT pin
+24-21 - Reserved
+25 BASE_AUDIO_CLK Base clock for audio system (I2S)
+26 BASE_CGU_OUT0_CLK Base clock for CGU_OUT0 clock output
+27 BASE_CGU_OUT1_CLK Base clock for CGU_OUT1 clock output
+
+BASE_PERIPH_CLK and BASE_SPI_CLK is only available on LPC43xx.
+BASE_ADCHS_CLK is only available on LPC4370.
+
+
+Example board file:
+
+/ {
+ clocks {
+ xtal: xtal {
+ compatible = "fixed-clock";
+ #clock-cells = <0>;
+ clock-frequency = <12000000>;
+ };
+
+ xtal32: xtal32 {
+ compatible = "fixed-clock";
+ #clock-cells = <0>;
+ clock-frequency = <32768>;
+ };
+
+ enet_rx_clk: enet_rx_clk {
+ compatible = "fixed-clock";
+ #clock-cells = <0>;
+ clock-frequency = <0>;
+ clock-output-names = "enet_rx_clk";
+ };
+
+ enet_tx_clk: enet_tx_clk {
+ compatible = "fixed-clock";
+ #clock-cells = <0>;
+ clock-frequency = <0>;
+ clock-output-names = "enet_tx_clk";
+ };
+
+ gp_clkin: gp_clkin {
+ compatible = "fixed-clock";
+ #clock-cells = <0>;
+ clock-frequency = <0>;
+ clock-output-names = "gp_clkin";
+ };
+ };
+
+ soc {
+ cgu: clock-controller@40050000 {
+ compatible = "nxp,lpc1850-cgu";
+ reg = <0x40050000 0x1000>;
+ #clock-cells = <1>;
+ clocks = <&xtal>, <&creg_clk 1>, <&enet_rx_clk>, <&enet_tx_clk>, <&gp_clkin>;
+ };
+
+ /* A CGU and CCU clock consumer */
+ lcdc: lcdc@40008000 {
+ ...
+ clocks = <&cgu BASE_LCD_CLK>, <&ccu1 CLK_CPU_LCD>;
+ clock-names = "clcdclk", "apb_pclk";
+ ...
+ };
+ };
+};
--
1.8.0
^ permalink raw reply related [flat|nested] 30+ messages in thread
* [PATCH v4 2/5] doc: dt: add documentation for lpc1850-cgu clk driver
@ 2015-05-28 20:31 ` Joachim Eastwood
0 siblings, 0 replies; 30+ messages in thread
From: Joachim Eastwood @ 2015-05-28 20:31 UTC (permalink / raw)
To: linux-arm-kernel
Add DT binding documentation for lpc1850-cgu driver.
Signed-off-by: Joachim Eastwood <manabian@gmail.com>
---
.../devicetree/bindings/clock/lpc1850-cgu.txt | 131 +++++++++++++++++++++
1 file changed, 131 insertions(+)
create mode 100644 Documentation/devicetree/bindings/clock/lpc1850-cgu.txt
diff --git a/Documentation/devicetree/bindings/clock/lpc1850-cgu.txt b/Documentation/devicetree/bindings/clock/lpc1850-cgu.txt
new file mode 100644
index 000000000000..2cc32a9a945a
--- /dev/null
+++ b/Documentation/devicetree/bindings/clock/lpc1850-cgu.txt
@@ -0,0 +1,131 @@
+* NXP LPC1850 Clock Generation Unit (CGU)
+
+The CGU generates multiple independent clocks for the core and the
+peripheral blocks of the LPC18xx. Each independent clock is called
+a base clock and itself is one of the inputs to the two Clock
+Control Units (CCUs) which control the branch clocks to the
+individual peripherals.
+
+The CGU selects the inputs to the clock generators from multiple
+clock sources, controls the clock generation, and routes the outputs
+of the clock generators through the clock source bus to the output
+stages. Each output stage provides an independent clock source and
+corresponds to one of the base clocks for the LPC18xx.
+
+ - Above text taken from NXP LPC1850 User Manual.
+
+
+This binding uses the common clock binding:
+ Documentation/devicetree/bindings/clock/clock-bindings.txt
+
+Required properties:
+- compatible:
+ Should be "nxp,lpc1850-cgu"
+- reg:
+ Shall define the base and range of the address space
+ containing clock control registers
+- #clock-cells:
+ Shall have value <1>. The permitted clock-specifier values
+ are the base clock numbers defined below.
+- clocks:
+ Shall contain a list of phandles for the external input
+ sources to the CGU. The list shall be in the following
+ order: xtal, 32khz, enet_rx_clk, enet_tx_clk, gp_clkin.
+- clock-indices:
+ Shall be an ordered list of numbers defining the base clock
+ number provided by the CGU.
+- clock-output-names:
+ Shall be an ordered list of strings defining the names of
+ the clocks provided by the CGU.
+
+Which base clocks that are available on the CGU depends on the
+specific LPC part. Base clocks are numbered from 0 to 27.
+
+Number: Name: Description:
+ 0 BASE_SAFE_CLK Base safe clock (always on) for WWDT
+ 1 BASE_USB0_CLK Base clock for USB0
+ 2 BASE_PERIPH_CLK Base clock for Cortex-M0SUB subsystem,
+ SPI, and SGPIO
+ 3 BASE_USB1_CLK Base clock for USB1
+ 4 BASE_CPU_CLK System base clock for ARM Cortex-M core
+ and APB peripheral blocks #0 and #2
+ 5 BASE_SPIFI_CLK Base clock for SPIFI
+ 6 BASE_SPI_CLK Base clock for SPI
+ 7 BASE_PHY_RX_CLK Base clock for Ethernet PHY Receive clock
+ 8 BASE_PHY_TX_CLK Base clock for Ethernet PHY Transmit clock
+ 9 BASE_APB1_CLK Base clock for APB peripheral block # 1
+10 BASE_APB3_CLK Base clock for APB peripheral block # 3
+11 BASE_LCD_CLK Base clock for LCD
+12 BASE_ADCHS_CLK Base clock for ADCHS
+13 BASE_SDIO_CLK Base clock for SD/MMC
+14 BASE_SSP0_CLK Base clock for SSP0
+15 BASE_SSP1_CLK Base clock for SSP1
+16 BASE_UART0_CLK Base clock for UART0
+17 BASE_UART1_CLK Base clock for UART1
+18 BASE_UART2_CLK Base clock for UART2
+19 BASE_UART3_CLK Base clock for UART3
+20 BASE_OUT_CLK Base clock for CLKOUT pin
+24-21 - Reserved
+25 BASE_AUDIO_CLK Base clock for audio system (I2S)
+26 BASE_CGU_OUT0_CLK Base clock for CGU_OUT0 clock output
+27 BASE_CGU_OUT1_CLK Base clock for CGU_OUT1 clock output
+
+BASE_PERIPH_CLK and BASE_SPI_CLK is only available on LPC43xx.
+BASE_ADCHS_CLK is only available on LPC4370.
+
+
+Example board file:
+
+/ {
+ clocks {
+ xtal: xtal {
+ compatible = "fixed-clock";
+ #clock-cells = <0>;
+ clock-frequency = <12000000>;
+ };
+
+ xtal32: xtal32 {
+ compatible = "fixed-clock";
+ #clock-cells = <0>;
+ clock-frequency = <32768>;
+ };
+
+ enet_rx_clk: enet_rx_clk {
+ compatible = "fixed-clock";
+ #clock-cells = <0>;
+ clock-frequency = <0>;
+ clock-output-names = "enet_rx_clk";
+ };
+
+ enet_tx_clk: enet_tx_clk {
+ compatible = "fixed-clock";
+ #clock-cells = <0>;
+ clock-frequency = <0>;
+ clock-output-names = "enet_tx_clk";
+ };
+
+ gp_clkin: gp_clkin {
+ compatible = "fixed-clock";
+ #clock-cells = <0>;
+ clock-frequency = <0>;
+ clock-output-names = "gp_clkin";
+ };
+ };
+
+ soc {
+ cgu: clock-controller at 40050000 {
+ compatible = "nxp,lpc1850-cgu";
+ reg = <0x40050000 0x1000>;
+ #clock-cells = <1>;
+ clocks = <&xtal>, <&creg_clk 1>, <&enet_rx_clk>, <&enet_tx_clk>, <&gp_clkin>;
+ };
+
+ /* A CGU and CCU clock consumer */
+ lcdc: lcdc at 40008000 {
+ ...
+ clocks = <&cgu BASE_LCD_CLK>, <&ccu1 CLK_CPU_LCD>;
+ clock-names = "clcdclk", "apb_pclk";
+ ...
+ };
+ };
+};
--
1.8.0
^ permalink raw reply related [flat|nested] 30+ messages in thread
* [PATCH v4 3/5] clk: add lpc18xx ccu clk driver
2015-05-28 20:31 ` Joachim Eastwood
(?)
@ 2015-05-28 20:31 ` Joachim Eastwood
-1 siblings, 0 replies; 30+ messages in thread
From: Joachim Eastwood @ 2015-05-28 20:31 UTC (permalink / raw)
To: mturquette-QSEj5FYQhm4dnm+yROfE0A, sboyd-sgV2jX0FEOL9JmXXK+q4OQ
Cc: Joachim Eastwood, linux-clk-u79uwXL29TY76Z2rM5mHXA,
devicetree-u79uwXL29TY76Z2rM5mHXA,
linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r
Add driver for NXP LPC18xx/43xx Clock Control Unit (CCU). The CCU
provides fine grained gating of most clocks present in the SoC.
Signed-off-by: Joachim Eastwood <manabian-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
---
drivers/clk/nxp/Makefile | 1 +
drivers/clk/nxp/clk-lpc18xx-ccu.c | 293 ++++++++++++++++++++++++++++++++
include/dt-bindings/clock/lpc18xx-ccu.h | 74 ++++++++
3 files changed, 368 insertions(+)
create mode 100644 drivers/clk/nxp/clk-lpc18xx-ccu.c
create mode 100644 include/dt-bindings/clock/lpc18xx-ccu.h
diff --git a/drivers/clk/nxp/Makefile b/drivers/clk/nxp/Makefile
index aca9d3e4f7fe..7f608b0ad7b4 100644
--- a/drivers/clk/nxp/Makefile
+++ b/drivers/clk/nxp/Makefile
@@ -1 +1,2 @@
obj-$(CONFIG_ARCH_LPC18XX) += clk-lpc18xx-cgu.o
+obj-$(CONFIG_ARCH_LPC18XX) += clk-lpc18xx-ccu.o
diff --git a/drivers/clk/nxp/clk-lpc18xx-ccu.c b/drivers/clk/nxp/clk-lpc18xx-ccu.c
new file mode 100644
index 000000000000..eeaee97da110
--- /dev/null
+++ b/drivers/clk/nxp/clk-lpc18xx-ccu.c
@@ -0,0 +1,293 @@
+/*
+ * Clk driver for NXP LPC18xx/LPC43xx Clock Control Unit (CCU)
+ *
+ * Copyright (C) 2015 Joachim Eastwood <manabian-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2. This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+#include <linux/clk.h>
+#include <linux/clk-provider.h>
+#include <linux/kernel.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/slab.h>
+#include <linux/string.h>
+
+#include <dt-bindings/clock/lpc18xx-ccu.h>
+
+/* Bit defines for CCU branch configuration register */
+#define LPC18XX_CCU_RUN BIT(0)
+#define LPC18XX_CCU_AUTO BIT(1)
+#define LPC18XX_CCU_DIV BIT(5)
+#define LPC18XX_CCU_DIVSTAT BIT(27)
+
+/* CCU branch feature bits */
+#define CCU_BRANCH_IS_BUS BIT(0)
+#define CCU_BRANCH_HAVE_DIV2 BIT(1)
+
+#define to_clk_gate(_hw) container_of(_hw, struct clk_gate, hw)
+
+struct lpc18xx_branch_clk_data {
+ const char **name;
+ int num;
+};
+
+struct lpc18xx_clk_branch {
+ const char *base_name;
+ const char *name;
+ u16 offset;
+ u16 flags;
+ struct clk *clk;
+ struct clk_gate gate;
+};
+
+static struct lpc18xx_clk_branch clk_branches[] = {
+ {"base_apb3_clk", "apb3_bus", CLK_APB3_BUS, CCU_BRANCH_IS_BUS},
+ {"base_apb3_clk", "apb3_i2c1", CLK_APB3_I2C1, 0},
+ {"base_apb3_clk", "apb3_dac", CLK_APB3_DAC, 0},
+ {"base_apb3_clk", "apb3_adc0", CLK_APB3_ADC0, 0},
+ {"base_apb3_clk", "apb3_adc1", CLK_APB3_ADC1, 0},
+ {"base_apb3_clk", "apb3_can0", CLK_APB3_CAN0, 0},
+
+ {"base_apb1_clk", "apb1_bus", CLK_APB1_BUS, CCU_BRANCH_IS_BUS},
+ {"base_apb1_clk", "apb1_mc_pwm", CLK_APB1_MOTOCON_PWM, 0},
+ {"base_apb1_clk", "apb1_i2c0", CLK_APB1_I2C0, 0},
+ {"base_apb1_clk", "apb1_i2s", CLK_APB1_I2S, 0},
+ {"base_apb1_clk", "apb1_can1", CLK_APB1_CAN1, 0},
+
+ {"base_spifi_clk", "spifi", CLK_SPIFI, 0},
+
+ {"base_cpu_clk", "cpu_bus", CLK_CPU_BUS, CCU_BRANCH_IS_BUS},
+ {"base_cpu_clk", "cpu_spifi", CLK_CPU_SPIFI, 0},
+ {"base_cpu_clk", "cpu_gpio", CLK_CPU_GPIO, 0},
+ {"base_cpu_clk", "cpu_lcd", CLK_CPU_LCD, 0},
+ {"base_cpu_clk", "cpu_ethernet", CLK_CPU_ETHERNET, 0},
+ {"base_cpu_clk", "cpu_usb0", CLK_CPU_USB0, 0},
+ {"base_cpu_clk", "cpu_emc", CLK_CPU_EMC, 0},
+ {"base_cpu_clk", "cpu_sdio", CLK_CPU_SDIO, 0},
+ {"base_cpu_clk", "cpu_dma", CLK_CPU_DMA, 0},
+ {"base_cpu_clk", "cpu_core", CLK_CPU_CORE, 0},
+ {"base_cpu_clk", "cpu_sct", CLK_CPU_SCT, 0},
+ {"base_cpu_clk", "cpu_usb1", CLK_CPU_USB1, 0},
+ {"base_cpu_clk", "cpu_emcdiv", CLK_CPU_EMCDIV, CCU_BRANCH_HAVE_DIV2},
+ {"base_cpu_clk", "cpu_flasha", CLK_CPU_FLASHA, CCU_BRANCH_HAVE_DIV2},
+ {"base_cpu_clk", "cpu_flashb", CLK_CPU_FLASHB, CCU_BRANCH_HAVE_DIV2},
+ {"base_cpu_clk", "cpu_m0app", CLK_CPU_M0APP, CCU_BRANCH_HAVE_DIV2},
+ {"base_cpu_clk", "cpu_adchs", CLK_CPU_ADCHS, CCU_BRANCH_HAVE_DIV2},
+ {"base_cpu_clk", "cpu_eeprom", CLK_CPU_EEPROM, CCU_BRANCH_HAVE_DIV2},
+ {"base_cpu_clk", "cpu_wwdt", CLK_CPU_WWDT, 0},
+ {"base_cpu_clk", "cpu_uart0", CLK_CPU_UART0, 0},
+ {"base_cpu_clk", "cpu_uart1", CLK_CPU_UART1, 0},
+ {"base_cpu_clk", "cpu_ssp0", CLK_CPU_SSP0, 0},
+ {"base_cpu_clk", "cpu_timer0", CLK_CPU_TIMER0, 0},
+ {"base_cpu_clk", "cpu_timer1", CLK_CPU_TIMER1, 0},
+ {"base_cpu_clk", "cpu_scu", CLK_CPU_SCU, 0},
+ {"base_cpu_clk", "cpu_creg", CLK_CPU_CREG, 0},
+ {"base_cpu_clk", "cpu_ritimer", CLK_CPU_RITIMER, 0},
+ {"base_cpu_clk", "cpu_uart2", CLK_CPU_UART2, 0},
+ {"base_cpu_clk", "cpu_uart3", CLK_CPU_UART3, 0},
+ {"base_cpu_clk", "cpu_timer2", CLK_CPU_TIMER2, 0},
+ {"base_cpu_clk", "cpu_timer3", CLK_CPU_TIMER3, 0},
+ {"base_cpu_clk", "cpu_ssp1", CLK_CPU_SSP1, 0},
+ {"base_cpu_clk", "cpu_qei", CLK_CPU_QEI, 0},
+
+ {"base_periph_clk", "periph_bus", CLK_PERIPH_BUS, CCU_BRANCH_IS_BUS},
+ {"base_periph_clk", "periph_core", CLK_PERIPH_CORE, 0},
+ {"base_periph_clk", "periph_sgpio", CLK_PERIPH_SGPIO, 0},
+
+ {"base_usb0_clk", "usb0", CLK_USB0, 0},
+ {"base_usb1_clk", "usb1", CLK_USB1, 0},
+ {"base_spi_clk", "spi", CLK_SPI, 0},
+ {"base_adchs_clk", "adchs", CLK_ADCHS, 0},
+
+ {"base_audio_clk", "audio", CLK_AUDIO, 0},
+ {"base_uart3_clk", "apb2_uart3", CLK_APB2_UART3, 0},
+ {"base_uart2_clk", "apb2_uart2", CLK_APB2_UART2, 0},
+ {"base_uart1_clk", "apb0_uart1", CLK_APB0_UART1, 0},
+ {"base_uart0_clk", "apb0_uart0", CLK_APB0_UART0, 0},
+ {"base_ssp1_clk", "apb2_ssp1", CLK_APB2_SSP1, 0},
+ {"base_ssp0_clk", "apb0_ssp0", CLK_APB0_SSP0, 0},
+ {"base_sdio_clk", "sdio", CLK_SDIO, 0},
+};
+
+static struct clk *lpc18xx_ccu_branch_clk_get(struct of_phandle_args *clkspec,
+ void *data)
+{
+ struct lpc18xx_branch_clk_data *clk_data = data;
+ unsigned int offset = clkspec->args[0];
+ int i, j;
+
+ for (i = 0; i < ARRAY_SIZE(clk_branches); i++) {
+ if (clk_branches[i].offset != offset)
+ continue;
+
+ for (j = 0; j < clk_data->num; j++) {
+ if (!strcmp(clk_branches[i].base_name, clk_data->name[j]))
+ return clk_branches[i].clk;
+ }
+ }
+
+ pr_err("%s: invalid clock offset %d\n", __func__, offset);
+
+ return ERR_PTR(-EINVAL);
+}
+
+static int lpc18xx_ccu_gate_endisable(struct clk_hw *hw, bool enable)
+{
+ struct clk_gate *gate = to_clk_gate(hw);
+ u32 val;
+
+ /*
+ * Divider field is write only, so divider stat field must
+ * be read so divider field can be set accordingly.
+ */
+ val = clk_readl(gate->reg);
+ if (val & LPC18XX_CCU_DIVSTAT)
+ val |= LPC18XX_CCU_DIV;
+
+ if (enable) {
+ val |= LPC18XX_CCU_RUN;
+ } else {
+ /*
+ * To safely disable a branch clock a squence of two separate
+ * writes must be used. First write should set the AUTO bit
+ * and the next write should clear the RUN bit.
+ */
+ val |= LPC18XX_CCU_AUTO;
+ clk_writel(val, gate->reg);
+
+ val &= ~LPC18XX_CCU_RUN;
+ }
+
+ clk_writel(val, gate->reg);
+
+ return 0;
+}
+
+static int lpc18xx_ccu_gate_enable(struct clk_hw *hw)
+{
+ return lpc18xx_ccu_gate_endisable(hw, true);
+}
+
+static void lpc18xx_ccu_gate_disable(struct clk_hw *hw)
+{
+ lpc18xx_ccu_gate_endisable(hw, false);
+}
+
+static int lpc18xx_ccu_gate_is_enabled(struct clk_hw *hw)
+{
+ struct clk_gate *gate = to_clk_gate(hw);
+
+ return clk_readl(gate->reg) & LPC18XX_CCU_RUN;
+}
+
+static const struct clk_ops lpc18xx_ccu_gate_ops = {
+ .enable = lpc18xx_ccu_gate_enable,
+ .disable = lpc18xx_ccu_gate_disable,
+ .is_enabled = lpc18xx_ccu_gate_is_enabled,
+};
+
+static void lpc18xx_ccu_register_branch_gate_div(struct lpc18xx_clk_branch *branch,
+ void __iomem *reg_base,
+ const char *parent)
+{
+ const struct clk_ops *div_ops = NULL;
+ struct clk_divider *div = NULL;
+ struct clk_hw *div_hw = NULL;
+
+ if (branch->flags & CCU_BRANCH_HAVE_DIV2) {
+ div = kzalloc(sizeof(*div), GFP_KERNEL);
+ if (!div)
+ return;
+
+ div->reg = branch->offset + reg_base;
+ div->flags = CLK_DIVIDER_READ_ONLY;
+ div->shift = 27;
+ div->width = 1;
+
+ div_hw = &div->hw;
+ div_ops = &clk_divider_ops;
+ }
+
+ branch->gate.reg = branch->offset + reg_base;
+ branch->gate.bit_idx = 0;
+
+ branch->clk = clk_register_composite(NULL, branch->name, &parent, 1,
+ NULL, NULL,
+ div_hw, div_ops,
+ &branch->gate.hw, &lpc18xx_ccu_gate_ops, 0);
+ if (IS_ERR(branch->clk)) {
+ kfree(div);
+ pr_warn("%s: failed to register %s\n", __func__, branch->name);
+ return;
+ }
+
+ /* Grab essential branch clocks for CPU and SDRAM */
+ switch (branch->offset) {
+ case CLK_CPU_EMC:
+ case CLK_CPU_CORE:
+ case CLK_CPU_CREG:
+ case CLK_CPU_EMCDIV:
+ clk_prepare_enable(branch->clk);
+ }
+}
+
+static void lpc18xx_ccu_register_branch_clks(void __iomem *reg_base,
+ const char *base_name)
+{
+ const char *parent = base_name;
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(clk_branches); i++) {
+ if (strcmp(clk_branches[i].base_name, base_name))
+ continue;
+
+ lpc18xx_ccu_register_branch_gate_div(&clk_branches[i], reg_base,
+ parent);
+
+ if (clk_branches[i].flags & CCU_BRANCH_IS_BUS)
+ parent = clk_branches[i].name;
+ }
+}
+
+static void __init lpc18xx_ccu_init(struct device_node *np)
+{
+ struct lpc18xx_branch_clk_data *clk_data;
+ void __iomem *reg_base;
+ int i, ret;
+
+ reg_base = of_iomap(np, 0);
+ if (!reg_base) {
+ pr_warn("%s: failed to map address range\n", __func__);
+ return;
+ }
+
+ clk_data = kzalloc(sizeof(*clk_data), GFP_KERNEL);
+ if (!clk_data)
+ return;
+
+ clk_data->num = of_property_count_strings(np, "clock-names");
+ clk_data->name = kcalloc(clk_data->num, sizeof(char *), GFP_KERNEL);
+ if (!clk_data->name) {
+ kfree(clk_data);
+ return;
+ }
+
+ for (i = 0; i < clk_data->num; i++) {
+ ret = of_property_read_string_index(np, "clock-names", i,
+ &clk_data->name[i]);
+ if (ret) {
+ pr_warn("%s: failed to get clock name at idx %d\n",
+ __func__, i);
+ continue;
+ }
+
+ lpc18xx_ccu_register_branch_clks(reg_base, clk_data->name[i]);
+ }
+
+ of_clk_add_provider(np, lpc18xx_ccu_branch_clk_get, clk_data);
+}
+CLK_OF_DECLARE(lpc18xx_ccu, "nxp,lpc1850-ccu", lpc18xx_ccu_init);
diff --git a/include/dt-bindings/clock/lpc18xx-ccu.h b/include/dt-bindings/clock/lpc18xx-ccu.h
new file mode 100644
index 000000000000..bbfe00b6ab7d
--- /dev/null
+++ b/include/dt-bindings/clock/lpc18xx-ccu.h
@@ -0,0 +1,74 @@
+/*
+ * Copyright (c) 2015 Joachim Eastwood <manabian-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
+ *
+ * This code is released using a dual license strategy: BSD/GPL
+ * You can choose the licence that better fits your requirements.
+ *
+ * Released under the terms of 3-clause BSD License
+ * Released under the terms of GNU General Public License Version 2.0
+ *
+ */
+
+/* Clock Control Unit 1 (CCU1) clock offsets */
+#define CLK_APB3_BUS 0x100
+#define CLK_APB3_I2C1 0x108
+#define CLK_APB3_DAC 0x110
+#define CLK_APB3_ADC0 0x118
+#define CLK_APB3_ADC1 0x120
+#define CLK_APB3_CAN0 0x128
+#define CLK_APB1_BUS 0x200
+#define CLK_APB1_MOTOCON_PWM 0x208
+#define CLK_APB1_I2C0 0x210
+#define CLK_APB1_I2S 0x218
+#define CLK_APB1_CAN1 0x220
+#define CLK_SPIFI 0x300
+#define CLK_CPU_BUS 0x400
+#define CLK_CPU_SPIFI 0x408
+#define CLK_CPU_GPIO 0x410
+#define CLK_CPU_LCD 0x418
+#define CLK_CPU_ETHERNET 0x420
+#define CLK_CPU_USB0 0x428
+#define CLK_CPU_EMC 0x430
+#define CLK_CPU_SDIO 0x438
+#define CLK_CPU_DMA 0x440
+#define CLK_CPU_CORE 0x448
+#define CLK_CPU_SCT 0x468
+#define CLK_CPU_USB1 0x470
+#define CLK_CPU_EMCDIV 0x478
+#define CLK_CPU_FLASHA 0x480
+#define CLK_CPU_FLASHB 0x488
+#define CLK_CPU_M0APP 0x490
+#define CLK_CPU_ADCHS 0x498
+#define CLK_CPU_EEPROM 0x4a0
+#define CLK_CPU_WWDT 0x500
+#define CLK_CPU_UART0 0x508
+#define CLK_CPU_UART1 0x510
+#define CLK_CPU_SSP0 0x518
+#define CLK_CPU_TIMER0 0x520
+#define CLK_CPU_TIMER1 0x528
+#define CLK_CPU_SCU 0x530
+#define CLK_CPU_CREG 0x538
+#define CLK_CPU_RITIMER 0x600
+#define CLK_CPU_UART2 0x608
+#define CLK_CPU_UART3 0x610
+#define CLK_CPU_TIMER2 0x618
+#define CLK_CPU_TIMER3 0x620
+#define CLK_CPU_SSP1 0x628
+#define CLK_CPU_QEI 0x630
+#define CLK_PERIPH_BUS 0x700
+#define CLK_PERIPH_CORE 0x710
+#define CLK_PERIPH_SGPIO 0x718
+#define CLK_USB0 0x800
+#define CLK_USB1 0x900
+#define CLK_SPI 0xA00
+#define CLK_ADCHS 0xB00
+
+/* Clock Control Unit 2 (CCU2) clock offsets */
+#define CLK_AUDIO 0x100
+#define CLK_APB2_UART3 0x200
+#define CLK_APB2_UART2 0x300
+#define CLK_APB0_UART1 0x400
+#define CLK_APB0_UART0 0x500
+#define CLK_APB2_SSP1 0x600
+#define CLK_APB0_SSP0 0x700
+#define CLK_SDIO 0x800
--
1.8.0
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply related [flat|nested] 30+ messages in thread
* [PATCH v4 3/5] clk: add lpc18xx ccu clk driver
@ 2015-05-28 20:31 ` Joachim Eastwood
0 siblings, 0 replies; 30+ messages in thread
From: Joachim Eastwood @ 2015-05-28 20:31 UTC (permalink / raw)
To: mturquette, sboyd
Cc: Joachim Eastwood, linux-clk, devicetree, linux-arm-kernel
Add driver for NXP LPC18xx/43xx Clock Control Unit (CCU). The CCU
provides fine grained gating of most clocks present in the SoC.
Signed-off-by: Joachim Eastwood <manabian@gmail.com>
---
drivers/clk/nxp/Makefile | 1 +
drivers/clk/nxp/clk-lpc18xx-ccu.c | 293 ++++++++++++++++++++++++++++++++
include/dt-bindings/clock/lpc18xx-ccu.h | 74 ++++++++
3 files changed, 368 insertions(+)
create mode 100644 drivers/clk/nxp/clk-lpc18xx-ccu.c
create mode 100644 include/dt-bindings/clock/lpc18xx-ccu.h
diff --git a/drivers/clk/nxp/Makefile b/drivers/clk/nxp/Makefile
index aca9d3e4f7fe..7f608b0ad7b4 100644
--- a/drivers/clk/nxp/Makefile
+++ b/drivers/clk/nxp/Makefile
@@ -1 +1,2 @@
obj-$(CONFIG_ARCH_LPC18XX) += clk-lpc18xx-cgu.o
+obj-$(CONFIG_ARCH_LPC18XX) += clk-lpc18xx-ccu.o
diff --git a/drivers/clk/nxp/clk-lpc18xx-ccu.c b/drivers/clk/nxp/clk-lpc18xx-ccu.c
new file mode 100644
index 000000000000..eeaee97da110
--- /dev/null
+++ b/drivers/clk/nxp/clk-lpc18xx-ccu.c
@@ -0,0 +1,293 @@
+/*
+ * Clk driver for NXP LPC18xx/LPC43xx Clock Control Unit (CCU)
+ *
+ * Copyright (C) 2015 Joachim Eastwood <manabian@gmail.com>
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2. This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+#include <linux/clk.h>
+#include <linux/clk-provider.h>
+#include <linux/kernel.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/slab.h>
+#include <linux/string.h>
+
+#include <dt-bindings/clock/lpc18xx-ccu.h>
+
+/* Bit defines for CCU branch configuration register */
+#define LPC18XX_CCU_RUN BIT(0)
+#define LPC18XX_CCU_AUTO BIT(1)
+#define LPC18XX_CCU_DIV BIT(5)
+#define LPC18XX_CCU_DIVSTAT BIT(27)
+
+/* CCU branch feature bits */
+#define CCU_BRANCH_IS_BUS BIT(0)
+#define CCU_BRANCH_HAVE_DIV2 BIT(1)
+
+#define to_clk_gate(_hw) container_of(_hw, struct clk_gate, hw)
+
+struct lpc18xx_branch_clk_data {
+ const char **name;
+ int num;
+};
+
+struct lpc18xx_clk_branch {
+ const char *base_name;
+ const char *name;
+ u16 offset;
+ u16 flags;
+ struct clk *clk;
+ struct clk_gate gate;
+};
+
+static struct lpc18xx_clk_branch clk_branches[] = {
+ {"base_apb3_clk", "apb3_bus", CLK_APB3_BUS, CCU_BRANCH_IS_BUS},
+ {"base_apb3_clk", "apb3_i2c1", CLK_APB3_I2C1, 0},
+ {"base_apb3_clk", "apb3_dac", CLK_APB3_DAC, 0},
+ {"base_apb3_clk", "apb3_adc0", CLK_APB3_ADC0, 0},
+ {"base_apb3_clk", "apb3_adc1", CLK_APB3_ADC1, 0},
+ {"base_apb3_clk", "apb3_can0", CLK_APB3_CAN0, 0},
+
+ {"base_apb1_clk", "apb1_bus", CLK_APB1_BUS, CCU_BRANCH_IS_BUS},
+ {"base_apb1_clk", "apb1_mc_pwm", CLK_APB1_MOTOCON_PWM, 0},
+ {"base_apb1_clk", "apb1_i2c0", CLK_APB1_I2C0, 0},
+ {"base_apb1_clk", "apb1_i2s", CLK_APB1_I2S, 0},
+ {"base_apb1_clk", "apb1_can1", CLK_APB1_CAN1, 0},
+
+ {"base_spifi_clk", "spifi", CLK_SPIFI, 0},
+
+ {"base_cpu_clk", "cpu_bus", CLK_CPU_BUS, CCU_BRANCH_IS_BUS},
+ {"base_cpu_clk", "cpu_spifi", CLK_CPU_SPIFI, 0},
+ {"base_cpu_clk", "cpu_gpio", CLK_CPU_GPIO, 0},
+ {"base_cpu_clk", "cpu_lcd", CLK_CPU_LCD, 0},
+ {"base_cpu_clk", "cpu_ethernet", CLK_CPU_ETHERNET, 0},
+ {"base_cpu_clk", "cpu_usb0", CLK_CPU_USB0, 0},
+ {"base_cpu_clk", "cpu_emc", CLK_CPU_EMC, 0},
+ {"base_cpu_clk", "cpu_sdio", CLK_CPU_SDIO, 0},
+ {"base_cpu_clk", "cpu_dma", CLK_CPU_DMA, 0},
+ {"base_cpu_clk", "cpu_core", CLK_CPU_CORE, 0},
+ {"base_cpu_clk", "cpu_sct", CLK_CPU_SCT, 0},
+ {"base_cpu_clk", "cpu_usb1", CLK_CPU_USB1, 0},
+ {"base_cpu_clk", "cpu_emcdiv", CLK_CPU_EMCDIV, CCU_BRANCH_HAVE_DIV2},
+ {"base_cpu_clk", "cpu_flasha", CLK_CPU_FLASHA, CCU_BRANCH_HAVE_DIV2},
+ {"base_cpu_clk", "cpu_flashb", CLK_CPU_FLASHB, CCU_BRANCH_HAVE_DIV2},
+ {"base_cpu_clk", "cpu_m0app", CLK_CPU_M0APP, CCU_BRANCH_HAVE_DIV2},
+ {"base_cpu_clk", "cpu_adchs", CLK_CPU_ADCHS, CCU_BRANCH_HAVE_DIV2},
+ {"base_cpu_clk", "cpu_eeprom", CLK_CPU_EEPROM, CCU_BRANCH_HAVE_DIV2},
+ {"base_cpu_clk", "cpu_wwdt", CLK_CPU_WWDT, 0},
+ {"base_cpu_clk", "cpu_uart0", CLK_CPU_UART0, 0},
+ {"base_cpu_clk", "cpu_uart1", CLK_CPU_UART1, 0},
+ {"base_cpu_clk", "cpu_ssp0", CLK_CPU_SSP0, 0},
+ {"base_cpu_clk", "cpu_timer0", CLK_CPU_TIMER0, 0},
+ {"base_cpu_clk", "cpu_timer1", CLK_CPU_TIMER1, 0},
+ {"base_cpu_clk", "cpu_scu", CLK_CPU_SCU, 0},
+ {"base_cpu_clk", "cpu_creg", CLK_CPU_CREG, 0},
+ {"base_cpu_clk", "cpu_ritimer", CLK_CPU_RITIMER, 0},
+ {"base_cpu_clk", "cpu_uart2", CLK_CPU_UART2, 0},
+ {"base_cpu_clk", "cpu_uart3", CLK_CPU_UART3, 0},
+ {"base_cpu_clk", "cpu_timer2", CLK_CPU_TIMER2, 0},
+ {"base_cpu_clk", "cpu_timer3", CLK_CPU_TIMER3, 0},
+ {"base_cpu_clk", "cpu_ssp1", CLK_CPU_SSP1, 0},
+ {"base_cpu_clk", "cpu_qei", CLK_CPU_QEI, 0},
+
+ {"base_periph_clk", "periph_bus", CLK_PERIPH_BUS, CCU_BRANCH_IS_BUS},
+ {"base_periph_clk", "periph_core", CLK_PERIPH_CORE, 0},
+ {"base_periph_clk", "periph_sgpio", CLK_PERIPH_SGPIO, 0},
+
+ {"base_usb0_clk", "usb0", CLK_USB0, 0},
+ {"base_usb1_clk", "usb1", CLK_USB1, 0},
+ {"base_spi_clk", "spi", CLK_SPI, 0},
+ {"base_adchs_clk", "adchs", CLK_ADCHS, 0},
+
+ {"base_audio_clk", "audio", CLK_AUDIO, 0},
+ {"base_uart3_clk", "apb2_uart3", CLK_APB2_UART3, 0},
+ {"base_uart2_clk", "apb2_uart2", CLK_APB2_UART2, 0},
+ {"base_uart1_clk", "apb0_uart1", CLK_APB0_UART1, 0},
+ {"base_uart0_clk", "apb0_uart0", CLK_APB0_UART0, 0},
+ {"base_ssp1_clk", "apb2_ssp1", CLK_APB2_SSP1, 0},
+ {"base_ssp0_clk", "apb0_ssp0", CLK_APB0_SSP0, 0},
+ {"base_sdio_clk", "sdio", CLK_SDIO, 0},
+};
+
+static struct clk *lpc18xx_ccu_branch_clk_get(struct of_phandle_args *clkspec,
+ void *data)
+{
+ struct lpc18xx_branch_clk_data *clk_data = data;
+ unsigned int offset = clkspec->args[0];
+ int i, j;
+
+ for (i = 0; i < ARRAY_SIZE(clk_branches); i++) {
+ if (clk_branches[i].offset != offset)
+ continue;
+
+ for (j = 0; j < clk_data->num; j++) {
+ if (!strcmp(clk_branches[i].base_name, clk_data->name[j]))
+ return clk_branches[i].clk;
+ }
+ }
+
+ pr_err("%s: invalid clock offset %d\n", __func__, offset);
+
+ return ERR_PTR(-EINVAL);
+}
+
+static int lpc18xx_ccu_gate_endisable(struct clk_hw *hw, bool enable)
+{
+ struct clk_gate *gate = to_clk_gate(hw);
+ u32 val;
+
+ /*
+ * Divider field is write only, so divider stat field must
+ * be read so divider field can be set accordingly.
+ */
+ val = clk_readl(gate->reg);
+ if (val & LPC18XX_CCU_DIVSTAT)
+ val |= LPC18XX_CCU_DIV;
+
+ if (enable) {
+ val |= LPC18XX_CCU_RUN;
+ } else {
+ /*
+ * To safely disable a branch clock a squence of two separate
+ * writes must be used. First write should set the AUTO bit
+ * and the next write should clear the RUN bit.
+ */
+ val |= LPC18XX_CCU_AUTO;
+ clk_writel(val, gate->reg);
+
+ val &= ~LPC18XX_CCU_RUN;
+ }
+
+ clk_writel(val, gate->reg);
+
+ return 0;
+}
+
+static int lpc18xx_ccu_gate_enable(struct clk_hw *hw)
+{
+ return lpc18xx_ccu_gate_endisable(hw, true);
+}
+
+static void lpc18xx_ccu_gate_disable(struct clk_hw *hw)
+{
+ lpc18xx_ccu_gate_endisable(hw, false);
+}
+
+static int lpc18xx_ccu_gate_is_enabled(struct clk_hw *hw)
+{
+ struct clk_gate *gate = to_clk_gate(hw);
+
+ return clk_readl(gate->reg) & LPC18XX_CCU_RUN;
+}
+
+static const struct clk_ops lpc18xx_ccu_gate_ops = {
+ .enable = lpc18xx_ccu_gate_enable,
+ .disable = lpc18xx_ccu_gate_disable,
+ .is_enabled = lpc18xx_ccu_gate_is_enabled,
+};
+
+static void lpc18xx_ccu_register_branch_gate_div(struct lpc18xx_clk_branch *branch,
+ void __iomem *reg_base,
+ const char *parent)
+{
+ const struct clk_ops *div_ops = NULL;
+ struct clk_divider *div = NULL;
+ struct clk_hw *div_hw = NULL;
+
+ if (branch->flags & CCU_BRANCH_HAVE_DIV2) {
+ div = kzalloc(sizeof(*div), GFP_KERNEL);
+ if (!div)
+ return;
+
+ div->reg = branch->offset + reg_base;
+ div->flags = CLK_DIVIDER_READ_ONLY;
+ div->shift = 27;
+ div->width = 1;
+
+ div_hw = &div->hw;
+ div_ops = &clk_divider_ops;
+ }
+
+ branch->gate.reg = branch->offset + reg_base;
+ branch->gate.bit_idx = 0;
+
+ branch->clk = clk_register_composite(NULL, branch->name, &parent, 1,
+ NULL, NULL,
+ div_hw, div_ops,
+ &branch->gate.hw, &lpc18xx_ccu_gate_ops, 0);
+ if (IS_ERR(branch->clk)) {
+ kfree(div);
+ pr_warn("%s: failed to register %s\n", __func__, branch->name);
+ return;
+ }
+
+ /* Grab essential branch clocks for CPU and SDRAM */
+ switch (branch->offset) {
+ case CLK_CPU_EMC:
+ case CLK_CPU_CORE:
+ case CLK_CPU_CREG:
+ case CLK_CPU_EMCDIV:
+ clk_prepare_enable(branch->clk);
+ }
+}
+
+static void lpc18xx_ccu_register_branch_clks(void __iomem *reg_base,
+ const char *base_name)
+{
+ const char *parent = base_name;
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(clk_branches); i++) {
+ if (strcmp(clk_branches[i].base_name, base_name))
+ continue;
+
+ lpc18xx_ccu_register_branch_gate_div(&clk_branches[i], reg_base,
+ parent);
+
+ if (clk_branches[i].flags & CCU_BRANCH_IS_BUS)
+ parent = clk_branches[i].name;
+ }
+}
+
+static void __init lpc18xx_ccu_init(struct device_node *np)
+{
+ struct lpc18xx_branch_clk_data *clk_data;
+ void __iomem *reg_base;
+ int i, ret;
+
+ reg_base = of_iomap(np, 0);
+ if (!reg_base) {
+ pr_warn("%s: failed to map address range\n", __func__);
+ return;
+ }
+
+ clk_data = kzalloc(sizeof(*clk_data), GFP_KERNEL);
+ if (!clk_data)
+ return;
+
+ clk_data->num = of_property_count_strings(np, "clock-names");
+ clk_data->name = kcalloc(clk_data->num, sizeof(char *), GFP_KERNEL);
+ if (!clk_data->name) {
+ kfree(clk_data);
+ return;
+ }
+
+ for (i = 0; i < clk_data->num; i++) {
+ ret = of_property_read_string_index(np, "clock-names", i,
+ &clk_data->name[i]);
+ if (ret) {
+ pr_warn("%s: failed to get clock name at idx %d\n",
+ __func__, i);
+ continue;
+ }
+
+ lpc18xx_ccu_register_branch_clks(reg_base, clk_data->name[i]);
+ }
+
+ of_clk_add_provider(np, lpc18xx_ccu_branch_clk_get, clk_data);
+}
+CLK_OF_DECLARE(lpc18xx_ccu, "nxp,lpc1850-ccu", lpc18xx_ccu_init);
diff --git a/include/dt-bindings/clock/lpc18xx-ccu.h b/include/dt-bindings/clock/lpc18xx-ccu.h
new file mode 100644
index 000000000000..bbfe00b6ab7d
--- /dev/null
+++ b/include/dt-bindings/clock/lpc18xx-ccu.h
@@ -0,0 +1,74 @@
+/*
+ * Copyright (c) 2015 Joachim Eastwood <manabian@gmail.com>
+ *
+ * This code is released using a dual license strategy: BSD/GPL
+ * You can choose the licence that better fits your requirements.
+ *
+ * Released under the terms of 3-clause BSD License
+ * Released under the terms of GNU General Public License Version 2.0
+ *
+ */
+
+/* Clock Control Unit 1 (CCU1) clock offsets */
+#define CLK_APB3_BUS 0x100
+#define CLK_APB3_I2C1 0x108
+#define CLK_APB3_DAC 0x110
+#define CLK_APB3_ADC0 0x118
+#define CLK_APB3_ADC1 0x120
+#define CLK_APB3_CAN0 0x128
+#define CLK_APB1_BUS 0x200
+#define CLK_APB1_MOTOCON_PWM 0x208
+#define CLK_APB1_I2C0 0x210
+#define CLK_APB1_I2S 0x218
+#define CLK_APB1_CAN1 0x220
+#define CLK_SPIFI 0x300
+#define CLK_CPU_BUS 0x400
+#define CLK_CPU_SPIFI 0x408
+#define CLK_CPU_GPIO 0x410
+#define CLK_CPU_LCD 0x418
+#define CLK_CPU_ETHERNET 0x420
+#define CLK_CPU_USB0 0x428
+#define CLK_CPU_EMC 0x430
+#define CLK_CPU_SDIO 0x438
+#define CLK_CPU_DMA 0x440
+#define CLK_CPU_CORE 0x448
+#define CLK_CPU_SCT 0x468
+#define CLK_CPU_USB1 0x470
+#define CLK_CPU_EMCDIV 0x478
+#define CLK_CPU_FLASHA 0x480
+#define CLK_CPU_FLASHB 0x488
+#define CLK_CPU_M0APP 0x490
+#define CLK_CPU_ADCHS 0x498
+#define CLK_CPU_EEPROM 0x4a0
+#define CLK_CPU_WWDT 0x500
+#define CLK_CPU_UART0 0x508
+#define CLK_CPU_UART1 0x510
+#define CLK_CPU_SSP0 0x518
+#define CLK_CPU_TIMER0 0x520
+#define CLK_CPU_TIMER1 0x528
+#define CLK_CPU_SCU 0x530
+#define CLK_CPU_CREG 0x538
+#define CLK_CPU_RITIMER 0x600
+#define CLK_CPU_UART2 0x608
+#define CLK_CPU_UART3 0x610
+#define CLK_CPU_TIMER2 0x618
+#define CLK_CPU_TIMER3 0x620
+#define CLK_CPU_SSP1 0x628
+#define CLK_CPU_QEI 0x630
+#define CLK_PERIPH_BUS 0x700
+#define CLK_PERIPH_CORE 0x710
+#define CLK_PERIPH_SGPIO 0x718
+#define CLK_USB0 0x800
+#define CLK_USB1 0x900
+#define CLK_SPI 0xA00
+#define CLK_ADCHS 0xB00
+
+/* Clock Control Unit 2 (CCU2) clock offsets */
+#define CLK_AUDIO 0x100
+#define CLK_APB2_UART3 0x200
+#define CLK_APB2_UART2 0x300
+#define CLK_APB0_UART1 0x400
+#define CLK_APB0_UART0 0x500
+#define CLK_APB2_SSP1 0x600
+#define CLK_APB0_SSP0 0x700
+#define CLK_SDIO 0x800
--
1.8.0
^ permalink raw reply related [flat|nested] 30+ messages in thread
* [PATCH v4 3/5] clk: add lpc18xx ccu clk driver
@ 2015-05-28 20:31 ` Joachim Eastwood
0 siblings, 0 replies; 30+ messages in thread
From: Joachim Eastwood @ 2015-05-28 20:31 UTC (permalink / raw)
To: linux-arm-kernel
Add driver for NXP LPC18xx/43xx Clock Control Unit (CCU). The CCU
provides fine grained gating of most clocks present in the SoC.
Signed-off-by: Joachim Eastwood <manabian@gmail.com>
---
drivers/clk/nxp/Makefile | 1 +
drivers/clk/nxp/clk-lpc18xx-ccu.c | 293 ++++++++++++++++++++++++++++++++
include/dt-bindings/clock/lpc18xx-ccu.h | 74 ++++++++
3 files changed, 368 insertions(+)
create mode 100644 drivers/clk/nxp/clk-lpc18xx-ccu.c
create mode 100644 include/dt-bindings/clock/lpc18xx-ccu.h
diff --git a/drivers/clk/nxp/Makefile b/drivers/clk/nxp/Makefile
index aca9d3e4f7fe..7f608b0ad7b4 100644
--- a/drivers/clk/nxp/Makefile
+++ b/drivers/clk/nxp/Makefile
@@ -1 +1,2 @@
obj-$(CONFIG_ARCH_LPC18XX) += clk-lpc18xx-cgu.o
+obj-$(CONFIG_ARCH_LPC18XX) += clk-lpc18xx-ccu.o
diff --git a/drivers/clk/nxp/clk-lpc18xx-ccu.c b/drivers/clk/nxp/clk-lpc18xx-ccu.c
new file mode 100644
index 000000000000..eeaee97da110
--- /dev/null
+++ b/drivers/clk/nxp/clk-lpc18xx-ccu.c
@@ -0,0 +1,293 @@
+/*
+ * Clk driver for NXP LPC18xx/LPC43xx Clock Control Unit (CCU)
+ *
+ * Copyright (C) 2015 Joachim Eastwood <manabian@gmail.com>
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2. This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+#include <linux/clk.h>
+#include <linux/clk-provider.h>
+#include <linux/kernel.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/slab.h>
+#include <linux/string.h>
+
+#include <dt-bindings/clock/lpc18xx-ccu.h>
+
+/* Bit defines for CCU branch configuration register */
+#define LPC18XX_CCU_RUN BIT(0)
+#define LPC18XX_CCU_AUTO BIT(1)
+#define LPC18XX_CCU_DIV BIT(5)
+#define LPC18XX_CCU_DIVSTAT BIT(27)
+
+/* CCU branch feature bits */
+#define CCU_BRANCH_IS_BUS BIT(0)
+#define CCU_BRANCH_HAVE_DIV2 BIT(1)
+
+#define to_clk_gate(_hw) container_of(_hw, struct clk_gate, hw)
+
+struct lpc18xx_branch_clk_data {
+ const char **name;
+ int num;
+};
+
+struct lpc18xx_clk_branch {
+ const char *base_name;
+ const char *name;
+ u16 offset;
+ u16 flags;
+ struct clk *clk;
+ struct clk_gate gate;
+};
+
+static struct lpc18xx_clk_branch clk_branches[] = {
+ {"base_apb3_clk", "apb3_bus", CLK_APB3_BUS, CCU_BRANCH_IS_BUS},
+ {"base_apb3_clk", "apb3_i2c1", CLK_APB3_I2C1, 0},
+ {"base_apb3_clk", "apb3_dac", CLK_APB3_DAC, 0},
+ {"base_apb3_clk", "apb3_adc0", CLK_APB3_ADC0, 0},
+ {"base_apb3_clk", "apb3_adc1", CLK_APB3_ADC1, 0},
+ {"base_apb3_clk", "apb3_can0", CLK_APB3_CAN0, 0},
+
+ {"base_apb1_clk", "apb1_bus", CLK_APB1_BUS, CCU_BRANCH_IS_BUS},
+ {"base_apb1_clk", "apb1_mc_pwm", CLK_APB1_MOTOCON_PWM, 0},
+ {"base_apb1_clk", "apb1_i2c0", CLK_APB1_I2C0, 0},
+ {"base_apb1_clk", "apb1_i2s", CLK_APB1_I2S, 0},
+ {"base_apb1_clk", "apb1_can1", CLK_APB1_CAN1, 0},
+
+ {"base_spifi_clk", "spifi", CLK_SPIFI, 0},
+
+ {"base_cpu_clk", "cpu_bus", CLK_CPU_BUS, CCU_BRANCH_IS_BUS},
+ {"base_cpu_clk", "cpu_spifi", CLK_CPU_SPIFI, 0},
+ {"base_cpu_clk", "cpu_gpio", CLK_CPU_GPIO, 0},
+ {"base_cpu_clk", "cpu_lcd", CLK_CPU_LCD, 0},
+ {"base_cpu_clk", "cpu_ethernet", CLK_CPU_ETHERNET, 0},
+ {"base_cpu_clk", "cpu_usb0", CLK_CPU_USB0, 0},
+ {"base_cpu_clk", "cpu_emc", CLK_CPU_EMC, 0},
+ {"base_cpu_clk", "cpu_sdio", CLK_CPU_SDIO, 0},
+ {"base_cpu_clk", "cpu_dma", CLK_CPU_DMA, 0},
+ {"base_cpu_clk", "cpu_core", CLK_CPU_CORE, 0},
+ {"base_cpu_clk", "cpu_sct", CLK_CPU_SCT, 0},
+ {"base_cpu_clk", "cpu_usb1", CLK_CPU_USB1, 0},
+ {"base_cpu_clk", "cpu_emcdiv", CLK_CPU_EMCDIV, CCU_BRANCH_HAVE_DIV2},
+ {"base_cpu_clk", "cpu_flasha", CLK_CPU_FLASHA, CCU_BRANCH_HAVE_DIV2},
+ {"base_cpu_clk", "cpu_flashb", CLK_CPU_FLASHB, CCU_BRANCH_HAVE_DIV2},
+ {"base_cpu_clk", "cpu_m0app", CLK_CPU_M0APP, CCU_BRANCH_HAVE_DIV2},
+ {"base_cpu_clk", "cpu_adchs", CLK_CPU_ADCHS, CCU_BRANCH_HAVE_DIV2},
+ {"base_cpu_clk", "cpu_eeprom", CLK_CPU_EEPROM, CCU_BRANCH_HAVE_DIV2},
+ {"base_cpu_clk", "cpu_wwdt", CLK_CPU_WWDT, 0},
+ {"base_cpu_clk", "cpu_uart0", CLK_CPU_UART0, 0},
+ {"base_cpu_clk", "cpu_uart1", CLK_CPU_UART1, 0},
+ {"base_cpu_clk", "cpu_ssp0", CLK_CPU_SSP0, 0},
+ {"base_cpu_clk", "cpu_timer0", CLK_CPU_TIMER0, 0},
+ {"base_cpu_clk", "cpu_timer1", CLK_CPU_TIMER1, 0},
+ {"base_cpu_clk", "cpu_scu", CLK_CPU_SCU, 0},
+ {"base_cpu_clk", "cpu_creg", CLK_CPU_CREG, 0},
+ {"base_cpu_clk", "cpu_ritimer", CLK_CPU_RITIMER, 0},
+ {"base_cpu_clk", "cpu_uart2", CLK_CPU_UART2, 0},
+ {"base_cpu_clk", "cpu_uart3", CLK_CPU_UART3, 0},
+ {"base_cpu_clk", "cpu_timer2", CLK_CPU_TIMER2, 0},
+ {"base_cpu_clk", "cpu_timer3", CLK_CPU_TIMER3, 0},
+ {"base_cpu_clk", "cpu_ssp1", CLK_CPU_SSP1, 0},
+ {"base_cpu_clk", "cpu_qei", CLK_CPU_QEI, 0},
+
+ {"base_periph_clk", "periph_bus", CLK_PERIPH_BUS, CCU_BRANCH_IS_BUS},
+ {"base_periph_clk", "periph_core", CLK_PERIPH_CORE, 0},
+ {"base_periph_clk", "periph_sgpio", CLK_PERIPH_SGPIO, 0},
+
+ {"base_usb0_clk", "usb0", CLK_USB0, 0},
+ {"base_usb1_clk", "usb1", CLK_USB1, 0},
+ {"base_spi_clk", "spi", CLK_SPI, 0},
+ {"base_adchs_clk", "adchs", CLK_ADCHS, 0},
+
+ {"base_audio_clk", "audio", CLK_AUDIO, 0},
+ {"base_uart3_clk", "apb2_uart3", CLK_APB2_UART3, 0},
+ {"base_uart2_clk", "apb2_uart2", CLK_APB2_UART2, 0},
+ {"base_uart1_clk", "apb0_uart1", CLK_APB0_UART1, 0},
+ {"base_uart0_clk", "apb0_uart0", CLK_APB0_UART0, 0},
+ {"base_ssp1_clk", "apb2_ssp1", CLK_APB2_SSP1, 0},
+ {"base_ssp0_clk", "apb0_ssp0", CLK_APB0_SSP0, 0},
+ {"base_sdio_clk", "sdio", CLK_SDIO, 0},
+};
+
+static struct clk *lpc18xx_ccu_branch_clk_get(struct of_phandle_args *clkspec,
+ void *data)
+{
+ struct lpc18xx_branch_clk_data *clk_data = data;
+ unsigned int offset = clkspec->args[0];
+ int i, j;
+
+ for (i = 0; i < ARRAY_SIZE(clk_branches); i++) {
+ if (clk_branches[i].offset != offset)
+ continue;
+
+ for (j = 0; j < clk_data->num; j++) {
+ if (!strcmp(clk_branches[i].base_name, clk_data->name[j]))
+ return clk_branches[i].clk;
+ }
+ }
+
+ pr_err("%s: invalid clock offset %d\n", __func__, offset);
+
+ return ERR_PTR(-EINVAL);
+}
+
+static int lpc18xx_ccu_gate_endisable(struct clk_hw *hw, bool enable)
+{
+ struct clk_gate *gate = to_clk_gate(hw);
+ u32 val;
+
+ /*
+ * Divider field is write only, so divider stat field must
+ * be read so divider field can be set accordingly.
+ */
+ val = clk_readl(gate->reg);
+ if (val & LPC18XX_CCU_DIVSTAT)
+ val |= LPC18XX_CCU_DIV;
+
+ if (enable) {
+ val |= LPC18XX_CCU_RUN;
+ } else {
+ /*
+ * To safely disable a branch clock a squence of two separate
+ * writes must be used. First write should set the AUTO bit
+ * and the next write should clear the RUN bit.
+ */
+ val |= LPC18XX_CCU_AUTO;
+ clk_writel(val, gate->reg);
+
+ val &= ~LPC18XX_CCU_RUN;
+ }
+
+ clk_writel(val, gate->reg);
+
+ return 0;
+}
+
+static int lpc18xx_ccu_gate_enable(struct clk_hw *hw)
+{
+ return lpc18xx_ccu_gate_endisable(hw, true);
+}
+
+static void lpc18xx_ccu_gate_disable(struct clk_hw *hw)
+{
+ lpc18xx_ccu_gate_endisable(hw, false);
+}
+
+static int lpc18xx_ccu_gate_is_enabled(struct clk_hw *hw)
+{
+ struct clk_gate *gate = to_clk_gate(hw);
+
+ return clk_readl(gate->reg) & LPC18XX_CCU_RUN;
+}
+
+static const struct clk_ops lpc18xx_ccu_gate_ops = {
+ .enable = lpc18xx_ccu_gate_enable,
+ .disable = lpc18xx_ccu_gate_disable,
+ .is_enabled = lpc18xx_ccu_gate_is_enabled,
+};
+
+static void lpc18xx_ccu_register_branch_gate_div(struct lpc18xx_clk_branch *branch,
+ void __iomem *reg_base,
+ const char *parent)
+{
+ const struct clk_ops *div_ops = NULL;
+ struct clk_divider *div = NULL;
+ struct clk_hw *div_hw = NULL;
+
+ if (branch->flags & CCU_BRANCH_HAVE_DIV2) {
+ div = kzalloc(sizeof(*div), GFP_KERNEL);
+ if (!div)
+ return;
+
+ div->reg = branch->offset + reg_base;
+ div->flags = CLK_DIVIDER_READ_ONLY;
+ div->shift = 27;
+ div->width = 1;
+
+ div_hw = &div->hw;
+ div_ops = &clk_divider_ops;
+ }
+
+ branch->gate.reg = branch->offset + reg_base;
+ branch->gate.bit_idx = 0;
+
+ branch->clk = clk_register_composite(NULL, branch->name, &parent, 1,
+ NULL, NULL,
+ div_hw, div_ops,
+ &branch->gate.hw, &lpc18xx_ccu_gate_ops, 0);
+ if (IS_ERR(branch->clk)) {
+ kfree(div);
+ pr_warn("%s: failed to register %s\n", __func__, branch->name);
+ return;
+ }
+
+ /* Grab essential branch clocks for CPU and SDRAM */
+ switch (branch->offset) {
+ case CLK_CPU_EMC:
+ case CLK_CPU_CORE:
+ case CLK_CPU_CREG:
+ case CLK_CPU_EMCDIV:
+ clk_prepare_enable(branch->clk);
+ }
+}
+
+static void lpc18xx_ccu_register_branch_clks(void __iomem *reg_base,
+ const char *base_name)
+{
+ const char *parent = base_name;
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(clk_branches); i++) {
+ if (strcmp(clk_branches[i].base_name, base_name))
+ continue;
+
+ lpc18xx_ccu_register_branch_gate_div(&clk_branches[i], reg_base,
+ parent);
+
+ if (clk_branches[i].flags & CCU_BRANCH_IS_BUS)
+ parent = clk_branches[i].name;
+ }
+}
+
+static void __init lpc18xx_ccu_init(struct device_node *np)
+{
+ struct lpc18xx_branch_clk_data *clk_data;
+ void __iomem *reg_base;
+ int i, ret;
+
+ reg_base = of_iomap(np, 0);
+ if (!reg_base) {
+ pr_warn("%s: failed to map address range\n", __func__);
+ return;
+ }
+
+ clk_data = kzalloc(sizeof(*clk_data), GFP_KERNEL);
+ if (!clk_data)
+ return;
+
+ clk_data->num = of_property_count_strings(np, "clock-names");
+ clk_data->name = kcalloc(clk_data->num, sizeof(char *), GFP_KERNEL);
+ if (!clk_data->name) {
+ kfree(clk_data);
+ return;
+ }
+
+ for (i = 0; i < clk_data->num; i++) {
+ ret = of_property_read_string_index(np, "clock-names", i,
+ &clk_data->name[i]);
+ if (ret) {
+ pr_warn("%s: failed to get clock name at idx %d\n",
+ __func__, i);
+ continue;
+ }
+
+ lpc18xx_ccu_register_branch_clks(reg_base, clk_data->name[i]);
+ }
+
+ of_clk_add_provider(np, lpc18xx_ccu_branch_clk_get, clk_data);
+}
+CLK_OF_DECLARE(lpc18xx_ccu, "nxp,lpc1850-ccu", lpc18xx_ccu_init);
diff --git a/include/dt-bindings/clock/lpc18xx-ccu.h b/include/dt-bindings/clock/lpc18xx-ccu.h
new file mode 100644
index 000000000000..bbfe00b6ab7d
--- /dev/null
+++ b/include/dt-bindings/clock/lpc18xx-ccu.h
@@ -0,0 +1,74 @@
+/*
+ * Copyright (c) 2015 Joachim Eastwood <manabian@gmail.com>
+ *
+ * This code is released using a dual license strategy: BSD/GPL
+ * You can choose the licence that better fits your requirements.
+ *
+ * Released under the terms of 3-clause BSD License
+ * Released under the terms of GNU General Public License Version 2.0
+ *
+ */
+
+/* Clock Control Unit 1 (CCU1) clock offsets */
+#define CLK_APB3_BUS 0x100
+#define CLK_APB3_I2C1 0x108
+#define CLK_APB3_DAC 0x110
+#define CLK_APB3_ADC0 0x118
+#define CLK_APB3_ADC1 0x120
+#define CLK_APB3_CAN0 0x128
+#define CLK_APB1_BUS 0x200
+#define CLK_APB1_MOTOCON_PWM 0x208
+#define CLK_APB1_I2C0 0x210
+#define CLK_APB1_I2S 0x218
+#define CLK_APB1_CAN1 0x220
+#define CLK_SPIFI 0x300
+#define CLK_CPU_BUS 0x400
+#define CLK_CPU_SPIFI 0x408
+#define CLK_CPU_GPIO 0x410
+#define CLK_CPU_LCD 0x418
+#define CLK_CPU_ETHERNET 0x420
+#define CLK_CPU_USB0 0x428
+#define CLK_CPU_EMC 0x430
+#define CLK_CPU_SDIO 0x438
+#define CLK_CPU_DMA 0x440
+#define CLK_CPU_CORE 0x448
+#define CLK_CPU_SCT 0x468
+#define CLK_CPU_USB1 0x470
+#define CLK_CPU_EMCDIV 0x478
+#define CLK_CPU_FLASHA 0x480
+#define CLK_CPU_FLASHB 0x488
+#define CLK_CPU_M0APP 0x490
+#define CLK_CPU_ADCHS 0x498
+#define CLK_CPU_EEPROM 0x4a0
+#define CLK_CPU_WWDT 0x500
+#define CLK_CPU_UART0 0x508
+#define CLK_CPU_UART1 0x510
+#define CLK_CPU_SSP0 0x518
+#define CLK_CPU_TIMER0 0x520
+#define CLK_CPU_TIMER1 0x528
+#define CLK_CPU_SCU 0x530
+#define CLK_CPU_CREG 0x538
+#define CLK_CPU_RITIMER 0x600
+#define CLK_CPU_UART2 0x608
+#define CLK_CPU_UART3 0x610
+#define CLK_CPU_TIMER2 0x618
+#define CLK_CPU_TIMER3 0x620
+#define CLK_CPU_SSP1 0x628
+#define CLK_CPU_QEI 0x630
+#define CLK_PERIPH_BUS 0x700
+#define CLK_PERIPH_CORE 0x710
+#define CLK_PERIPH_SGPIO 0x718
+#define CLK_USB0 0x800
+#define CLK_USB1 0x900
+#define CLK_SPI 0xA00
+#define CLK_ADCHS 0xB00
+
+/* Clock Control Unit 2 (CCU2) clock offsets */
+#define CLK_AUDIO 0x100
+#define CLK_APB2_UART3 0x200
+#define CLK_APB2_UART2 0x300
+#define CLK_APB0_UART1 0x400
+#define CLK_APB0_UART0 0x500
+#define CLK_APB2_SSP1 0x600
+#define CLK_APB0_SSP0 0x700
+#define CLK_SDIO 0x800
--
1.8.0
^ permalink raw reply related [flat|nested] 30+ messages in thread
* [PATCH v4 4/5] doc: dt: add documentation for lpc1850-ccu clk driver
2015-05-28 20:31 ` Joachim Eastwood
(?)
@ 2015-05-28 20:31 ` Joachim Eastwood
-1 siblings, 0 replies; 30+ messages in thread
From: Joachim Eastwood @ 2015-05-28 20:31 UTC (permalink / raw)
To: mturquette-QSEj5FYQhm4dnm+yROfE0A, sboyd-sgV2jX0FEOL9JmXXK+q4OQ
Cc: Joachim Eastwood, linux-clk-u79uwXL29TY76Z2rM5mHXA,
devicetree-u79uwXL29TY76Z2rM5mHXA,
linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r
Add DT binding documentation for lpc1850-ccu clk driver.
Signed-off-by: Joachim Eastwood <manabian-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
---
.../devicetree/bindings/clock/lpc1850-ccu.txt | 77 ++++++++++++++++++++++
1 file changed, 77 insertions(+)
create mode 100644 Documentation/devicetree/bindings/clock/lpc1850-ccu.txt
diff --git a/Documentation/devicetree/bindings/clock/lpc1850-ccu.txt b/Documentation/devicetree/bindings/clock/lpc1850-ccu.txt
new file mode 100644
index 000000000000..fa97c12014ac
--- /dev/null
+++ b/Documentation/devicetree/bindings/clock/lpc1850-ccu.txt
@@ -0,0 +1,77 @@
+* NXP LPC1850 Clock Control Unit (CCU)
+
+Each CGU base clock has several clock branches which can be turned on
+or off independently by the Clock Control Units CCU1 or CCU2. The
+branch clocks are distributed between CCU1 and CCU2.
+
+ - Above text taken from NXP LPC1850 User Manual.
+
+This binding uses the common clock binding:
+ Documentation/devicetree/bindings/clock/clock-bindings.txt
+
+Required properties:
+- compatible:
+ Should be "nxp,lpc1850-ccu"
+- reg:
+ Shall define the base and range of the address space
+ containing clock control registers
+- #clock-cells:
+ Shall have value <1>. The permitted clock-specifier values
+ are the branch clock names defined in table below.
+- clocks:
+ Shall contain a list of phandles for the base clocks routed
+ from the CGU to the specific CCU. See mapping of base clocks
+ and CCU in table below.
+- clock-names:
+ Shall contain a list of names for the base clock routed
+ from the CGU to the specific CCU. Valid CCU clock names:
+ "base_usb0_clk", "base_periph_clk", "base_usb1_clk",
+ "base_cpu_clk", "base_spifi_clk", "base_spi_clk",
+ "base_apb1_clk", "base_apb3_clk", "base_adchs_clk",
+ "base_sdio_clk", "base_ssp0_clk", "base_ssp1_clk",
+ "base_uart0_clk", "base_uart1_clk", "base_uart2_clk",
+ "base_uart3_clk", "base_audio_clk"
+
+Which branch clocks that are available on the CCU depends on the
+specific LPC part. Check the user manual for your specific part.
+
+A list of CCU clocks can be found in dt-bindings/clock/lpc18xx-ccu.h.
+
+Example board file:
+
+soc {
+ ccu1: clock-controller@40051000 {
+ compatible = "nxp,lpc1850-ccu";
+ reg = <0x40051000 0x1000>;
+ #clock-cells = <1>;
+ clocks = <&cgu BASE_APB3_CLK>, <&cgu BASE_APB1_CLK>,
+ <&cgu BASE_SPIFI_CLK>, <&cgu BASE_CPU_CLK>,
+ <&cgu BASE_PERIPH_CLK>, <&cgu BASE_USB0_CLK>,
+ <&cgu BASE_USB1_CLK>, <&cgu BASE_SPI_CLK>;
+ clock-names = "base_apb3_clk", "base_apb1_clk",
+ "base_spifi_clk", "base_cpu_clk",
+ "base_periph_clk", "base_usb0_clk",
+ "base_usb1_clk", "base_spi_clk";
+ };
+
+ ccu2: clock-controller@40052000 {
+ compatible = "nxp,lpc1850-ccu";
+ reg = <0x40052000 0x1000>;
+ #clock-cells = <1>;
+ clocks = <&cgu BASE_AUDIO_CLK>, <&cgu BASE_UART3_CLK>,
+ <&cgu BASE_UART2_CLK>, <&cgu BASE_UART1_CLK>,
+ <&cgu BASE_UART0_CLK>, <&cgu BASE_SSP1_CLK>,
+ <&cgu BASE_SSP0_CLK>, <&cgu BASE_SDIO_CLK>;
+ clock-names = "base_audio_clk", "base_uart3_clk",
+ "base_uart2_clk", "base_uart1_clk",
+ "base_uart0_clk", "base_ssp1_clk",
+ "base_ssp0_clk", "base_sdio_clk";
+ };
+
+ /* A user of CCU brach clocks */
+ uart1: serial@40082000 {
+ ...
+ clocks = <&ccu2 CLK_APB0_UART1>, <&ccu1 CLK_CPU_UART1>;
+ ...
+ };
+};
--
1.8.0
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply related [flat|nested] 30+ messages in thread
* [PATCH v4 4/5] doc: dt: add documentation for lpc1850-ccu clk driver
@ 2015-05-28 20:31 ` Joachim Eastwood
0 siblings, 0 replies; 30+ messages in thread
From: Joachim Eastwood @ 2015-05-28 20:31 UTC (permalink / raw)
To: mturquette, sboyd
Cc: Joachim Eastwood, linux-clk, devicetree, linux-arm-kernel
Add DT binding documentation for lpc1850-ccu clk driver.
Signed-off-by: Joachim Eastwood <manabian@gmail.com>
---
.../devicetree/bindings/clock/lpc1850-ccu.txt | 77 ++++++++++++++++++++++
1 file changed, 77 insertions(+)
create mode 100644 Documentation/devicetree/bindings/clock/lpc1850-ccu.txt
diff --git a/Documentation/devicetree/bindings/clock/lpc1850-ccu.txt b/Documentation/devicetree/bindings/clock/lpc1850-ccu.txt
new file mode 100644
index 000000000000..fa97c12014ac
--- /dev/null
+++ b/Documentation/devicetree/bindings/clock/lpc1850-ccu.txt
@@ -0,0 +1,77 @@
+* NXP LPC1850 Clock Control Unit (CCU)
+
+Each CGU base clock has several clock branches which can be turned on
+or off independently by the Clock Control Units CCU1 or CCU2. The
+branch clocks are distributed between CCU1 and CCU2.
+
+ - Above text taken from NXP LPC1850 User Manual.
+
+This binding uses the common clock binding:
+ Documentation/devicetree/bindings/clock/clock-bindings.txt
+
+Required properties:
+- compatible:
+ Should be "nxp,lpc1850-ccu"
+- reg:
+ Shall define the base and range of the address space
+ containing clock control registers
+- #clock-cells:
+ Shall have value <1>. The permitted clock-specifier values
+ are the branch clock names defined in table below.
+- clocks:
+ Shall contain a list of phandles for the base clocks routed
+ from the CGU to the specific CCU. See mapping of base clocks
+ and CCU in table below.
+- clock-names:
+ Shall contain a list of names for the base clock routed
+ from the CGU to the specific CCU. Valid CCU clock names:
+ "base_usb0_clk", "base_periph_clk", "base_usb1_clk",
+ "base_cpu_clk", "base_spifi_clk", "base_spi_clk",
+ "base_apb1_clk", "base_apb3_clk", "base_adchs_clk",
+ "base_sdio_clk", "base_ssp0_clk", "base_ssp1_clk",
+ "base_uart0_clk", "base_uart1_clk", "base_uart2_clk",
+ "base_uart3_clk", "base_audio_clk"
+
+Which branch clocks that are available on the CCU depends on the
+specific LPC part. Check the user manual for your specific part.
+
+A list of CCU clocks can be found in dt-bindings/clock/lpc18xx-ccu.h.
+
+Example board file:
+
+soc {
+ ccu1: clock-controller@40051000 {
+ compatible = "nxp,lpc1850-ccu";
+ reg = <0x40051000 0x1000>;
+ #clock-cells = <1>;
+ clocks = <&cgu BASE_APB3_CLK>, <&cgu BASE_APB1_CLK>,
+ <&cgu BASE_SPIFI_CLK>, <&cgu BASE_CPU_CLK>,
+ <&cgu BASE_PERIPH_CLK>, <&cgu BASE_USB0_CLK>,
+ <&cgu BASE_USB1_CLK>, <&cgu BASE_SPI_CLK>;
+ clock-names = "base_apb3_clk", "base_apb1_clk",
+ "base_spifi_clk", "base_cpu_clk",
+ "base_periph_clk", "base_usb0_clk",
+ "base_usb1_clk", "base_spi_clk";
+ };
+
+ ccu2: clock-controller@40052000 {
+ compatible = "nxp,lpc1850-ccu";
+ reg = <0x40052000 0x1000>;
+ #clock-cells = <1>;
+ clocks = <&cgu BASE_AUDIO_CLK>, <&cgu BASE_UART3_CLK>,
+ <&cgu BASE_UART2_CLK>, <&cgu BASE_UART1_CLK>,
+ <&cgu BASE_UART0_CLK>, <&cgu BASE_SSP1_CLK>,
+ <&cgu BASE_SSP0_CLK>, <&cgu BASE_SDIO_CLK>;
+ clock-names = "base_audio_clk", "base_uart3_clk",
+ "base_uart2_clk", "base_uart1_clk",
+ "base_uart0_clk", "base_ssp1_clk",
+ "base_ssp0_clk", "base_sdio_clk";
+ };
+
+ /* A user of CCU brach clocks */
+ uart1: serial@40082000 {
+ ...
+ clocks = <&ccu2 CLK_APB0_UART1>, <&ccu1 CLK_CPU_UART1>;
+ ...
+ };
+};
--
1.8.0
^ permalink raw reply related [flat|nested] 30+ messages in thread
* [PATCH v4 4/5] doc: dt: add documentation for lpc1850-ccu clk driver
@ 2015-05-28 20:31 ` Joachim Eastwood
0 siblings, 0 replies; 30+ messages in thread
From: Joachim Eastwood @ 2015-05-28 20:31 UTC (permalink / raw)
To: linux-arm-kernel
Add DT binding documentation for lpc1850-ccu clk driver.
Signed-off-by: Joachim Eastwood <manabian@gmail.com>
---
.../devicetree/bindings/clock/lpc1850-ccu.txt | 77 ++++++++++++++++++++++
1 file changed, 77 insertions(+)
create mode 100644 Documentation/devicetree/bindings/clock/lpc1850-ccu.txt
diff --git a/Documentation/devicetree/bindings/clock/lpc1850-ccu.txt b/Documentation/devicetree/bindings/clock/lpc1850-ccu.txt
new file mode 100644
index 000000000000..fa97c12014ac
--- /dev/null
+++ b/Documentation/devicetree/bindings/clock/lpc1850-ccu.txt
@@ -0,0 +1,77 @@
+* NXP LPC1850 Clock Control Unit (CCU)
+
+Each CGU base clock has several clock branches which can be turned on
+or off independently by the Clock Control Units CCU1 or CCU2. The
+branch clocks are distributed between CCU1 and CCU2.
+
+ - Above text taken from NXP LPC1850 User Manual.
+
+This binding uses the common clock binding:
+ Documentation/devicetree/bindings/clock/clock-bindings.txt
+
+Required properties:
+- compatible:
+ Should be "nxp,lpc1850-ccu"
+- reg:
+ Shall define the base and range of the address space
+ containing clock control registers
+- #clock-cells:
+ Shall have value <1>. The permitted clock-specifier values
+ are the branch clock names defined in table below.
+- clocks:
+ Shall contain a list of phandles for the base clocks routed
+ from the CGU to the specific CCU. See mapping of base clocks
+ and CCU in table below.
+- clock-names:
+ Shall contain a list of names for the base clock routed
+ from the CGU to the specific CCU. Valid CCU clock names:
+ "base_usb0_clk", "base_periph_clk", "base_usb1_clk",
+ "base_cpu_clk", "base_spifi_clk", "base_spi_clk",
+ "base_apb1_clk", "base_apb3_clk", "base_adchs_clk",
+ "base_sdio_clk", "base_ssp0_clk", "base_ssp1_clk",
+ "base_uart0_clk", "base_uart1_clk", "base_uart2_clk",
+ "base_uart3_clk", "base_audio_clk"
+
+Which branch clocks that are available on the CCU depends on the
+specific LPC part. Check the user manual for your specific part.
+
+A list of CCU clocks can be found in dt-bindings/clock/lpc18xx-ccu.h.
+
+Example board file:
+
+soc {
+ ccu1: clock-controller at 40051000 {
+ compatible = "nxp,lpc1850-ccu";
+ reg = <0x40051000 0x1000>;
+ #clock-cells = <1>;
+ clocks = <&cgu BASE_APB3_CLK>, <&cgu BASE_APB1_CLK>,
+ <&cgu BASE_SPIFI_CLK>, <&cgu BASE_CPU_CLK>,
+ <&cgu BASE_PERIPH_CLK>, <&cgu BASE_USB0_CLK>,
+ <&cgu BASE_USB1_CLK>, <&cgu BASE_SPI_CLK>;
+ clock-names = "base_apb3_clk", "base_apb1_clk",
+ "base_spifi_clk", "base_cpu_clk",
+ "base_periph_clk", "base_usb0_clk",
+ "base_usb1_clk", "base_spi_clk";
+ };
+
+ ccu2: clock-controller at 40052000 {
+ compatible = "nxp,lpc1850-ccu";
+ reg = <0x40052000 0x1000>;
+ #clock-cells = <1>;
+ clocks = <&cgu BASE_AUDIO_CLK>, <&cgu BASE_UART3_CLK>,
+ <&cgu BASE_UART2_CLK>, <&cgu BASE_UART1_CLK>,
+ <&cgu BASE_UART0_CLK>, <&cgu BASE_SSP1_CLK>,
+ <&cgu BASE_SSP0_CLK>, <&cgu BASE_SDIO_CLK>;
+ clock-names = "base_audio_clk", "base_uart3_clk",
+ "base_uart2_clk", "base_uart1_clk",
+ "base_uart0_clk", "base_ssp1_clk",
+ "base_ssp0_clk", "base_sdio_clk";
+ };
+
+ /* A user of CCU brach clocks */
+ uart1: serial at 40082000 {
+ ...
+ clocks = <&ccu2 CLK_APB0_UART1>, <&ccu1 CLK_CPU_UART1>;
+ ...
+ };
+};
--
1.8.0
^ permalink raw reply related [flat|nested] 30+ messages in thread
* [PATCH v4 5/5] ARM: dts: lpc18xx: add clock nodes for cgu and ccu
2015-05-28 20:31 ` Joachim Eastwood
(?)
@ 2015-05-28 20:31 ` Joachim Eastwood
-1 siblings, 0 replies; 30+ messages in thread
From: Joachim Eastwood @ 2015-05-28 20:31 UTC (permalink / raw)
To: mturquette-QSEj5FYQhm4dnm+yROfE0A, sboyd-sgV2jX0FEOL9JmXXK+q4OQ
Cc: Joachim Eastwood, linux-clk-u79uwXL29TY76Z2rM5mHXA,
devicetree-u79uwXL29TY76Z2rM5mHXA,
linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r
Signed-off-by: Joachim Eastwood <manabian-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
---
arch/arm/boot/dts/lpc18xx.dtsi | 85 ++++++++++++++++++++++++++------
arch/arm/boot/dts/lpc4350-hitex-eval.dts | 4 --
2 files changed, 71 insertions(+), 18 deletions(-)
diff --git a/arch/arm/boot/dts/lpc18xx.dtsi b/arch/arm/boot/dts/lpc18xx.dtsi
index 204da5b52ef9..78292d0cb263 100644
--- a/arch/arm/boot/dts/lpc18xx.dtsi
+++ b/arch/arm/boot/dts/lpc18xx.dtsi
@@ -13,6 +13,9 @@
#include "armv7-m.dtsi"
+#include "dt-bindings/clock/lpc18xx-cgu.h"
+#include "dt-bindings/clock/lpc18xx-ccu.h"
+
/ {
cpus {
#address-cells = <1>;
@@ -22,6 +25,7 @@
compatible = "arm,cortex-m3";
device_type = "cpu";
reg = <0x0>;
+ clocks = <&ccu1 CLK_CPU_CORE>;
};
};
@@ -32,23 +36,76 @@
clock-frequency = <12000000>;
};
- /* Temporary hardcode PLL1 until clk drivers are merged */
- pll1: pll1 {
- compatible = "fixed-factor-clock";
- clocks = <&xtal>;
+ xtal32: xtal32 {
+ compatible = "fixed-clock";
+ #clock-cells = <0>;
+ clock-frequency = <32768>;
+ };
+
+ enet_rx_clk: enet_rx_clk {
+ compatible = "fixed-clock";
+ #clock-cells = <0>;
+ clock-frequency = <0>;
+ clock-output-names = "enet_rx_clk";
+ };
+
+ enet_tx_clk: enet_tx_clk {
+ compatible = "fixed-clock";
+ #clock-cells = <0>;
+ clock-frequency = <0>;
+ clock-output-names = "enet_tx_clk";
+ };
+
+ gp_clkin: gp_clkin {
+ compatible = "fixed-clock";
#clock-cells = <0>;
- clock-div = <1>;
- clock-mult = <12>;
+ clock-frequency = <0>;
+ clock-output-names = "gp_clkin";
};
};
soc {
+ cgu: clock-controller@40050000 {
+ compatible = "nxp,lpc1850-cgu";
+ reg = <0x40050000 0x1000>;
+ #clock-cells = <1>;
+ clocks = <&xtal>, <&xtal32>, <&enet_rx_clk>, <&enet_tx_clk>, <&gp_clkin>;
+ };
+
+ ccu1: clock-controller@40051000 {
+ compatible = "nxp,lpc1850-ccu";
+ reg = <0x40051000 0x1000>;
+ #clock-cells = <1>;
+ clocks = <&cgu BASE_APB3_CLK>, <&cgu BASE_APB1_CLK>,
+ <&cgu BASE_SPIFI_CLK>, <&cgu BASE_CPU_CLK>,
+ <&cgu BASE_PERIPH_CLK>, <&cgu BASE_USB0_CLK>,
+ <&cgu BASE_USB1_CLK>, <&cgu BASE_SPI_CLK>;
+ clock-names = "base_apb3_clk", "base_apb1_clk",
+ "base_spifi_clk", "base_cpu_clk",
+ "base_periph_clk", "base_usb0_clk",
+ "base_usb1_clk", "base_spi_clk";
+ };
+
+ ccu2: clock-controller@40052000 {
+ compatible = "nxp,lpc1850-ccu";
+ reg = <0x40052000 0x1000>;
+ #clock-cells = <1>;
+ clocks = <&cgu BASE_AUDIO_CLK>, <&cgu BASE_UART3_CLK>,
+ <&cgu BASE_UART2_CLK>, <&cgu BASE_UART1_CLK>,
+ <&cgu BASE_UART0_CLK>, <&cgu BASE_SSP1_CLK>,
+ <&cgu BASE_SSP0_CLK>, <&cgu BASE_SDIO_CLK>;
+ clock-names = "base_audio_clk", "base_uart3_clk",
+ "base_uart2_clk", "base_uart1_clk",
+ "base_uart0_clk", "base_ssp1_clk",
+ "base_ssp0_clk", "base_sdio_clk";
+ };
+
uart0: serial@40081000 {
compatible = "ns16550a";
reg = <0x40081000 0x1000>;
reg-shift = <2>;
interrupts = <24>;
- clocks = <&pll1>;
+ clocks = <&ccu2 CLK_APB0_UART0>, <&ccu1 CLK_CPU_UART0>;
status = "disabled";
};
@@ -57,7 +114,7 @@
reg = <0x40082000 0x1000>;
reg-shift = <2>;
interrupts = <25>;
- clocks = <&pll1>;
+ clocks = <&ccu2 CLK_APB0_UART1>, <&ccu1 CLK_CPU_UART1>;
status = "disabled";
};
@@ -65,7 +122,7 @@
compatible = "nxp,lpc3220-timer";
reg = <0x40084000 0x1000>;
interrupts = <12>;
- clocks = <&pll1>;
+ clocks = <&ccu1 CLK_CPU_TIMER0>;
clock-names = "timerclk";
};
@@ -73,7 +130,7 @@
compatible = "nxp,lpc3220-timer";
reg = <0x40085000 0x1000>;
interrupts = <13>;
- clocks = <&pll1>;
+ clocks = <&ccu1 CLK_CPU_TIMER1>;
clock-names = "timerclk";
};
@@ -82,7 +139,7 @@
reg = <0x400c1000 0x1000>;
reg-shift = <2>;
interrupts = <26>;
- clocks = <&pll1>;
+ clocks = <&ccu2 CLK_APB2_UART2>, <&ccu1 CLK_CPU_UART2>;
status = "disabled";
};
@@ -91,7 +148,7 @@
reg = <0x400c2000 0x1000>;
reg-shift = <2>;
interrupts = <27>;
- clocks = <&pll1>;
+ clocks = <&ccu2 CLK_APB2_UART3>, <&ccu1 CLK_CPU_UART3>;
status = "disabled";
};
@@ -99,7 +156,7 @@
compatible = "nxp,lpc3220-timer";
reg = <0x400c3000 0x1000>;
interrupts = <14>;
- clocks = <&pll1>;
+ clocks = <&ccu1 CLK_CPU_TIMER2>;
clock-names = "timerclk";
};
@@ -107,7 +164,7 @@
compatible = "nxp,lpc3220-timer";
reg = <0x400c4000 0x1000>;
interrupts = <15>;
- clocks = <&pll1>;
+ clocks = <&ccu1 CLK_CPU_TIMER3>;
clock-names = "timerclk";
};
};
diff --git a/arch/arm/boot/dts/lpc4350-hitex-eval.dts b/arch/arm/boot/dts/lpc4350-hitex-eval.dts
index d04072f40817..4ebdb54cc9ce 100644
--- a/arch/arm/boot/dts/lpc4350-hitex-eval.dts
+++ b/arch/arm/boot/dts/lpc4350-hitex-eval.dts
@@ -36,10 +36,6 @@
};
};
-&pll1 {
- clock-mult = <15>;
-};
-
&uart0 {
status = "okay";
};
--
1.8.0
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply related [flat|nested] 30+ messages in thread
* [PATCH v4 5/5] ARM: dts: lpc18xx: add clock nodes for cgu and ccu
@ 2015-05-28 20:31 ` Joachim Eastwood
0 siblings, 0 replies; 30+ messages in thread
From: Joachim Eastwood @ 2015-05-28 20:31 UTC (permalink / raw)
To: mturquette, sboyd
Cc: Joachim Eastwood, linux-clk, devicetree, linux-arm-kernel
Signed-off-by: Joachim Eastwood <manabian@gmail.com>
---
arch/arm/boot/dts/lpc18xx.dtsi | 85 ++++++++++++++++++++++++++------
arch/arm/boot/dts/lpc4350-hitex-eval.dts | 4 --
2 files changed, 71 insertions(+), 18 deletions(-)
diff --git a/arch/arm/boot/dts/lpc18xx.dtsi b/arch/arm/boot/dts/lpc18xx.dtsi
index 204da5b52ef9..78292d0cb263 100644
--- a/arch/arm/boot/dts/lpc18xx.dtsi
+++ b/arch/arm/boot/dts/lpc18xx.dtsi
@@ -13,6 +13,9 @@
#include "armv7-m.dtsi"
+#include "dt-bindings/clock/lpc18xx-cgu.h"
+#include "dt-bindings/clock/lpc18xx-ccu.h"
+
/ {
cpus {
#address-cells = <1>;
@@ -22,6 +25,7 @@
compatible = "arm,cortex-m3";
device_type = "cpu";
reg = <0x0>;
+ clocks = <&ccu1 CLK_CPU_CORE>;
};
};
@@ -32,23 +36,76 @@
clock-frequency = <12000000>;
};
- /* Temporary hardcode PLL1 until clk drivers are merged */
- pll1: pll1 {
- compatible = "fixed-factor-clock";
- clocks = <&xtal>;
+ xtal32: xtal32 {
+ compatible = "fixed-clock";
+ #clock-cells = <0>;
+ clock-frequency = <32768>;
+ };
+
+ enet_rx_clk: enet_rx_clk {
+ compatible = "fixed-clock";
+ #clock-cells = <0>;
+ clock-frequency = <0>;
+ clock-output-names = "enet_rx_clk";
+ };
+
+ enet_tx_clk: enet_tx_clk {
+ compatible = "fixed-clock";
+ #clock-cells = <0>;
+ clock-frequency = <0>;
+ clock-output-names = "enet_tx_clk";
+ };
+
+ gp_clkin: gp_clkin {
+ compatible = "fixed-clock";
#clock-cells = <0>;
- clock-div = <1>;
- clock-mult = <12>;
+ clock-frequency = <0>;
+ clock-output-names = "gp_clkin";
};
};
soc {
+ cgu: clock-controller@40050000 {
+ compatible = "nxp,lpc1850-cgu";
+ reg = <0x40050000 0x1000>;
+ #clock-cells = <1>;
+ clocks = <&xtal>, <&xtal32>, <&enet_rx_clk>, <&enet_tx_clk>, <&gp_clkin>;
+ };
+
+ ccu1: clock-controller@40051000 {
+ compatible = "nxp,lpc1850-ccu";
+ reg = <0x40051000 0x1000>;
+ #clock-cells = <1>;
+ clocks = <&cgu BASE_APB3_CLK>, <&cgu BASE_APB1_CLK>,
+ <&cgu BASE_SPIFI_CLK>, <&cgu BASE_CPU_CLK>,
+ <&cgu BASE_PERIPH_CLK>, <&cgu BASE_USB0_CLK>,
+ <&cgu BASE_USB1_CLK>, <&cgu BASE_SPI_CLK>;
+ clock-names = "base_apb3_clk", "base_apb1_clk",
+ "base_spifi_clk", "base_cpu_clk",
+ "base_periph_clk", "base_usb0_clk",
+ "base_usb1_clk", "base_spi_clk";
+ };
+
+ ccu2: clock-controller@40052000 {
+ compatible = "nxp,lpc1850-ccu";
+ reg = <0x40052000 0x1000>;
+ #clock-cells = <1>;
+ clocks = <&cgu BASE_AUDIO_CLK>, <&cgu BASE_UART3_CLK>,
+ <&cgu BASE_UART2_CLK>, <&cgu BASE_UART1_CLK>,
+ <&cgu BASE_UART0_CLK>, <&cgu BASE_SSP1_CLK>,
+ <&cgu BASE_SSP0_CLK>, <&cgu BASE_SDIO_CLK>;
+ clock-names = "base_audio_clk", "base_uart3_clk",
+ "base_uart2_clk", "base_uart1_clk",
+ "base_uart0_clk", "base_ssp1_clk",
+ "base_ssp0_clk", "base_sdio_clk";
+ };
+
uart0: serial@40081000 {
compatible = "ns16550a";
reg = <0x40081000 0x1000>;
reg-shift = <2>;
interrupts = <24>;
- clocks = <&pll1>;
+ clocks = <&ccu2 CLK_APB0_UART0>, <&ccu1 CLK_CPU_UART0>;
status = "disabled";
};
@@ -57,7 +114,7 @@
reg = <0x40082000 0x1000>;
reg-shift = <2>;
interrupts = <25>;
- clocks = <&pll1>;
+ clocks = <&ccu2 CLK_APB0_UART1>, <&ccu1 CLK_CPU_UART1>;
status = "disabled";
};
@@ -65,7 +122,7 @@
compatible = "nxp,lpc3220-timer";
reg = <0x40084000 0x1000>;
interrupts = <12>;
- clocks = <&pll1>;
+ clocks = <&ccu1 CLK_CPU_TIMER0>;
clock-names = "timerclk";
};
@@ -73,7 +130,7 @@
compatible = "nxp,lpc3220-timer";
reg = <0x40085000 0x1000>;
interrupts = <13>;
- clocks = <&pll1>;
+ clocks = <&ccu1 CLK_CPU_TIMER1>;
clock-names = "timerclk";
};
@@ -82,7 +139,7 @@
reg = <0x400c1000 0x1000>;
reg-shift = <2>;
interrupts = <26>;
- clocks = <&pll1>;
+ clocks = <&ccu2 CLK_APB2_UART2>, <&ccu1 CLK_CPU_UART2>;
status = "disabled";
};
@@ -91,7 +148,7 @@
reg = <0x400c2000 0x1000>;
reg-shift = <2>;
interrupts = <27>;
- clocks = <&pll1>;
+ clocks = <&ccu2 CLK_APB2_UART3>, <&ccu1 CLK_CPU_UART3>;
status = "disabled";
};
@@ -99,7 +156,7 @@
compatible = "nxp,lpc3220-timer";
reg = <0x400c3000 0x1000>;
interrupts = <14>;
- clocks = <&pll1>;
+ clocks = <&ccu1 CLK_CPU_TIMER2>;
clock-names = "timerclk";
};
@@ -107,7 +164,7 @@
compatible = "nxp,lpc3220-timer";
reg = <0x400c4000 0x1000>;
interrupts = <15>;
- clocks = <&pll1>;
+ clocks = <&ccu1 CLK_CPU_TIMER3>;
clock-names = "timerclk";
};
};
diff --git a/arch/arm/boot/dts/lpc4350-hitex-eval.dts b/arch/arm/boot/dts/lpc4350-hitex-eval.dts
index d04072f40817..4ebdb54cc9ce 100644
--- a/arch/arm/boot/dts/lpc4350-hitex-eval.dts
+++ b/arch/arm/boot/dts/lpc4350-hitex-eval.dts
@@ -36,10 +36,6 @@
};
};
-&pll1 {
- clock-mult = <15>;
-};
-
&uart0 {
status = "okay";
};
--
1.8.0
^ permalink raw reply related [flat|nested] 30+ messages in thread
* [PATCH v4 5/5] ARM: dts: lpc18xx: add clock nodes for cgu and ccu
@ 2015-05-28 20:31 ` Joachim Eastwood
0 siblings, 0 replies; 30+ messages in thread
From: Joachim Eastwood @ 2015-05-28 20:31 UTC (permalink / raw)
To: linux-arm-kernel
Signed-off-by: Joachim Eastwood <manabian@gmail.com>
---
arch/arm/boot/dts/lpc18xx.dtsi | 85 ++++++++++++++++++++++++++------
arch/arm/boot/dts/lpc4350-hitex-eval.dts | 4 --
2 files changed, 71 insertions(+), 18 deletions(-)
diff --git a/arch/arm/boot/dts/lpc18xx.dtsi b/arch/arm/boot/dts/lpc18xx.dtsi
index 204da5b52ef9..78292d0cb263 100644
--- a/arch/arm/boot/dts/lpc18xx.dtsi
+++ b/arch/arm/boot/dts/lpc18xx.dtsi
@@ -13,6 +13,9 @@
#include "armv7-m.dtsi"
+#include "dt-bindings/clock/lpc18xx-cgu.h"
+#include "dt-bindings/clock/lpc18xx-ccu.h"
+
/ {
cpus {
#address-cells = <1>;
@@ -22,6 +25,7 @@
compatible = "arm,cortex-m3";
device_type = "cpu";
reg = <0x0>;
+ clocks = <&ccu1 CLK_CPU_CORE>;
};
};
@@ -32,23 +36,76 @@
clock-frequency = <12000000>;
};
- /* Temporary hardcode PLL1 until clk drivers are merged */
- pll1: pll1 {
- compatible = "fixed-factor-clock";
- clocks = <&xtal>;
+ xtal32: xtal32 {
+ compatible = "fixed-clock";
+ #clock-cells = <0>;
+ clock-frequency = <32768>;
+ };
+
+ enet_rx_clk: enet_rx_clk {
+ compatible = "fixed-clock";
+ #clock-cells = <0>;
+ clock-frequency = <0>;
+ clock-output-names = "enet_rx_clk";
+ };
+
+ enet_tx_clk: enet_tx_clk {
+ compatible = "fixed-clock";
+ #clock-cells = <0>;
+ clock-frequency = <0>;
+ clock-output-names = "enet_tx_clk";
+ };
+
+ gp_clkin: gp_clkin {
+ compatible = "fixed-clock";
#clock-cells = <0>;
- clock-div = <1>;
- clock-mult = <12>;
+ clock-frequency = <0>;
+ clock-output-names = "gp_clkin";
};
};
soc {
+ cgu: clock-controller at 40050000 {
+ compatible = "nxp,lpc1850-cgu";
+ reg = <0x40050000 0x1000>;
+ #clock-cells = <1>;
+ clocks = <&xtal>, <&xtal32>, <&enet_rx_clk>, <&enet_tx_clk>, <&gp_clkin>;
+ };
+
+ ccu1: clock-controller at 40051000 {
+ compatible = "nxp,lpc1850-ccu";
+ reg = <0x40051000 0x1000>;
+ #clock-cells = <1>;
+ clocks = <&cgu BASE_APB3_CLK>, <&cgu BASE_APB1_CLK>,
+ <&cgu BASE_SPIFI_CLK>, <&cgu BASE_CPU_CLK>,
+ <&cgu BASE_PERIPH_CLK>, <&cgu BASE_USB0_CLK>,
+ <&cgu BASE_USB1_CLK>, <&cgu BASE_SPI_CLK>;
+ clock-names = "base_apb3_clk", "base_apb1_clk",
+ "base_spifi_clk", "base_cpu_clk",
+ "base_periph_clk", "base_usb0_clk",
+ "base_usb1_clk", "base_spi_clk";
+ };
+
+ ccu2: clock-controller at 40052000 {
+ compatible = "nxp,lpc1850-ccu";
+ reg = <0x40052000 0x1000>;
+ #clock-cells = <1>;
+ clocks = <&cgu BASE_AUDIO_CLK>, <&cgu BASE_UART3_CLK>,
+ <&cgu BASE_UART2_CLK>, <&cgu BASE_UART1_CLK>,
+ <&cgu BASE_UART0_CLK>, <&cgu BASE_SSP1_CLK>,
+ <&cgu BASE_SSP0_CLK>, <&cgu BASE_SDIO_CLK>;
+ clock-names = "base_audio_clk", "base_uart3_clk",
+ "base_uart2_clk", "base_uart1_clk",
+ "base_uart0_clk", "base_ssp1_clk",
+ "base_ssp0_clk", "base_sdio_clk";
+ };
+
uart0: serial at 40081000 {
compatible = "ns16550a";
reg = <0x40081000 0x1000>;
reg-shift = <2>;
interrupts = <24>;
- clocks = <&pll1>;
+ clocks = <&ccu2 CLK_APB0_UART0>, <&ccu1 CLK_CPU_UART0>;
status = "disabled";
};
@@ -57,7 +114,7 @@
reg = <0x40082000 0x1000>;
reg-shift = <2>;
interrupts = <25>;
- clocks = <&pll1>;
+ clocks = <&ccu2 CLK_APB0_UART1>, <&ccu1 CLK_CPU_UART1>;
status = "disabled";
};
@@ -65,7 +122,7 @@
compatible = "nxp,lpc3220-timer";
reg = <0x40084000 0x1000>;
interrupts = <12>;
- clocks = <&pll1>;
+ clocks = <&ccu1 CLK_CPU_TIMER0>;
clock-names = "timerclk";
};
@@ -73,7 +130,7 @@
compatible = "nxp,lpc3220-timer";
reg = <0x40085000 0x1000>;
interrupts = <13>;
- clocks = <&pll1>;
+ clocks = <&ccu1 CLK_CPU_TIMER1>;
clock-names = "timerclk";
};
@@ -82,7 +139,7 @@
reg = <0x400c1000 0x1000>;
reg-shift = <2>;
interrupts = <26>;
- clocks = <&pll1>;
+ clocks = <&ccu2 CLK_APB2_UART2>, <&ccu1 CLK_CPU_UART2>;
status = "disabled";
};
@@ -91,7 +148,7 @@
reg = <0x400c2000 0x1000>;
reg-shift = <2>;
interrupts = <27>;
- clocks = <&pll1>;
+ clocks = <&ccu2 CLK_APB2_UART3>, <&ccu1 CLK_CPU_UART3>;
status = "disabled";
};
@@ -99,7 +156,7 @@
compatible = "nxp,lpc3220-timer";
reg = <0x400c3000 0x1000>;
interrupts = <14>;
- clocks = <&pll1>;
+ clocks = <&ccu1 CLK_CPU_TIMER2>;
clock-names = "timerclk";
};
@@ -107,7 +164,7 @@
compatible = "nxp,lpc3220-timer";
reg = <0x400c4000 0x1000>;
interrupts = <15>;
- clocks = <&pll1>;
+ clocks = <&ccu1 CLK_CPU_TIMER3>;
clock-names = "timerclk";
};
};
diff --git a/arch/arm/boot/dts/lpc4350-hitex-eval.dts b/arch/arm/boot/dts/lpc4350-hitex-eval.dts
index d04072f40817..4ebdb54cc9ce 100644
--- a/arch/arm/boot/dts/lpc4350-hitex-eval.dts
+++ b/arch/arm/boot/dts/lpc4350-hitex-eval.dts
@@ -36,10 +36,6 @@
};
};
-&pll1 {
- clock-mult = <15>;
-};
-
&uart0 {
status = "okay";
};
--
1.8.0
^ permalink raw reply related [flat|nested] 30+ messages in thread
* Re: [PATCH v4 3/5] clk: add lpc18xx ccu clk driver
2015-05-28 20:31 ` Joachim Eastwood
(?)
@ 2015-06-10 2:13 ` Michael Turquette
-1 siblings, 0 replies; 30+ messages in thread
From: Michael Turquette @ 2015-06-10 2:13 UTC (permalink / raw)
To: sboyd-sgV2jX0FEOL9JmXXK+q4OQ
Cc: Joachim Eastwood, linux-clk-u79uwXL29TY76Z2rM5mHXA,
devicetree-u79uwXL29TY76Z2rM5mHXA,
linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r
Quoting Joachim Eastwood (2015-05-28 13:31:45)
> +static struct lpc18xx_clk_branch clk_branches[] = {
> + {"base_apb3_clk", "apb3_bus", CLK_APB3_BUS, CCU_BRANCH_IS_BUS},
> + {"base_apb3_clk", "apb3_i2c1", CLK_APB3_I2C1, 0},
> + {"base_apb3_clk", "apb3_dac", CLK_APB3_DAC, 0},
> + {"base_apb3_clk", "apb3_adc0", CLK_APB3_ADC0, 0},
> + {"base_apb3_clk", "apb3_adc1", CLK_APB3_ADC1, 0},
> + {"base_apb3_clk", "apb3_can0", CLK_APB3_CAN0, 0},
> +
> + {"base_apb1_clk", "apb1_bus", CLK_APB1_BUS, CCU_BRANCH_IS_BUS},
> + {"base_apb1_clk", "apb1_mc_pwm", CLK_APB1_MOTOCON_PWM, 0},
> + {"base_apb1_clk", "apb1_i2c0", CLK_APB1_I2C0, 0},
> + {"base_apb1_clk", "apb1_i2s", CLK_APB1_I2S, 0},
> + {"base_apb1_clk", "apb1_can1", CLK_APB1_CAN1, 0},
> +
> + {"base_spifi_clk", "spifi", CLK_SPIFI, 0},
> +
> + {"base_cpu_clk", "cpu_bus", CLK_CPU_BUS, CCU_BRANCH_IS_BUS},
> + {"base_cpu_clk", "cpu_spifi", CLK_CPU_SPIFI, 0},
> + {"base_cpu_clk", "cpu_gpio", CLK_CPU_GPIO, 0},
> + {"base_cpu_clk", "cpu_lcd", CLK_CPU_LCD, 0},
> + {"base_cpu_clk", "cpu_ethernet", CLK_CPU_ETHERNET, 0},
> + {"base_cpu_clk", "cpu_usb0", CLK_CPU_USB0, 0},
> + {"base_cpu_clk", "cpu_emc", CLK_CPU_EMC, 0},
> + {"base_cpu_clk", "cpu_sdio", CLK_CPU_SDIO, 0},
> + {"base_cpu_clk", "cpu_dma", CLK_CPU_DMA, 0},
> + {"base_cpu_clk", "cpu_core", CLK_CPU_CORE, 0},
> + {"base_cpu_clk", "cpu_sct", CLK_CPU_SCT, 0},
> + {"base_cpu_clk", "cpu_usb1", CLK_CPU_USB1, 0},
> + {"base_cpu_clk", "cpu_emcdiv", CLK_CPU_EMCDIV, CCU_BRANCH_HAVE_DIV2},
> + {"base_cpu_clk", "cpu_flasha", CLK_CPU_FLASHA, CCU_BRANCH_HAVE_DIV2},
> + {"base_cpu_clk", "cpu_flashb", CLK_CPU_FLASHB, CCU_BRANCH_HAVE_DIV2},
> + {"base_cpu_clk", "cpu_m0app", CLK_CPU_M0APP, CCU_BRANCH_HAVE_DIV2},
> + {"base_cpu_clk", "cpu_adchs", CLK_CPU_ADCHS, CCU_BRANCH_HAVE_DIV2},
> + {"base_cpu_clk", "cpu_eeprom", CLK_CPU_EEPROM, CCU_BRANCH_HAVE_DIV2},
> + {"base_cpu_clk", "cpu_wwdt", CLK_CPU_WWDT, 0},
> + {"base_cpu_clk", "cpu_uart0", CLK_CPU_UART0, 0},
> + {"base_cpu_clk", "cpu_uart1", CLK_CPU_UART1, 0},
> + {"base_cpu_clk", "cpu_ssp0", CLK_CPU_SSP0, 0},
> + {"base_cpu_clk", "cpu_timer0", CLK_CPU_TIMER0, 0},
> + {"base_cpu_clk", "cpu_timer1", CLK_CPU_TIMER1, 0},
> + {"base_cpu_clk", "cpu_scu", CLK_CPU_SCU, 0},
> + {"base_cpu_clk", "cpu_creg", CLK_CPU_CREG, 0},
> + {"base_cpu_clk", "cpu_ritimer", CLK_CPU_RITIMER, 0},
> + {"base_cpu_clk", "cpu_uart2", CLK_CPU_UART2, 0},
> + {"base_cpu_clk", "cpu_uart3", CLK_CPU_UART3, 0},
> + {"base_cpu_clk", "cpu_timer2", CLK_CPU_TIMER2, 0},
> + {"base_cpu_clk", "cpu_timer3", CLK_CPU_TIMER3, 0},
> + {"base_cpu_clk", "cpu_ssp1", CLK_CPU_SSP1, 0},
> + {"base_cpu_clk", "cpu_qei", CLK_CPU_QEI, 0},
> +
> + {"base_periph_clk", "periph_bus", CLK_PERIPH_BUS, CCU_BRANCH_IS_BUS},
> + {"base_periph_clk", "periph_core", CLK_PERIPH_CORE, 0},
> + {"base_periph_clk", "periph_sgpio", CLK_PERIPH_SGPIO, 0},
> +
> + {"base_usb0_clk", "usb0", CLK_USB0, 0},
> + {"base_usb1_clk", "usb1", CLK_USB1, 0},
> + {"base_spi_clk", "spi", CLK_SPI, 0},
> + {"base_adchs_clk", "adchs", CLK_ADCHS, 0},
> +
> + {"base_audio_clk", "audio", CLK_AUDIO, 0},
> + {"base_uart3_clk", "apb2_uart3", CLK_APB2_UART3, 0},
> + {"base_uart2_clk", "apb2_uart2", CLK_APB2_UART2, 0},
> + {"base_uart1_clk", "apb0_uart1", CLK_APB0_UART1, 0},
> + {"base_uart0_clk", "apb0_uart0", CLK_APB0_UART0, 0},
> + {"base_ssp1_clk", "apb2_ssp1", CLK_APB2_SSP1, 0},
> + {"base_ssp0_clk", "apb0_ssp0", CLK_APB0_SSP0, 0},
> + {"base_sdio_clk", "sdio", CLK_SDIO, 0},
> +};
Hi Joachim,
If it were me, I would have broken this up into two tables, one for each
CCU. In general I would structure the code to reflect the fact that two
different IP blocks are being accessed. This isn't a deal breaker but I
thought I would mention it in case you want to make the change.
Otherwise this series looks good to me. Let me know if you plan a V5
submission.
I can take patches #1-4 into the clk tree. Please add my Acked-by to
patch #5. I will create an immutable branch to share with the arm-soc
tree so that they can take #5 and have access to the dt-bindings
headers.
Regards,
Mike
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply [flat|nested] 30+ messages in thread
* Re: [PATCH v4 3/5] clk: add lpc18xx ccu clk driver
@ 2015-06-10 2:13 ` Michael Turquette
0 siblings, 0 replies; 30+ messages in thread
From: Michael Turquette @ 2015-06-10 2:13 UTC (permalink / raw)
To: Joachim Eastwood, sboyd
Cc: Joachim Eastwood, linux-clk, devicetree, linux-arm-kernel
Quoting Joachim Eastwood (2015-05-28 13:31:45)
> +static struct lpc18xx_clk_branch clk_branches[] =3D {
> + {"base_apb3_clk", "apb3_bus", CLK_APB3_BUS, C=
CU_BRANCH_IS_BUS},
> + {"base_apb3_clk", "apb3_i2c1", CLK_APB3_I2C1, 0=
},
> + {"base_apb3_clk", "apb3_dac", CLK_APB3_DAC, 0=
},
> + {"base_apb3_clk", "apb3_adc0", CLK_APB3_ADC0, 0=
},
> + {"base_apb3_clk", "apb3_adc1", CLK_APB3_ADC1, 0=
},
> + {"base_apb3_clk", "apb3_can0", CLK_APB3_CAN0, 0=
},
> +
> + {"base_apb1_clk", "apb1_bus", CLK_APB1_BUS, C=
CU_BRANCH_IS_BUS},
> + {"base_apb1_clk", "apb1_mc_pwm", CLK_APB1_MOTOCON_PWM, 0=
},
> + {"base_apb1_clk", "apb1_i2c0", CLK_APB1_I2C0, 0=
},
> + {"base_apb1_clk", "apb1_i2s", CLK_APB1_I2S, 0=
},
> + {"base_apb1_clk", "apb1_can1", CLK_APB1_CAN1, 0=
},
> +
> + {"base_spifi_clk", "spifi", CLK_SPIFI, 0=
},
> +
> + {"base_cpu_clk", "cpu_bus", CLK_CPU_BUS, C=
CU_BRANCH_IS_BUS},
> + {"base_cpu_clk", "cpu_spifi", CLK_CPU_SPIFI, 0=
},
> + {"base_cpu_clk", "cpu_gpio", CLK_CPU_GPIO, 0=
},
> + {"base_cpu_clk", "cpu_lcd", CLK_CPU_LCD, 0=
},
> + {"base_cpu_clk", "cpu_ethernet", CLK_CPU_ETHERNET, 0=
},
> + {"base_cpu_clk", "cpu_usb0", CLK_CPU_USB0, 0=
},
> + {"base_cpu_clk", "cpu_emc", CLK_CPU_EMC, 0=
},
> + {"base_cpu_clk", "cpu_sdio", CLK_CPU_SDIO, 0=
},
> + {"base_cpu_clk", "cpu_dma", CLK_CPU_DMA, 0=
},
> + {"base_cpu_clk", "cpu_core", CLK_CPU_CORE, 0=
},
> + {"base_cpu_clk", "cpu_sct", CLK_CPU_SCT, 0=
},
> + {"base_cpu_clk", "cpu_usb1", CLK_CPU_USB1, 0=
},
> + {"base_cpu_clk", "cpu_emcdiv", CLK_CPU_EMCDIV, C=
CU_BRANCH_HAVE_DIV2},
> + {"base_cpu_clk", "cpu_flasha", CLK_CPU_FLASHA, C=
CU_BRANCH_HAVE_DIV2},
> + {"base_cpu_clk", "cpu_flashb", CLK_CPU_FLASHB, C=
CU_BRANCH_HAVE_DIV2},
> + {"base_cpu_clk", "cpu_m0app", CLK_CPU_M0APP, C=
CU_BRANCH_HAVE_DIV2},
> + {"base_cpu_clk", "cpu_adchs", CLK_CPU_ADCHS, C=
CU_BRANCH_HAVE_DIV2},
> + {"base_cpu_clk", "cpu_eeprom", CLK_CPU_EEPROM, C=
CU_BRANCH_HAVE_DIV2},
> + {"base_cpu_clk", "cpu_wwdt", CLK_CPU_WWDT, 0=
},
> + {"base_cpu_clk", "cpu_uart0", CLK_CPU_UART0, 0=
},
> + {"base_cpu_clk", "cpu_uart1", CLK_CPU_UART1, 0=
},
> + {"base_cpu_clk", "cpu_ssp0", CLK_CPU_SSP0, 0=
},
> + {"base_cpu_clk", "cpu_timer0", CLK_CPU_TIMER0, 0=
},
> + {"base_cpu_clk", "cpu_timer1", CLK_CPU_TIMER1, 0=
},
> + {"base_cpu_clk", "cpu_scu", CLK_CPU_SCU, 0=
},
> + {"base_cpu_clk", "cpu_creg", CLK_CPU_CREG, 0=
},
> + {"base_cpu_clk", "cpu_ritimer", CLK_CPU_RITIMER, 0=
},
> + {"base_cpu_clk", "cpu_uart2", CLK_CPU_UART2, 0=
},
> + {"base_cpu_clk", "cpu_uart3", CLK_CPU_UART3, 0=
},
> + {"base_cpu_clk", "cpu_timer2", CLK_CPU_TIMER2, 0=
},
> + {"base_cpu_clk", "cpu_timer3", CLK_CPU_TIMER3, 0=
},
> + {"base_cpu_clk", "cpu_ssp1", CLK_CPU_SSP1, 0=
},
> + {"base_cpu_clk", "cpu_qei", CLK_CPU_QEI, 0=
},
> +
> + {"base_periph_clk", "periph_bus", CLK_PERIPH_BUS, C=
CU_BRANCH_IS_BUS},
> + {"base_periph_clk", "periph_core", CLK_PERIPH_CORE, 0=
},
> + {"base_periph_clk", "periph_sgpio", CLK_PERIPH_SGPIO, 0=
},
> +
> + {"base_usb0_clk", "usb0", CLK_USB0, 0=
},
> + {"base_usb1_clk", "usb1", CLK_USB1, 0=
},
> + {"base_spi_clk", "spi", CLK_SPI, 0=
},
> + {"base_adchs_clk", "adchs", CLK_ADCHS, 0=
},
> +
> + {"base_audio_clk", "audio", CLK_AUDIO, 0=
},
> + {"base_uart3_clk", "apb2_uart3", CLK_APB2_UART3, 0=
},
> + {"base_uart2_clk", "apb2_uart2", CLK_APB2_UART2, 0=
},
> + {"base_uart1_clk", "apb0_uart1", CLK_APB0_UART1, 0=
},
> + {"base_uart0_clk", "apb0_uart0", CLK_APB0_UART0, 0=
},
> + {"base_ssp1_clk", "apb2_ssp1", CLK_APB2_SSP1, 0=
},
> + {"base_ssp0_clk", "apb0_ssp0", CLK_APB0_SSP0, 0=
},
> + {"base_sdio_clk", "sdio", CLK_SDIO, 0=
},
> +};
Hi Joachim,
If it were me, I would have broken this up into two tables, one for each
CCU. In general I would structure the code to reflect the fact that two
different IP blocks are being accessed. This isn't a deal breaker but I
thought I would mention it in case you want to make the change.
Otherwise this series looks good to me. Let me know if you plan a V5
submission.
I can take patches #1-4 into the clk tree. Please add my Acked-by to
patch #5. I will create an immutable branch to share with the arm-soc
tree so that they can take #5 and have access to the dt-bindings
headers.
Regards,
Mike
^ permalink raw reply [flat|nested] 30+ messages in thread
* [PATCH v4 3/5] clk: add lpc18xx ccu clk driver
@ 2015-06-10 2:13 ` Michael Turquette
0 siblings, 0 replies; 30+ messages in thread
From: Michael Turquette @ 2015-06-10 2:13 UTC (permalink / raw)
To: linux-arm-kernel
Quoting Joachim Eastwood (2015-05-28 13:31:45)
> +static struct lpc18xx_clk_branch clk_branches[] = {
> + {"base_apb3_clk", "apb3_bus", CLK_APB3_BUS, CCU_BRANCH_IS_BUS},
> + {"base_apb3_clk", "apb3_i2c1", CLK_APB3_I2C1, 0},
> + {"base_apb3_clk", "apb3_dac", CLK_APB3_DAC, 0},
> + {"base_apb3_clk", "apb3_adc0", CLK_APB3_ADC0, 0},
> + {"base_apb3_clk", "apb3_adc1", CLK_APB3_ADC1, 0},
> + {"base_apb3_clk", "apb3_can0", CLK_APB3_CAN0, 0},
> +
> + {"base_apb1_clk", "apb1_bus", CLK_APB1_BUS, CCU_BRANCH_IS_BUS},
> + {"base_apb1_clk", "apb1_mc_pwm", CLK_APB1_MOTOCON_PWM, 0},
> + {"base_apb1_clk", "apb1_i2c0", CLK_APB1_I2C0, 0},
> + {"base_apb1_clk", "apb1_i2s", CLK_APB1_I2S, 0},
> + {"base_apb1_clk", "apb1_can1", CLK_APB1_CAN1, 0},
> +
> + {"base_spifi_clk", "spifi", CLK_SPIFI, 0},
> +
> + {"base_cpu_clk", "cpu_bus", CLK_CPU_BUS, CCU_BRANCH_IS_BUS},
> + {"base_cpu_clk", "cpu_spifi", CLK_CPU_SPIFI, 0},
> + {"base_cpu_clk", "cpu_gpio", CLK_CPU_GPIO, 0},
> + {"base_cpu_clk", "cpu_lcd", CLK_CPU_LCD, 0},
> + {"base_cpu_clk", "cpu_ethernet", CLK_CPU_ETHERNET, 0},
> + {"base_cpu_clk", "cpu_usb0", CLK_CPU_USB0, 0},
> + {"base_cpu_clk", "cpu_emc", CLK_CPU_EMC, 0},
> + {"base_cpu_clk", "cpu_sdio", CLK_CPU_SDIO, 0},
> + {"base_cpu_clk", "cpu_dma", CLK_CPU_DMA, 0},
> + {"base_cpu_clk", "cpu_core", CLK_CPU_CORE, 0},
> + {"base_cpu_clk", "cpu_sct", CLK_CPU_SCT, 0},
> + {"base_cpu_clk", "cpu_usb1", CLK_CPU_USB1, 0},
> + {"base_cpu_clk", "cpu_emcdiv", CLK_CPU_EMCDIV, CCU_BRANCH_HAVE_DIV2},
> + {"base_cpu_clk", "cpu_flasha", CLK_CPU_FLASHA, CCU_BRANCH_HAVE_DIV2},
> + {"base_cpu_clk", "cpu_flashb", CLK_CPU_FLASHB, CCU_BRANCH_HAVE_DIV2},
> + {"base_cpu_clk", "cpu_m0app", CLK_CPU_M0APP, CCU_BRANCH_HAVE_DIV2},
> + {"base_cpu_clk", "cpu_adchs", CLK_CPU_ADCHS, CCU_BRANCH_HAVE_DIV2},
> + {"base_cpu_clk", "cpu_eeprom", CLK_CPU_EEPROM, CCU_BRANCH_HAVE_DIV2},
> + {"base_cpu_clk", "cpu_wwdt", CLK_CPU_WWDT, 0},
> + {"base_cpu_clk", "cpu_uart0", CLK_CPU_UART0, 0},
> + {"base_cpu_clk", "cpu_uart1", CLK_CPU_UART1, 0},
> + {"base_cpu_clk", "cpu_ssp0", CLK_CPU_SSP0, 0},
> + {"base_cpu_clk", "cpu_timer0", CLK_CPU_TIMER0, 0},
> + {"base_cpu_clk", "cpu_timer1", CLK_CPU_TIMER1, 0},
> + {"base_cpu_clk", "cpu_scu", CLK_CPU_SCU, 0},
> + {"base_cpu_clk", "cpu_creg", CLK_CPU_CREG, 0},
> + {"base_cpu_clk", "cpu_ritimer", CLK_CPU_RITIMER, 0},
> + {"base_cpu_clk", "cpu_uart2", CLK_CPU_UART2, 0},
> + {"base_cpu_clk", "cpu_uart3", CLK_CPU_UART3, 0},
> + {"base_cpu_clk", "cpu_timer2", CLK_CPU_TIMER2, 0},
> + {"base_cpu_clk", "cpu_timer3", CLK_CPU_TIMER3, 0},
> + {"base_cpu_clk", "cpu_ssp1", CLK_CPU_SSP1, 0},
> + {"base_cpu_clk", "cpu_qei", CLK_CPU_QEI, 0},
> +
> + {"base_periph_clk", "periph_bus", CLK_PERIPH_BUS, CCU_BRANCH_IS_BUS},
> + {"base_periph_clk", "periph_core", CLK_PERIPH_CORE, 0},
> + {"base_periph_clk", "periph_sgpio", CLK_PERIPH_SGPIO, 0},
> +
> + {"base_usb0_clk", "usb0", CLK_USB0, 0},
> + {"base_usb1_clk", "usb1", CLK_USB1, 0},
> + {"base_spi_clk", "spi", CLK_SPI, 0},
> + {"base_adchs_clk", "adchs", CLK_ADCHS, 0},
> +
> + {"base_audio_clk", "audio", CLK_AUDIO, 0},
> + {"base_uart3_clk", "apb2_uart3", CLK_APB2_UART3, 0},
> + {"base_uart2_clk", "apb2_uart2", CLK_APB2_UART2, 0},
> + {"base_uart1_clk", "apb0_uart1", CLK_APB0_UART1, 0},
> + {"base_uart0_clk", "apb0_uart0", CLK_APB0_UART0, 0},
> + {"base_ssp1_clk", "apb2_ssp1", CLK_APB2_SSP1, 0},
> + {"base_ssp0_clk", "apb0_ssp0", CLK_APB0_SSP0, 0},
> + {"base_sdio_clk", "sdio", CLK_SDIO, 0},
> +};
Hi Joachim,
If it were me, I would have broken this up into two tables, one for each
CCU. In general I would structure the code to reflect the fact that two
different IP blocks are being accessed. This isn't a deal breaker but I
thought I would mention it in case you want to make the change.
Otherwise this series looks good to me. Let me know if you plan a V5
submission.
I can take patches #1-4 into the clk tree. Please add my Acked-by to
patch #5. I will create an immutable branch to share with the arm-soc
tree so that they can take #5 and have access to the dt-bindings
headers.
Regards,
Mike
^ permalink raw reply [flat|nested] 30+ messages in thread
* Re: [PATCH v4 3/5] clk: add lpc18xx ccu clk driver
2015-06-10 2:13 ` Michael Turquette
(?)
@ 2015-06-10 14:02 ` Joachim Eastwood
-1 siblings, 0 replies; 30+ messages in thread
From: Joachim Eastwood @ 2015-06-10 14:02 UTC (permalink / raw)
To: Michael Turquette
Cc: Stephen Boyd, linux-clk-u79uwXL29TY76Z2rM5mHXA,
devicetree-u79uwXL29TY76Z2rM5mHXA,
linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r
Hi Mike,
> Hi Joachim,
>
> If it were me, I would have broken this up into two tables, one for each
> CCU. In general I would structure the code to reflect the fact that two
> different IP blocks are being accessed. This isn't a deal breaker but I
> thought I would mention it in case you want to make the change.
>
> Otherwise this series looks good to me. Let me know if you plan a V5
> submission.
If there is still time for 4.2 and you don't have any more comments on
how the driver uses the DT bindings I would rather send a follow up
patch that splits the ccu table for 4.3.
> I can take patches #1-4 into the clk tree. Please add my Acked-by to
> patch #5. I will create an immutable branch to share with the arm-soc
> tree so that they can take #5 and have access to the dt-bindings
> headers.
Sounds good. I'll talk to arm-soc team about it. But it isn't critical
for me to get the DTS changes in for 4.2, but I would be very grateful
for getting the drivers and headers in for 4.2 so that 4.3 is ready
and doesn't have any header dependencies for all the driver DTS stuff.
Thanks, Mike.
regards,
Joachim Eastwood
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply [flat|nested] 30+ messages in thread
* Re: [PATCH v4 3/5] clk: add lpc18xx ccu clk driver
@ 2015-06-10 14:02 ` Joachim Eastwood
0 siblings, 0 replies; 30+ messages in thread
From: Joachim Eastwood @ 2015-06-10 14:02 UTC (permalink / raw)
To: Michael Turquette; +Cc: Stephen Boyd, linux-clk, devicetree, linux-arm-kernel
Hi Mike,
> Hi Joachim,
>
> If it were me, I would have broken this up into two tables, one for each
> CCU. In general I would structure the code to reflect the fact that two
> different IP blocks are being accessed. This isn't a deal breaker but I
> thought I would mention it in case you want to make the change.
>
> Otherwise this series looks good to me. Let me know if you plan a V5
> submission.
If there is still time for 4.2 and you don't have any more comments on
how the driver uses the DT bindings I would rather send a follow up
patch that splits the ccu table for 4.3.
> I can take patches #1-4 into the clk tree. Please add my Acked-by to
> patch #5. I will create an immutable branch to share with the arm-soc
> tree so that they can take #5 and have access to the dt-bindings
> headers.
Sounds good. I'll talk to arm-soc team about it. But it isn't critical
for me to get the DTS changes in for 4.2, but I would be very grateful
for getting the drivers and headers in for 4.2 so that 4.3 is ready
and doesn't have any header dependencies for all the driver DTS stuff.
Thanks, Mike.
regards,
Joachim Eastwood
^ permalink raw reply [flat|nested] 30+ messages in thread
* [PATCH v4 3/5] clk: add lpc18xx ccu clk driver
@ 2015-06-10 14:02 ` Joachim Eastwood
0 siblings, 0 replies; 30+ messages in thread
From: Joachim Eastwood @ 2015-06-10 14:02 UTC (permalink / raw)
To: linux-arm-kernel
Hi Mike,
> Hi Joachim,
>
> If it were me, I would have broken this up into two tables, one for each
> CCU. In general I would structure the code to reflect the fact that two
> different IP blocks are being accessed. This isn't a deal breaker but I
> thought I would mention it in case you want to make the change.
>
> Otherwise this series looks good to me. Let me know if you plan a V5
> submission.
If there is still time for 4.2 and you don't have any more comments on
how the driver uses the DT bindings I would rather send a follow up
patch that splits the ccu table for 4.3.
> I can take patches #1-4 into the clk tree. Please add my Acked-by to
> patch #5. I will create an immutable branch to share with the arm-soc
> tree so that they can take #5 and have access to the dt-bindings
> headers.
Sounds good. I'll talk to arm-soc team about it. But it isn't critical
for me to get the DTS changes in for 4.2, but I would be very grateful
for getting the drivers and headers in for 4.2 so that 4.3 is ready
and doesn't have any header dependencies for all the driver DTS stuff.
Thanks, Mike.
regards,
Joachim Eastwood
^ permalink raw reply [flat|nested] 30+ messages in thread
* Re: [PATCH v4 3/5] clk: add lpc18xx ccu clk driver
2015-06-10 14:02 ` Joachim Eastwood
(?)
@ 2015-06-18 22:45 ` Michael Turquette
-1 siblings, 0 replies; 30+ messages in thread
From: Michael Turquette @ 2015-06-18 22:45 UTC (permalink / raw)
To: Joachim Eastwood; +Cc: devicetree, Stephen Boyd, linux-clk, linux-arm-kernel
Quoting Joachim Eastwood (2015-06-10 07:02:59)
> Hi Mike,
>
>
> > Hi Joachim,
> >
> > If it were me, I would have broken this up into two tables, one for each
> > CCU. In general I would structure the code to reflect the fact that two
> > different IP blocks are being accessed. This isn't a deal breaker but I
> > thought I would mention it in case you want to make the change.
> >
> > Otherwise this series looks good to me. Let me know if you plan a V5
> > submission.
>
> If there is still time for 4.2 and you don't have any more comments on
> how the driver uses the DT bindings I would rather send a follow up
> patch that splits the ccu table for 4.3.
>
>
> > I can take patches #1-4 into the clk tree. Please add my Acked-by to
> > patch #5. I will create an immutable branch to share with the arm-soc
> > tree so that they can take #5 and have access to the dt-bindings
> > headers.
>
> Sounds good. I'll talk to arm-soc team about it. But it isn't critical
> for me to get the DTS changes in for 4.2, but I would be very grateful
> for getting the drivers and headers in for 4.2 so that 4.3 is ready
> and doesn't have any header dependencies for all the driver DTS stuff.
Patches #1-4 applied to clk-next for 4.2.
Regards,
Mike
>
> Thanks, Mike.
>
>
> regards,
> Joachim Eastwood
^ permalink raw reply [flat|nested] 30+ messages in thread
* Re: [PATCH v4 3/5] clk: add lpc18xx ccu clk driver
@ 2015-06-18 22:45 ` Michael Turquette
0 siblings, 0 replies; 30+ messages in thread
From: Michael Turquette @ 2015-06-18 22:45 UTC (permalink / raw)
To: Joachim Eastwood; +Cc: devicetree, Stephen Boyd, linux-clk, linux-arm-kernel
Quoting Joachim Eastwood (2015-06-10 07:02:59)
> Hi Mike,
>
>
> > Hi Joachim,
> >
> > If it were me, I would have broken this up into two tables, one for each
> > CCU. In general I would structure the code to reflect the fact that two
> > different IP blocks are being accessed. This isn't a deal breaker but I
> > thought I would mention it in case you want to make the change.
> >
> > Otherwise this series looks good to me. Let me know if you plan a V5
> > submission.
>
> If there is still time for 4.2 and you don't have any more comments on
> how the driver uses the DT bindings I would rather send a follow up
> patch that splits the ccu table for 4.3.
>
>
> > I can take patches #1-4 into the clk tree. Please add my Acked-by to
> > patch #5. I will create an immutable branch to share with the arm-soc
> > tree so that they can take #5 and have access to the dt-bindings
> > headers.
>
> Sounds good. I'll talk to arm-soc team about it. But it isn't critical
> for me to get the DTS changes in for 4.2, but I would be very grateful
> for getting the drivers and headers in for 4.2 so that 4.3 is ready
> and doesn't have any header dependencies for all the driver DTS stuff.
Patches #1-4 applied to clk-next for 4.2.
Regards,
Mike
>
> Thanks, Mike.
>
>
> regards,
> Joachim Eastwood
_______________________________________________
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] 30+ messages in thread
* [PATCH v4 3/5] clk: add lpc18xx ccu clk driver
@ 2015-06-18 22:45 ` Michael Turquette
0 siblings, 0 replies; 30+ messages in thread
From: Michael Turquette @ 2015-06-18 22:45 UTC (permalink / raw)
To: linux-arm-kernel
Quoting Joachim Eastwood (2015-06-10 07:02:59)
> Hi Mike,
>
>
> > Hi Joachim,
> >
> > If it were me, I would have broken this up into two tables, one for each
> > CCU. In general I would structure the code to reflect the fact that two
> > different IP blocks are being accessed. This isn't a deal breaker but I
> > thought I would mention it in case you want to make the change.
> >
> > Otherwise this series looks good to me. Let me know if you plan a V5
> > submission.
>
> If there is still time for 4.2 and you don't have any more comments on
> how the driver uses the DT bindings I would rather send a follow up
> patch that splits the ccu table for 4.3.
>
>
> > I can take patches #1-4 into the clk tree. Please add my Acked-by to
> > patch #5. I will create an immutable branch to share with the arm-soc
> > tree so that they can take #5 and have access to the dt-bindings
> > headers.
>
> Sounds good. I'll talk to arm-soc team about it. But it isn't critical
> for me to get the DTS changes in for 4.2, but I would be very grateful
> for getting the drivers and headers in for 4.2 so that 4.3 is ready
> and doesn't have any header dependencies for all the driver DTS stuff.
Patches #1-4 applied to clk-next for 4.2.
Regards,
Mike
>
> Thanks, Mike.
>
>
> regards,
> Joachim Eastwood
^ permalink raw reply [flat|nested] 30+ messages in thread
* Re: [PATCH v4 3/5] clk: add lpc18xx ccu clk driver
2015-06-18 22:45 ` Michael Turquette
(?)
@ 2015-06-19 5:17 ` Joachim Eastwood
-1 siblings, 0 replies; 30+ messages in thread
From: Joachim Eastwood @ 2015-06-19 5:17 UTC (permalink / raw)
To: Michael Turquette
Cc: Stephen Boyd, linux-clk-u79uwXL29TY76Z2rM5mHXA,
devicetree-u79uwXL29TY76Z2rM5mHXA,
linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r
On 19 June 2015 at 00:45, Michael Turquette <mturquette-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org> wrote:
> Quoting Joachim Eastwood (2015-06-10 07:02:59)
>> Hi Mike,
>>
>>
>> > Hi Joachim,
>> >
>> > If it were me, I would have broken this up into two tables, one for each
>> > CCU. In general I would structure the code to reflect the fact that two
>> > different IP blocks are being accessed. This isn't a deal breaker but I
>> > thought I would mention it in case you want to make the change.
>> >
>> > Otherwise this series looks good to me. Let me know if you plan a V5
>> > submission.
>>
>> If there is still time for 4.2 and you don't have any more comments on
>> how the driver uses the DT bindings I would rather send a follow up
>> patch that splits the ccu table for 4.3.
>>
>>
>> > I can take patches #1-4 into the clk tree. Please add my Acked-by to
>> > patch #5. I will create an immutable branch to share with the arm-soc
>> > tree so that they can take #5 and have access to the dt-bindings
>> > headers.
>>
>> Sounds good. I'll talk to arm-soc team about it. But it isn't critical
>> for me to get the DTS changes in for 4.2, but I would be very grateful
>> for getting the drivers and headers in for 4.2 so that 4.3 is ready
>> and doesn't have any header dependencies for all the driver DTS stuff.
>
> Patches #1-4 applied to clk-next for 4.2.
Thanks a lot, Mike.
regards,
Joachim Eastwood
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply [flat|nested] 30+ messages in thread
* Re: [PATCH v4 3/5] clk: add lpc18xx ccu clk driver
@ 2015-06-19 5:17 ` Joachim Eastwood
0 siblings, 0 replies; 30+ messages in thread
From: Joachim Eastwood @ 2015-06-19 5:17 UTC (permalink / raw)
To: Michael Turquette; +Cc: Stephen Boyd, linux-clk, devicetree, linux-arm-kernel
On 19 June 2015 at 00:45, Michael Turquette <mturquette@linaro.org> wrote:
> Quoting Joachim Eastwood (2015-06-10 07:02:59)
>> Hi Mike,
>>
>>
>> > Hi Joachim,
>> >
>> > If it were me, I would have broken this up into two tables, one for each
>> > CCU. In general I would structure the code to reflect the fact that two
>> > different IP blocks are being accessed. This isn't a deal breaker but I
>> > thought I would mention it in case you want to make the change.
>> >
>> > Otherwise this series looks good to me. Let me know if you plan a V5
>> > submission.
>>
>> If there is still time for 4.2 and you don't have any more comments on
>> how the driver uses the DT bindings I would rather send a follow up
>> patch that splits the ccu table for 4.3.
>>
>>
>> > I can take patches #1-4 into the clk tree. Please add my Acked-by to
>> > patch #5. I will create an immutable branch to share with the arm-soc
>> > tree so that they can take #5 and have access to the dt-bindings
>> > headers.
>>
>> Sounds good. I'll talk to arm-soc team about it. But it isn't critical
>> for me to get the DTS changes in for 4.2, but I would be very grateful
>> for getting the drivers and headers in for 4.2 so that 4.3 is ready
>> and doesn't have any header dependencies for all the driver DTS stuff.
>
> Patches #1-4 applied to clk-next for 4.2.
Thanks a lot, Mike.
regards,
Joachim Eastwood
^ permalink raw reply [flat|nested] 30+ messages in thread
* [PATCH v4 3/5] clk: add lpc18xx ccu clk driver
@ 2015-06-19 5:17 ` Joachim Eastwood
0 siblings, 0 replies; 30+ messages in thread
From: Joachim Eastwood @ 2015-06-19 5:17 UTC (permalink / raw)
To: linux-arm-kernel
On 19 June 2015 at 00:45, Michael Turquette <mturquette@linaro.org> wrote:
> Quoting Joachim Eastwood (2015-06-10 07:02:59)
>> Hi Mike,
>>
>>
>> > Hi Joachim,
>> >
>> > If it were me, I would have broken this up into two tables, one for each
>> > CCU. In general I would structure the code to reflect the fact that two
>> > different IP blocks are being accessed. This isn't a deal breaker but I
>> > thought I would mention it in case you want to make the change.
>> >
>> > Otherwise this series looks good to me. Let me know if you plan a V5
>> > submission.
>>
>> If there is still time for 4.2 and you don't have any more comments on
>> how the driver uses the DT bindings I would rather send a follow up
>> patch that splits the ccu table for 4.3.
>>
>>
>> > I can take patches #1-4 into the clk tree. Please add my Acked-by to
>> > patch #5. I will create an immutable branch to share with the arm-soc
>> > tree so that they can take #5 and have access to the dt-bindings
>> > headers.
>>
>> Sounds good. I'll talk to arm-soc team about it. But it isn't critical
>> for me to get the DTS changes in for 4.2, but I would be very grateful
>> for getting the drivers and headers in for 4.2 so that 4.3 is ready
>> and doesn't have any header dependencies for all the driver DTS stuff.
>
> Patches #1-4 applied to clk-next for 4.2.
Thanks a lot, Mike.
regards,
Joachim Eastwood
^ permalink raw reply [flat|nested] 30+ messages in thread
end of thread, other threads:[~2015-06-19 5:17 UTC | newest]
Thread overview: 30+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2015-05-28 20:31 [PATCH v4 0/5] Clk drivers for NXP LPC18xx family Joachim Eastwood
2015-05-28 20:31 ` Joachim Eastwood
2015-05-28 20:31 ` Joachim Eastwood
[not found] ` <1432845107-12458-1-git-send-email-manabian-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
2015-05-28 20:31 ` [PATCH v4 1/5] clk: add lpc18xx cgu clk driver Joachim Eastwood
2015-05-28 20:31 ` Joachim Eastwood
2015-05-28 20:31 ` Joachim Eastwood
2015-05-28 20:31 ` [PATCH v4 2/5] doc: dt: add documentation for lpc1850-cgu " Joachim Eastwood
2015-05-28 20:31 ` Joachim Eastwood
2015-05-28 20:31 ` Joachim Eastwood
2015-05-28 20:31 ` [PATCH v4 3/5] clk: add lpc18xx ccu " Joachim Eastwood
2015-05-28 20:31 ` Joachim Eastwood
2015-05-28 20:31 ` Joachim Eastwood
[not found] ` <1432845107-12458-4-git-send-email-manabian-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
2015-06-10 2:13 ` Michael Turquette
2015-06-10 2:13 ` Michael Turquette
2015-06-10 2:13 ` Michael Turquette
2015-06-10 14:02 ` Joachim Eastwood
2015-06-10 14:02 ` Joachim Eastwood
2015-06-10 14:02 ` Joachim Eastwood
2015-06-18 22:45 ` Michael Turquette
2015-06-18 22:45 ` Michael Turquette
2015-06-18 22:45 ` Michael Turquette
2015-06-19 5:17 ` Joachim Eastwood
2015-06-19 5:17 ` Joachim Eastwood
2015-06-19 5:17 ` Joachim Eastwood
2015-05-28 20:31 ` [PATCH v4 4/5] doc: dt: add documentation for lpc1850-ccu " Joachim Eastwood
2015-05-28 20:31 ` Joachim Eastwood
2015-05-28 20:31 ` Joachim Eastwood
2015-05-28 20:31 ` [PATCH v4 5/5] ARM: dts: lpc18xx: add clock nodes for cgu and ccu Joachim Eastwood
2015-05-28 20:31 ` Joachim Eastwood
2015-05-28 20:31 ` Joachim Eastwood
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.