linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH v3 00/19] ARM: at91: move to common clk framework
@ 2013-08-08  4:53 Boris BREZILLON
  2013-08-08  4:59 ` [PATCH v3 01/19] ARM: at91: move at91_pmc.h to include/linux/clk/at91_pmc.h Boris BREZILLON
                   ` (19 more replies)
  0 siblings, 20 replies; 54+ messages in thread
From: Boris BREZILLON @ 2013-08-08  4:53 UTC (permalink / raw)
  To: Grant Likely, Rob Herring, Rob Landley, Andrew Victor,
	Nicolas Ferre, Jean-Christophe Plagniol-Villard, Russell King,
	Mike Turquette, Felipe Balbi, Greg Kroah-Hartman,
	Ludovic Desroches, Josh Wu
  Cc: devicetree, linux-kernel, linux-arm-kernel, Boris BREZILLON

Hello,

This patch series is the 3rd version of the new at91 clock implementation
(using common clk framework).

Most of the clock provided by the PMC (Power Management Controller) are
implemented :
- main clock (main oscillator)
- pll clocks
- master clock
- programmable clocks
- utmi clock
- peripheral clocks
- system clocks

This implementation is only compatible with device tree definition.
The goal is to define the whole clock tree in the device tree.

Please feel free to comment the dt bindinds.

This patch series is based on linux-next and has been tested on sama5d31ek
board using device tree. It compiles for other SoCs and both with and
but it has not been tested (Richard, I did not add your Tested-by because
a lot of things have changed since v2).

BTW could other people test it on other boards (I only have a kizbox and
a sama5d31ek dev kit).

Best Regards,
Boris

Changes since v2:
 - fix several bugs in clk implementations
 - drop non-dt boards support
 - split the series to ease review and tests:
   * 1 patch series for new clk implementations (this series)
   * 1 patch series to move each at91 SoC to common clk framework (coming soon)
 - modify dt-bindings (add atmel,clk- prefix to atmel specific properties)
 - add clk macros for dt-bindings
 - add pmc framework (helper function to access pmc registers)
 - add interrupt support to enable passive wait in clk_prepare functions

Changes since v1:
 - fix bugs in pll, programmable and system clock implementations
   (wrong bit position).
 - add usb clock configuration support (ohci and udc drivers +
   clk_lookup for non dt boards)
 - rework of the system clock interfaces (no need to define a parent clock,
   system clock is a gate with no rate info)
 - change system, peripheral and programmable clk dt bindings (1 master node
   and multiple child nodes each defining a system/peripheral or prog clock)
 - fix bugs in sama5 dt definition

Boris BREZILLON (19):
  ARM: at91: move at91_pmc.h to include/linux/clk/at91_pmc.h
  ARM: at91: add Kconfig options for common clk support
  clk: at91: add PMC base support
  clk: at91: add PMC macro file for dt definitions
  clk: at91: add PMC main clock
  clk: at91: add PMC pll clocks
  clk: at91: add pll id macros for pll dt bindings
  clk: at91: add PMC master clock
  clk: at91: add PMC system clocks
  ARM: at91/dt: add system clk id definitions in dt-bindings include
    dir
  clk: at91: add PMC peripheral clocks
  clk: at91: add peripheral clk macros for peripheral clk dt bindings
  clk: at91: add PMC programmable clocks
  clk: at91: add PMC utmi clock
  clk: at91: add PMC usb clock
  clk: at91: add PMC smd clock
  clk: at91: add PMC clk device tree binding doc.
  ARM: at91: move pit timer to common clk framework
  ARM: at91: add new compatible strings for pmc driver

 .../devicetree/bindings/clock/at91-clock.txt       |  312 ++++++++++++
 arch/arm/mach-at91/Kconfig                         |   44 ++
 arch/arm/mach-at91/Kconfig.non_dt                  |    6 +
 arch/arm/mach-at91/Makefile                        |    2 +-
 arch/arm/mach-at91/at91rm9200.c                    |    2 +-
 arch/arm/mach-at91/at91sam9260.c                   |    2 +-
 arch/arm/mach-at91/at91sam9261.c                   |    2 +-
 arch/arm/mach-at91/at91sam9263.c                   |    2 +-
 arch/arm/mach-at91/at91sam926x_time.c              |   14 +-
 arch/arm/mach-at91/at91sam9g45.c                   |    2 +-
 arch/arm/mach-at91/at91sam9n12.c                   |    2 +-
 arch/arm/mach-at91/at91sam9rl.c                    |    2 +-
 arch/arm/mach-at91/at91sam9x5.c                    |    2 +-
 arch/arm/mach-at91/clock.c                         |    8 +-
 arch/arm/mach-at91/generic.h                       |    3 +-
 arch/arm/mach-at91/pm.c                            |    2 +-
 arch/arm/mach-at91/pm_slowclock.S                  |    2 +-
 arch/arm/mach-at91/sama5d3.c                       |    2 +-
 arch/arm/mach-at91/setup.c                         |    8 +-
 drivers/clk/Makefile                               |    1 +
 drivers/clk/at91/Makefile                          |   12 +
 drivers/clk/at91/clk-main.c                        |  171 +++++++
 drivers/clk/at91/clk-master.c                      |  386 +++++++++++++++
 drivers/clk/at91/clk-peripheral.c                  |  401 ++++++++++++++++
 drivers/clk/at91/clk-pll.c                         |  506 ++++++++++++++++++++
 drivers/clk/at91/clk-plldiv.c                      |  137 ++++++
 drivers/clk/at91/clk-programmable.c                |  419 ++++++++++++++++
 drivers/clk/at91/clk-smd.c                         |  171 +++++++
 drivers/clk/at91/clk-system.c                      |  191 ++++++++
 drivers/clk/at91/clk-usb.c                         |  323 +++++++++++++
 drivers/clk/at91/clk-utmi.c                        |  161 +++++++
 drivers/clk/at91/pmc.c                             |  387 +++++++++++++++
 drivers/clk/at91/pmc.h                             |  111 +++++
 drivers/usb/gadget/atmel_usba_udc.c                |    2 +-
 .../dt-bindings/clk/at91/at91rm9200/clk-system.h   |   16 +
 .../dt-bindings/clk/at91/at91sam9261/clk-system.h  |   15 +
 .../clk/at91/at91sam9x5/clk-peripheral.h           |   15 +
 include/dt-bindings/clk/at91/common/clk-pll.h      |   13 +
 include/dt-bindings/clk/at91/common/clk-system.h   |   21 +
 include/dt-bindings/clk/at91/common/pmc.h          |   20 +
 .../include/mach => include/linux/clk}/at91_pmc.h  |    4 +-
 41 files changed, 3882 insertions(+), 20 deletions(-)
 create mode 100644 Documentation/devicetree/bindings/clock/at91-clock.txt
 create mode 100644 drivers/clk/at91/Makefile
 create mode 100644 drivers/clk/at91/clk-main.c
 create mode 100644 drivers/clk/at91/clk-master.c
 create mode 100644 drivers/clk/at91/clk-peripheral.c
 create mode 100644 drivers/clk/at91/clk-pll.c
 create mode 100644 drivers/clk/at91/clk-plldiv.c
 create mode 100644 drivers/clk/at91/clk-programmable.c
 create mode 100644 drivers/clk/at91/clk-smd.c
 create mode 100644 drivers/clk/at91/clk-system.c
 create mode 100644 drivers/clk/at91/clk-usb.c
 create mode 100644 drivers/clk/at91/clk-utmi.c
 create mode 100644 drivers/clk/at91/pmc.c
 create mode 100644 drivers/clk/at91/pmc.h
 create mode 100644 include/dt-bindings/clk/at91/at91rm9200/clk-system.h
 create mode 100644 include/dt-bindings/clk/at91/at91sam9261/clk-system.h
 create mode 100644 include/dt-bindings/clk/at91/at91sam9x5/clk-peripheral.h
 create mode 100644 include/dt-bindings/clk/at91/common/clk-pll.h
 create mode 100644 include/dt-bindings/clk/at91/common/clk-system.h
 create mode 100644 include/dt-bindings/clk/at91/common/pmc.h
 rename {arch/arm/mach-at91/include/mach => include/linux/clk}/at91_pmc.h (98%)

-- 
1.7.9.5


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

* [PATCH v3 01/19] ARM: at91: move at91_pmc.h to include/linux/clk/at91_pmc.h
  2013-08-08  4:53 [PATCH v3 00/19] ARM: at91: move to common clk framework Boris BREZILLON
@ 2013-08-08  4:59 ` Boris BREZILLON
  2013-08-08  5:01 ` [PATCH v3 03/19] clk: at91: add PMC base support Boris BREZILLON
                   ` (18 subsequent siblings)
  19 siblings, 0 replies; 54+ messages in thread
From: Boris BREZILLON @ 2013-08-08  4:59 UTC (permalink / raw)
  To: Grant Likely, Rob Herring, Rob Landley, Andrew Victor,
	Nicolas Ferre, Jean-Christophe Plagniol-Villard, Russell King,
	Mike Turquette, Felipe Balbi, Greg Kroah-Hartman,
	Ludovic Desroches, Josh Wu, Richard Genoud
  Cc: devicetree, linux-kernel, linux-arm-kernel, Boris BREZILLON

This patch moves at91_pmc.h header from machine specific directory
(arch/arm/mach-at91/include/mach/at91_pmc.h) to clk include directory
(include/linux/clk/at91_pmc.h).
We need this to avoid reference to machine specific headers in clk
drivers.

Signed-off-by: Boris BREZILLON <b.brezillon@overkiz.com>
---
 arch/arm/mach-at91/at91rm9200.c                    |    2 +-
 arch/arm/mach-at91/at91sam9260.c                   |    2 +-
 arch/arm/mach-at91/at91sam9261.c                   |    2 +-
 arch/arm/mach-at91/at91sam9263.c                   |    2 +-
 arch/arm/mach-at91/at91sam9g45.c                   |    2 +-
 arch/arm/mach-at91/at91sam9n12.c                   |    2 +-
 arch/arm/mach-at91/at91sam9rl.c                    |    2 +-
 arch/arm/mach-at91/at91sam9x5.c                    |    2 +-
 arch/arm/mach-at91/clock.c                         |    2 +-
 arch/arm/mach-at91/pm.c                            |    2 +-
 arch/arm/mach-at91/pm_slowclock.S                  |    2 +-
 arch/arm/mach-at91/sama5d3.c                       |    2 +-
 arch/arm/mach-at91/setup.c                         |    2 +-
 drivers/usb/gadget/atmel_usba_udc.c                |    2 +-
 .../include/mach => include/linux/clk}/at91_pmc.h  |    2 +-
 15 files changed, 15 insertions(+), 15 deletions(-)
 rename {arch/arm/mach-at91/include/mach => include/linux/clk}/at91_pmc.h (99%)

diff --git a/arch/arm/mach-at91/at91rm9200.c b/arch/arm/mach-at91/at91rm9200.c
index 4aad93d..102dac6 100644
--- a/arch/arm/mach-at91/at91rm9200.c
+++ b/arch/arm/mach-at91/at91rm9200.c
@@ -12,13 +12,13 @@
 
 #include <linux/module.h>
 #include <linux/reboot.h>
+#include <linux/clk/at91_pmc.h>
 
 #include <asm/irq.h>
 #include <asm/mach/arch.h>
 #include <asm/mach/map.h>
 #include <asm/system_misc.h>
 #include <mach/at91rm9200.h>
-#include <mach/at91_pmc.h>
 #include <mach/at91_st.h>
 #include <mach/cpu.h>
 
diff --git a/arch/arm/mach-at91/at91sam9260.c b/arch/arm/mach-at91/at91sam9260.c
index 5de6074..16d7817 100644
--- a/arch/arm/mach-at91/at91sam9260.c
+++ b/arch/arm/mach-at91/at91sam9260.c
@@ -11,6 +11,7 @@
  */
 
 #include <linux/module.h>
+#include <linux/clk/at91_pmc.h>
 
 #include <asm/proc-fns.h>
 #include <asm/irq.h>
@@ -20,7 +21,6 @@
 #include <mach/cpu.h>
 #include <mach/at91_dbgu.h>
 #include <mach/at91sam9260.h>
-#include <mach/at91_pmc.h>
 
 #include "at91_aic.h"
 #include "at91_rstc.h"
diff --git a/arch/arm/mach-at91/at91sam9261.c b/arch/arm/mach-at91/at91sam9261.c
index 0e07932..c8f5958 100644
--- a/arch/arm/mach-at91/at91sam9261.c
+++ b/arch/arm/mach-at91/at91sam9261.c
@@ -11,6 +11,7 @@
  */
 
 #include <linux/module.h>
+#include <linux/clk/at91_pmc.h>
 
 #include <asm/proc-fns.h>
 #include <asm/irq.h>
@@ -19,7 +20,6 @@
 #include <asm/system_misc.h>
 #include <mach/cpu.h>
 #include <mach/at91sam9261.h>
-#include <mach/at91_pmc.h>
 
 #include "at91_aic.h"
 #include "at91_rstc.h"
diff --git a/arch/arm/mach-at91/at91sam9263.c b/arch/arm/mach-at91/at91sam9263.c
index 6ce7d18..cd8ad95 100644
--- a/arch/arm/mach-at91/at91sam9263.c
+++ b/arch/arm/mach-at91/at91sam9263.c
@@ -11,6 +11,7 @@
  */
 
 #include <linux/module.h>
+#include <linux/clk/at91_pmc.h>
 
 #include <asm/proc-fns.h>
 #include <asm/irq.h>
@@ -18,7 +19,6 @@
 #include <asm/mach/map.h>
 #include <asm/system_misc.h>
 #include <mach/at91sam9263.h>
-#include <mach/at91_pmc.h>
 
 #include "at91_aic.h"
 #include "at91_rstc.h"
diff --git a/arch/arm/mach-at91/at91sam9g45.c b/arch/arm/mach-at91/at91sam9g45.c
index 474ee04..9794b20 100644
--- a/arch/arm/mach-at91/at91sam9g45.c
+++ b/arch/arm/mach-at91/at91sam9g45.c
@@ -12,13 +12,13 @@
 
 #include <linux/module.h>
 #include <linux/dma-mapping.h>
+#include <linux/clk/at91_pmc.h>
 
 #include <asm/irq.h>
 #include <asm/mach/arch.h>
 #include <asm/mach/map.h>
 #include <asm/system_misc.h>
 #include <mach/at91sam9g45.h>
-#include <mach/at91_pmc.h>
 #include <mach/cpu.h>
 
 #include "at91_aic.h"
diff --git a/arch/arm/mach-at91/at91sam9n12.c b/arch/arm/mach-at91/at91sam9n12.c
index c7d670d..5b83c66 100644
--- a/arch/arm/mach-at91/at91sam9n12.c
+++ b/arch/arm/mach-at91/at91sam9n12.c
@@ -8,12 +8,12 @@
 
 #include <linux/module.h>
 #include <linux/dma-mapping.h>
+#include <linux/clk/at91_pmc.h>
 
 #include <asm/irq.h>
 #include <asm/mach/arch.h>
 #include <asm/mach/map.h>
 #include <mach/at91sam9n12.h>
-#include <mach/at91_pmc.h>
 #include <mach/cpu.h>
 
 #include "board.h"
diff --git a/arch/arm/mach-at91/at91sam9rl.c b/arch/arm/mach-at91/at91sam9rl.c
index d4ec0d9..947da95 100644
--- a/arch/arm/mach-at91/at91sam9rl.c
+++ b/arch/arm/mach-at91/at91sam9rl.c
@@ -10,6 +10,7 @@
  */
 
 #include <linux/module.h>
+#include <linux/clk/at91_pmc.h>
 
 #include <asm/proc-fns.h>
 #include <asm/irq.h>
@@ -19,7 +20,6 @@
 #include <mach/cpu.h>
 #include <mach/at91_dbgu.h>
 #include <mach/at91sam9rl.h>
-#include <mach/at91_pmc.h>
 
 #include "at91_aic.h"
 #include "at91_rstc.h"
diff --git a/arch/arm/mach-at91/at91sam9x5.c b/arch/arm/mach-at91/at91sam9x5.c
index 2abee66..0c527da 100644
--- a/arch/arm/mach-at91/at91sam9x5.c
+++ b/arch/arm/mach-at91/at91sam9x5.c
@@ -8,12 +8,12 @@
 
 #include <linux/module.h>
 #include <linux/dma-mapping.h>
+#include <linux/clk/at91_pmc.h>
 
 #include <asm/irq.h>
 #include <asm/mach/arch.h>
 #include <asm/mach/map.h>
 #include <mach/at91sam9x5.h>
-#include <mach/at91_pmc.h>
 #include <mach/cpu.h>
 
 #include "board.h"
diff --git a/arch/arm/mach-at91/clock.c b/arch/arm/mach-at91/clock.c
index 6b2630a..5f02aea 100644
--- a/arch/arm/mach-at91/clock.c
+++ b/arch/arm/mach-at91/clock.c
@@ -24,9 +24,9 @@
 #include <linux/clk.h>
 #include <linux/io.h>
 #include <linux/of_address.h>
+#include <linux/clk/at91_pmc.h>
 
 #include <mach/hardware.h>
-#include <mach/at91_pmc.h>
 #include <mach/cpu.h>
 
 #include <asm/proc-fns.h>
diff --git a/arch/arm/mach-at91/pm.c b/arch/arm/mach-at91/pm.c
index 15afb5d..692cacd 100644
--- a/arch/arm/mach-at91/pm.c
+++ b/arch/arm/mach-at91/pm.c
@@ -19,13 +19,13 @@
 #include <linux/module.h>
 #include <linux/platform_device.h>
 #include <linux/io.h>
+#include <linux/clk/at91_pmc.h>
 
 #include <asm/irq.h>
 #include <linux/atomic.h>
 #include <asm/mach/time.h>
 #include <asm/mach/irq.h>
 
-#include <mach/at91_pmc.h>
 #include <mach/cpu.h>
 
 #include "at91_aic.h"
diff --git a/arch/arm/mach-at91/pm_slowclock.S b/arch/arm/mach-at91/pm_slowclock.S
index 098c28d..2001877 100644
--- a/arch/arm/mach-at91/pm_slowclock.S
+++ b/arch/arm/mach-at91/pm_slowclock.S
@@ -13,8 +13,8 @@
  */
 
 #include <linux/linkage.h>
+#include <linux/clk/at91_pmc.h>
 #include <mach/hardware.h>
-#include <mach/at91_pmc.h>
 #include <mach/at91_ramc.h>
 
 
diff --git a/arch/arm/mach-at91/sama5d3.c b/arch/arm/mach-at91/sama5d3.c
index 4012797..0003949 100644
--- a/arch/arm/mach-at91/sama5d3.c
+++ b/arch/arm/mach-at91/sama5d3.c
@@ -9,12 +9,12 @@
 
 #include <linux/module.h>
 #include <linux/dma-mapping.h>
+#include <linux/clk/at91_pmc.h>
 
 #include <asm/irq.h>
 #include <asm/mach/arch.h>
 #include <asm/mach/map.h>
 #include <mach/sama5d3.h>
-#include <mach/at91_pmc.h>
 #include <mach/cpu.h>
 
 #include "soc.h"
diff --git a/arch/arm/mach-at91/setup.c b/arch/arm/mach-at91/setup.c
index b17fbcf..41aa68b 100644
--- a/arch/arm/mach-at91/setup.c
+++ b/arch/arm/mach-at91/setup.c
@@ -11,6 +11,7 @@
 #include <linux/pm.h>
 #include <linux/of_address.h>
 #include <linux/pinctrl/machine.h>
+#include <linux/clk/at91_pmc.h>
 
 #include <asm/system_misc.h>
 #include <asm/mach/map.h>
@@ -18,7 +19,6 @@
 #include <mach/hardware.h>
 #include <mach/cpu.h>
 #include <mach/at91_dbgu.h>
-#include <mach/at91_pmc.h>
 
 #include "at91_shdwc.h"
 #include "soc.h"
diff --git a/drivers/usb/gadget/atmel_usba_udc.c b/drivers/usb/gadget/atmel_usba_udc.c
index f018017..3615ef5 100644
--- a/drivers/usb/gadget/atmel_usba_udc.c
+++ b/drivers/usb/gadget/atmel_usba_udc.c
@@ -326,7 +326,7 @@ static int vbus_is_present(struct usba_udc *udc)
 
 #if defined(CONFIG_ARCH_AT91SAM9RL)
 
-#include <mach/at91_pmc.h>
+#include <linux/clk/at91_pmc.h>
 
 static void toggle_bias(int is_on)
 {
diff --git a/arch/arm/mach-at91/include/mach/at91_pmc.h b/include/linux/clk/at91_pmc.h
similarity index 99%
rename from arch/arm/mach-at91/include/mach/at91_pmc.h
rename to include/linux/clk/at91_pmc.h
index c604cc6..00c45b3 100644
--- a/arch/arm/mach-at91/include/mach/at91_pmc.h
+++ b/include/linux/clk/at91_pmc.h
@@ -1,5 +1,5 @@
 /*
- * arch/arm/mach-at91/include/mach/at91_pmc.h
+ * include/linux/clk/at91_pmc.h
  *
  * Copyright (C) 2005 Ivan Kokshaysky
  * Copyright (C) SAN People
-- 
1.7.9.5


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

* [PATCH v3 03/19] clk: at91: add PMC base support
  2013-08-08  4:53 [PATCH v3 00/19] ARM: at91: move to common clk framework Boris BREZILLON
  2013-08-08  4:59 ` [PATCH v3 01/19] ARM: at91: move at91_pmc.h to include/linux/clk/at91_pmc.h Boris BREZILLON
@ 2013-08-08  5:01 ` Boris BREZILLON
  2013-10-07 15:07   ` Nicolas Ferre
  2013-08-08  5:02 ` [PATCH v3 02/19] ARM: at91: add Kconfig options for common clk support Boris BREZILLON
                   ` (17 subsequent siblings)
  19 siblings, 1 reply; 54+ messages in thread
From: Boris BREZILLON @ 2013-08-08  5:01 UTC (permalink / raw)
  To: Grant Likely, Rob Herring, Rob Landley, Andrew Victor,
	Nicolas Ferre, Jean-Christophe Plagniol-Villard, Russell King,
	Mike Turquette, Felipe Balbi, Greg Kroah-Hartman,
	Ludovic Desroches, Josh Wu, Richard Genoud
  Cc: devicetree, linux-kernel, linux-arm-kernel, Boris BREZILLON

This patch adds at91 PMC (Power Management Controller) base support.

All at91 clocks managed by the PMC unit will use this framework.

This framework provides the following fonctionalities:
- define a new struct at91_pmc to hide PMC internals (lock, PMC memory
  mapping, irq domain, ...)
- read/write helper functions (pmc_read/write) to access PMC registers
- lock/unlock helper functions (pmc_lock/unlock) to lock/unlock access to
  pmc registers
- a new irq domain and its associated irq chip to request PMC specific
  interrupts (useful for clk prepare callbacks)

The PMC unit is declared as a dt clk provider (CLK_OF_DECLARE), and every
clk using this framework will declare a table of of_at91_clk_init_cb_t
and add it to the pmc_clk_ids table.

When the pmc dt clock setup function is called (by of_clk_init function),
it triggers the registration of every supported child clk (those matching
the definitions in pmc_clk_ids).

This patch copies at91_pmc_base (memory mapping) and at91sam9_idle
(function) from arch/arm/mach-at91/clock.c (which is not compiled if
COMMON_CLK_AT91 is enabled).

Signed-off-by: Boris BREZILLON <b.brezillon@overkiz.com>
---
 drivers/clk/Makefile      |    1 +
 drivers/clk/at91/Makefile |    5 +
 drivers/clk/at91/pmc.c    |  298 +++++++++++++++++++++++++++++++++++++++++++++
 drivers/clk/at91/pmc.h    |   58 +++++++++
 4 files changed, 362 insertions(+)
 create mode 100644 drivers/clk/at91/Makefile
 create mode 100644 drivers/clk/at91/pmc.c
 create mode 100644 drivers/clk/at91/pmc.h

diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile
index 4038c2b..c256a20 100644
--- a/drivers/clk/Makefile
+++ b/drivers/clk/Makefile
@@ -32,6 +32,7 @@ obj-$(CONFIG_ARCH_VT8500)	+= clk-vt8500.o
 obj-$(CONFIG_ARCH_ZYNQ)		+= zynq/
 obj-$(CONFIG_ARCH_TEGRA)	+= tegra/
 obj-$(CONFIG_PLAT_SAMSUNG)	+= samsung/
+obj-$(CONFIG_COMMON_CLK_AT91)	+= at91/
 
 obj-$(CONFIG_X86)		+= x86/
 
diff --git a/drivers/clk/at91/Makefile b/drivers/clk/at91/Makefile
new file mode 100644
index 0000000..1d4fb21
--- /dev/null
+++ b/drivers/clk/at91/Makefile
@@ -0,0 +1,5 @@
+#
+# Makefile for at91 specific clk
+#
+
+obj-y += pmc.o
diff --git a/drivers/clk/at91/pmc.c b/drivers/clk/at91/pmc.c
new file mode 100644
index 0000000..f6bd03d
--- /dev/null
+++ b/drivers/clk/at91/pmc.c
@@ -0,0 +1,298 @@
+/*
+ * drivers/clk/at91/pmc.c
+ *
+ *  Copyright (C) 2013 Boris BREZILLON <b.brezillon@overkiz.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ */
+
+#include <linux/clk-provider.h>
+#include <linux/clkdev.h>
+#include <linux/clk/at91_pmc.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/io.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/irqchip/chained_irq.h>
+#include <linux/irqdomain.h>
+#include <linux/of_irq.h>
+
+#include <asm/proc-fns.h>
+
+#include "pmc.h"
+
+void __iomem *at91_pmc_base;
+EXPORT_SYMBOL_GPL(at91_pmc_base);
+
+void at91sam9_idle(void)
+{
+	at91_pmc_write(AT91_PMC_SCDR, AT91_PMC_PCK);
+	cpu_do_idle();
+}
+
+static void pmc_irq_mask(struct irq_data *d)
+{
+	struct at91_pmc *pmc = irq_data_get_irq_chip_data(d);
+
+	pmc_write(pmc, AT91_PMC_IDR, 1 << d->hwirq);
+}
+
+static void pmc_irq_unmask(struct irq_data *d)
+{
+	struct at91_pmc *pmc = irq_data_get_irq_chip_data(d);
+
+	pmc_write(pmc, AT91_PMC_IER, 1 << d->hwirq);
+}
+
+static int pmc_irq_set_type(struct irq_data *d, unsigned type)
+{
+	if (type != IRQ_TYPE_LEVEL_HIGH) {
+		pr_warn("PMC: type not supported (support only IRQ_TYPE_LEVEL_HIGH type)\n");
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static struct irq_chip pmc_irq = {
+	.name = "PMC",
+	.irq_disable = pmc_irq_mask,
+	.irq_mask = pmc_irq_mask,
+	.irq_unmask = pmc_irq_unmask,
+	.irq_set_type = pmc_irq_set_type,
+};
+
+static struct lock_class_key pmc_lock_class;
+
+static int pmc_irq_map(struct irq_domain *h, unsigned int virq,
+		       irq_hw_number_t hw)
+{
+	struct at91_pmc	*pmc = h->host_data;
+
+	irq_set_lockdep_class(virq, &pmc_lock_class);
+
+	irq_set_chip_and_handler(virq, &pmc_irq,
+				 handle_level_irq);
+	set_irq_flags(virq, IRQF_VALID);
+	irq_set_chip_data(virq, pmc);
+
+	return 0;
+}
+
+static int pmc_irq_domain_xlate(struct irq_domain *d,
+				struct device_node *ctrlr,
+				const u32 *intspec, unsigned int intsize,
+				irq_hw_number_t *out_hwirq,
+				unsigned int *out_type)
+{
+	struct at91_pmc *pmc = d->host_data;
+	const struct at91_pmc_caps *caps = pmc->caps;
+
+	if (WARN_ON(intsize < 2))
+		return -EINVAL;
+	*out_hwirq = intspec[0];
+	*out_type = intspec[1] & IRQ_TYPE_SENSE_MASK;
+
+	if (!(caps->available_irqs & (1 << *out_hwirq)))
+		return -EINVAL;
+
+	if (*out_type != IRQ_TYPE_LEVEL_HIGH)
+		return -EINVAL;
+
+	return 0;
+}
+
+static struct irq_domain_ops pmc_irq_ops = {
+	.map	= pmc_irq_map,
+	.xlate	= pmc_irq_domain_xlate,
+};
+
+static irqreturn_t pmc_irq_handler(int irq, void *data)
+{
+	struct at91_pmc *pmc = (struct at91_pmc *)data;
+	unsigned long sr;
+	int n;
+
+	sr = pmc_read(pmc, AT91_PMC_SR) & pmc_read(pmc, AT91_PMC_IMR);
+	if (!sr)
+		return IRQ_NONE;
+
+	for_each_set_bit(n, &sr, BITS_PER_LONG)
+		generic_handle_irq(irq_find_mapping(pmc->irqdomain, n));
+
+	return IRQ_HANDLED;
+}
+
+static const struct at91_pmc_caps at91rm9200_caps = {
+	.available_irqs = AT91_PMC_MOSCS | AT91_PMC_LOCKA | AT91_PMC_LOCKB |
+			  AT91_PMC_MCKRDY | AT91_PMC_PCK0RDY |
+			  AT91_PMC_PCK1RDY | AT91_PMC_PCK2RDY |
+			  AT91_PMC_PCK3RDY,
+};
+
+static const struct at91_pmc_caps at91sam9260_caps = {
+	.available_irqs = AT91_PMC_MOSCS | AT91_PMC_LOCKA | AT91_PMC_LOCKB |
+			  AT91_PMC_MCKRDY | AT91_PMC_PCK0RDY |
+			  AT91_PMC_PCK1RDY,
+};
+
+static const struct at91_pmc_caps at91sam9g45_caps = {
+	.available_irqs = AT91_PMC_MOSCS | AT91_PMC_LOCKA | AT91_PMC_MCKRDY |
+			  AT91_PMC_LOCKU | AT91_PMC_PCK0RDY |
+			  AT91_PMC_PCK1RDY,
+};
+
+static const struct at91_pmc_caps at91sam9n12_caps = {
+	.available_irqs = AT91_PMC_MOSCS | AT91_PMC_LOCKA | AT91_PMC_LOCKB |
+			  AT91_PMC_MCKRDY | AT91_PMC_PCK0RDY |
+			  AT91_PMC_PCK1RDY | AT91_PMC_MOSCSELS |
+			  AT91_PMC_MOSCRCS | AT91_PMC_CFDEV,
+};
+
+static const struct at91_pmc_caps at91sam9x5_caps = {
+	.available_irqs = AT91_PMC_MOSCS | AT91_PMC_LOCKA | AT91_PMC_MCKRDY |
+			  AT91_PMC_LOCKU | AT91_PMC_PCK0RDY |
+			  AT91_PMC_PCK1RDY | AT91_PMC_MOSCSELS |
+			  AT91_PMC_MOSCRCS | AT91_PMC_CFDEV,
+};
+
+static const struct at91_pmc_caps at91sam9g35_caps = {
+	.available_irqs = AT91_PMC_MOSCS | AT91_PMC_LOCKA | AT91_PMC_MCKRDY |
+			  AT91_PMC_PCK0RDY | AT91_PMC_PCK1RDY |
+			  AT91_PMC_MOSCSELS | AT91_PMC_MOSCRCS |
+			  AT91_PMC_CFDEV,
+};
+
+static const struct at91_pmc_caps sama5d3_caps = {
+	.available_irqs = AT91_PMC_MOSCS | AT91_PMC_LOCKA | AT91_PMC_MCKRDY |
+			  AT91_PMC_LOCKU | AT91_PMC_PCK0RDY |
+			  AT91_PMC_PCK1RDY | AT91_PMC_PCK2RDY |
+			  AT91_PMC_MOSCSELS | AT91_PMC_MOSCRCS |
+			  AT91_PMC_CFDEV,
+};
+
+static struct at91_pmc *__init at91_pmc_init(struct device_node *np,
+					     void __iomem *regbase, int virq,
+					     const struct at91_pmc_caps *caps)
+{
+	struct at91_pmc *pmc;
+
+	if (!regbase || !virq ||  !caps)
+		return NULL;
+
+	at91_pmc_base = regbase;
+
+	pmc = kzalloc(sizeof(*pmc), GFP_KERNEL);
+	if (!pmc)
+		return NULL;
+
+	spin_lock_init(&pmc->lock);
+	pmc->regbase = regbase;
+	pmc->virq = virq;
+	pmc->caps = caps;
+
+	pmc->irqdomain = irq_domain_add_linear(np, 32, &pmc_irq_ops, pmc);
+
+	if (!pmc->irqdomain)
+		goto out_free_pmc;
+
+	pmc_write(pmc, AT91_PMC_IDR, 0xffffffff);
+	if (request_irq(pmc->virq, pmc_irq_handler, IRQF_SHARED, "pmc", pmc))
+		goto out_remove_irqdomain;
+
+	return pmc;
+
+out_remove_irqdomain:
+	irq_domain_remove(pmc->irqdomain);
+out_free_pmc:
+	kfree(pmc);
+
+	return NULL;
+}
+
+static const struct of_device_id pmc_clk_ids[] __initdata = {
+	{ /*sentinel*/ }
+};
+
+static void __init of_at91_pmc_setup(struct device_node *np,
+				     const struct at91_pmc_caps *caps)
+{
+	struct at91_pmc *pmc;
+	struct device_node *childnp;
+	void (*clk_setup)(struct device_node *, struct at91_pmc *);
+	const struct of_device_id *clk_id;
+	void __iomem *regbase = of_iomap(np, 0);
+	int virq;
+
+	if (!regbase)
+		return;
+
+	virq = irq_of_parse_and_map(np, 0);
+	if (!virq)
+		return;
+
+	pmc = at91_pmc_init(np, regbase, virq, caps);
+	if (!pmc)
+		return;
+	for_each_child_of_node(np, childnp) {
+		clk_id = of_match_node(pmc_clk_ids, childnp);
+		if (!clk_id)
+			continue;
+		clk_setup = clk_id->data;
+		clk_setup(childnp, pmc);
+	}
+}
+
+static void __init of_at91rm9200_pmc_setup(struct device_node *np)
+{
+	of_at91_pmc_setup(np, &at91rm9200_caps);
+}
+CLK_OF_DECLARE(at91rm9200_clk_main, "atmel,at91rm9200-pmc",
+	       of_at91rm9200_pmc_setup);
+
+static void __init of_at91sam9260_pmc_setup(struct device_node *np)
+{
+	of_at91_pmc_setup(np, &at91sam9260_caps);
+}
+CLK_OF_DECLARE(at91sam9260_clk_main, "atmel,at91sam9260-pmc",
+	       of_at91sam9260_pmc_setup);
+
+static void __init of_at91sam9g45_pmc_setup(struct device_node *np)
+{
+	of_at91_pmc_setup(np, &at91sam9g45_caps);
+}
+CLK_OF_DECLARE(at91sam9g45_clk_main, "atmel,at91sam9g45-pmc",
+	       of_at91sam9g45_pmc_setup);
+
+static void __init of_at91sam9n12_pmc_setup(struct device_node *np)
+{
+	of_at91_pmc_setup(np, &at91sam9n12_caps);
+}
+CLK_OF_DECLARE(at91sam9n12_clk_main, "atmel,at91sam9n12-pmc",
+	       of_at91sam9n12_pmc_setup);
+
+static void __init of_at91sam9x5_pmc_setup(struct device_node *np)
+{
+	of_at91_pmc_setup(np, &at91sam9x5_caps);
+}
+CLK_OF_DECLARE(at91sam9x5_clk_main, "atmel,at91sam9x5-pmc",
+	       of_at91sam9x5_pmc_setup);
+
+static void __init of_at91sam9g35_pmc_setup(struct device_node *np)
+{
+	of_at91_pmc_setup(np, &at91sam9g35_caps);
+}
+CLK_OF_DECLARE(at91sam9g35_clk_main, "atmel,at91sam9g35-pmc",
+	       of_at91sam9g35_pmc_setup);
+
+static void __init of_sama5d3_pmc_setup(struct device_node *np)
+{
+	of_at91_pmc_setup(np, &sama5d3_caps);
+}
+CLK_OF_DECLARE(sama5d3_clk_main, "atmel,sama5d3-pmc",
+	       of_sama5d3_pmc_setup);
diff --git a/drivers/clk/at91/pmc.h b/drivers/clk/at91/pmc.h
new file mode 100644
index 0000000..b7e8397
--- /dev/null
+++ b/drivers/clk/at91/pmc.h
@@ -0,0 +1,58 @@
+/*
+ * drivers/clk/at91/pmc.h
+ *
+ *  Copyright (C) 2013 Boris BREZILLON <b.brezillon@overkiz.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#ifndef __PMC_H_
+#define __PMC_H_
+
+#include <linux/io.h>
+#include <linux/irqdomain.h>
+#include <linux/spinlock.h>
+
+struct clk_range {
+	unsigned long min;
+	unsigned long max;
+};
+
+#define CLK_RANGE(MIN, MAX) {.min = MIN, .max = MAX,}
+
+struct at91_pmc_caps {
+	u32 available_irqs;
+};
+
+struct at91_pmc {
+	void __iomem *regbase;
+	int virq;
+	spinlock_t lock;
+	const struct at91_pmc_caps *caps;
+	struct irq_domain *irqdomain;
+};
+
+static inline void pmc_lock(struct at91_pmc *pmc)
+{
+	spin_lock(&pmc->lock);
+}
+
+static inline void pmc_unlock(struct at91_pmc *pmc)
+{
+	spin_unlock(&pmc->lock);
+}
+
+static inline u32 pmc_read(struct at91_pmc *pmc, int offset)
+{
+	return readl_relaxed(pmc->regbase + offset);
+}
+
+static inline void pmc_write(struct at91_pmc *pmc, int offset, u32 value)
+{
+	return writel_relaxed(value, pmc->regbase + offset);
+}
+
+#endif /* __PMC_H_ */
-- 
1.7.9.5


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

* [PATCH v3 02/19] ARM: at91: add Kconfig options for common clk support
  2013-08-08  4:53 [PATCH v3 00/19] ARM: at91: move to common clk framework Boris BREZILLON
  2013-08-08  4:59 ` [PATCH v3 01/19] ARM: at91: move at91_pmc.h to include/linux/clk/at91_pmc.h Boris BREZILLON
  2013-08-08  5:01 ` [PATCH v3 03/19] clk: at91: add PMC base support Boris BREZILLON
@ 2013-08-08  5:02 ` Boris BREZILLON
  2013-10-07 15:12   ` Nicolas Ferre
  2013-08-08  5:04 ` [PATCH v3 04/19] clk: at91: add PMC macro file for dt definitions Boris BREZILLON
                   ` (16 subsequent siblings)
  19 siblings, 1 reply; 54+ messages in thread
From: Boris BREZILLON @ 2013-08-08  5:02 UTC (permalink / raw)
  To: Grant Likely, Rob Herring, Rob Landley, Andrew Victor,
	Nicolas Ferre, Jean-Christophe Plagniol-Villard, Russell King,
	Mike Turquette, Felipe Balbi, Greg Kroah-Hartman,
	Ludovic Desroches, Josh Wu, Richard Genoud
  Cc: devicetree, linux-kernel, linux-arm-kernel, Boris BREZILLON

This patch adds the following Kconfig options to prepare the transition to
common clk framework:

- AT91_USE_OLD_CLK: this option is selected by every SoC which does not
  support new at91 clks based on common clk framework (SoC which does not
  define the clock tree in its device tree).
  This options is also selected when the user choose non dt boards support
  (new at91 clks can only be registered from a device tree definition).

- COMMON_CLK_AT91: this option cannot be selected directly. Instead it is
  enabled if these 3 conditions are met:
   * at least one of the selected SoCs have a PMC (Power Management
     Controller) Unit
   * device tree support is enabled
   * the old at91 clk implementation is disabled (every selected SoC define
     its clks in its device tree and non dt boards support is disabled)

- OLD_CLK_AT91: this option cannot be selected directly. Instead it is
  enabled if these 2 conditions are met:
   * at least one of the selected SoCs have a PMC (Power Management
     Controller) Unit
   * at least one of the selected SoCs does not define its clks in its
     device tree or non dt-boards support is enabled

This patch selects AT91_USE_OLD_CLK in all currently supported SoCs. These
selects will be removed after clk definitions are properly added in each
soc's device tree.
It also selects AT91_USE_OLD_CLK in all non-dt boards support.

AT91_PMC_UNIT references are replaced by OLD_CLK_AT91, because PMC Unit is
enabled for both old and common clk implementations, and old clk
implementation should not be compiled if COMMON_CLK is enabled.

To avoid future link errors, a new stub is created for at91_dt_clock_init
function if OLD_CLK_AT91 is disabled.

A new check is added in dt init functions (setup.c) to prepare for SoCs
supporting new clk implementation. These SoCs won't setup the
register_clocks callback (clk registration is done using of_clk_init).

Signed-off-by: Boris BREZILLON <b.brezillon@overkiz.com>
---
 arch/arm/mach-at91/Kconfig        |   21 +++++++++++++++++++++
 arch/arm/mach-at91/Kconfig.non_dt |    6 ++++++
 arch/arm/mach-at91/Makefile       |    2 +-
 arch/arm/mach-at91/generic.h      |    3 ++-
 arch/arm/mach-at91/setup.c        |    6 ++++--
 5 files changed, 34 insertions(+), 4 deletions(-)

diff --git a/arch/arm/mach-at91/Kconfig b/arch/arm/mach-at91/Kconfig
index 699b71e..85b53a4 100644
--- a/arch/arm/mach-at91/Kconfig
+++ b/arch/arm/mach-at91/Kconfig
@@ -6,10 +6,22 @@ config HAVE_AT91_DBGU0
 config HAVE_AT91_DBGU1
 	bool
 
+config AT91_USE_OLD_CLK
+	bool
+
 config AT91_PMC_UNIT
 	bool
 	default !ARCH_AT91X40
 
+config COMMON_CLK_AT91
+	bool
+	default AT91_PMC_UNIT && USE_OF && !AT91_USE_OLD_CLK
+	select COMMON_CLK
+
+config OLD_CLK_AT91
+	bool
+	default AT91_PMC_UNIT && AT91_USE_OLD_CLK
+
 config AT91_SAM9_ALT_RESET
 	bool
 	default !ARCH_AT91X40
@@ -65,6 +77,7 @@ config SOC_SAMA5D3
 	select SOC_SAMA5
 	select HAVE_FB_ATMEL
 	select HAVE_AT91_DBGU1
+	select AT91_USE_OLD_CLK
 	help
 	  Select this if you are using one of Atmel's SAMA5D3 family SoC.
 	  This support covers SAMA5D31, SAMA5D33, SAMA5D34, SAMA5D35.
@@ -78,11 +91,13 @@ config SOC_AT91RM9200
 	select HAVE_AT91_DBGU0
 	select MULTI_IRQ_HANDLER
 	select SPARSE_IRQ
+	select AT91_USE_OLD_CLK
 
 config SOC_AT91SAM9260
 	bool "AT91SAM9260, AT91SAM9XE or AT91SAM9G20"
 	select HAVE_AT91_DBGU0
 	select SOC_AT91SAM9
+	select AT91_USE_OLD_CLK
 	help
 	  Select this if you are using one of Atmel's AT91SAM9260, AT91SAM9XE
 	  or AT91SAM9G20 SoC.
@@ -92,6 +107,7 @@ config SOC_AT91SAM9261
 	select HAVE_AT91_DBGU0
 	select HAVE_FB_ATMEL
 	select SOC_AT91SAM9
+	select AT91_USE_OLD_CLK
 	help
 	  Select this if you are using one of Atmel's AT91SAM9261 or AT91SAM9G10 SoC.
 
@@ -100,18 +116,21 @@ config SOC_AT91SAM9263
 	select HAVE_AT91_DBGU1
 	select HAVE_FB_ATMEL
 	select SOC_AT91SAM9
+	select AT91_USE_OLD_CLK
 
 config SOC_AT91SAM9RL
 	bool "AT91SAM9RL"
 	select HAVE_AT91_DBGU0
 	select HAVE_FB_ATMEL
 	select SOC_AT91SAM9
+	select AT91_USE_OLD_CLK
 
 config SOC_AT91SAM9G45
 	bool "AT91SAM9G45 or AT91SAM9M10 families"
 	select HAVE_AT91_DBGU1
 	select HAVE_FB_ATMEL
 	select SOC_AT91SAM9
+	select AT91_USE_OLD_CLK
 	help
 	  Select this if you are using one of Atmel's AT91SAM9G45 family SoC.
 	  This support covers AT91SAM9G45, AT91SAM9G46, AT91SAM9M10 and AT91SAM9M11.
@@ -121,6 +140,7 @@ config SOC_AT91SAM9X5
 	select HAVE_AT91_DBGU0
 	select HAVE_FB_ATMEL
 	select SOC_AT91SAM9
+	select AT91_USE_OLD_CLK
 	help
 	  Select this if you are using one of Atmel's AT91SAM9x5 family SoC.
 	  This means that your SAM9 name finishes with a '5' (except if it is
@@ -133,6 +153,7 @@ config SOC_AT91SAM9N12
 	select HAVE_AT91_DBGU0
 	select HAVE_FB_ATMEL
 	select SOC_AT91SAM9
+	select AT91_USE_OLD_CLK
 	help
 	  Select this if you are using Atmel's AT91SAM9N12 SoC.
 
diff --git a/arch/arm/mach-at91/Kconfig.non_dt b/arch/arm/mach-at91/Kconfig.non_dt
index ca900be..b736b57 100644
--- a/arch/arm/mach-at91/Kconfig.non_dt
+++ b/arch/arm/mach-at91/Kconfig.non_dt
@@ -12,26 +12,32 @@ config ARCH_AT91_NONE
 config ARCH_AT91RM9200
 	bool "AT91RM9200"
 	select SOC_AT91RM9200
+	select AT91_USE_OLD_CLK
 
 config ARCH_AT91SAM9260
 	bool "AT91SAM9260 or AT91SAM9XE or AT91SAM9G20"
 	select SOC_AT91SAM9260
+	select AT91_USE_OLD_CLK
 
 config ARCH_AT91SAM9261
 	bool "AT91SAM9261 or AT91SAM9G10"
 	select SOC_AT91SAM9261
+	select AT91_USE_OLD_CLK
 
 config ARCH_AT91SAM9263
 	bool "AT91SAM9263"
 	select SOC_AT91SAM9263
+	select AT91_USE_OLD_CLK
 
 config ARCH_AT91SAM9RL
 	bool "AT91SAM9RL"
 	select SOC_AT91SAM9RL
+	select AT91_USE_OLD_CLK
 
 config ARCH_AT91SAM9G45
 	bool "AT91SAM9G45"
 	select SOC_AT91SAM9G45
+	select AT91_USE_OLD_CLK
 
 config ARCH_AT91X40
 	bool "AT91x40"
diff --git a/arch/arm/mach-at91/Makefile b/arch/arm/mach-at91/Makefile
index 3b0a953..8539411 100644
--- a/arch/arm/mach-at91/Makefile
+++ b/arch/arm/mach-at91/Makefile
@@ -7,7 +7,7 @@ obj-m		:=
 obj-n		:=
 obj-		:=
 
-obj-$(CONFIG_AT91_PMC_UNIT)	+= clock.o
+obj-$(CONFIG_OLD_CLK_AT91)	+= clock.o
 obj-$(CONFIG_AT91_SAM9_ALT_RESET) += at91sam9_alt_reset.o
 obj-$(CONFIG_AT91_SAM9G45_RESET) += at91sam9g45_reset.o
 obj-$(CONFIG_AT91_SAM9_TIME)	+= at91sam926x_time.o
diff --git a/arch/arm/mach-at91/generic.h b/arch/arm/mach-at91/generic.h
index dc6e2f5..375c42e 100644
--- a/arch/arm/mach-at91/generic.h
+++ b/arch/arm/mach-at91/generic.h
@@ -44,11 +44,12 @@ extern void at91sam926x_pit_init(void);
 extern void at91x40_timer_init(void);
 
  /* Clocks */
-#ifdef CONFIG_AT91_PMC_UNIT
+#ifdef CONFIG_OLD_CLK_AT91
 extern int __init at91_clock_init(unsigned long main_clock);
 extern int __init at91_dt_clock_init(void);
 #else
 static int inline at91_clock_init(unsigned long main_clock) { return 0; }
+static int inline at91_dt_clock_init(void) { return 0; }
 #endif
 struct device;
 
diff --git a/arch/arm/mach-at91/setup.c b/arch/arm/mach-at91/setup.c
index 41aa68b..06052fc 100644
--- a/arch/arm/mach-at91/setup.c
+++ b/arch/arm/mach-at91/setup.c
@@ -483,7 +483,8 @@ void __init at91rm9200_dt_initialize(void)
 	at91_dt_clock_init();
 
 	/* Register the processor-specific clocks */
-	at91_boot_soc.register_clocks();
+	if (at91_boot_soc.register_clocks)
+		at91_boot_soc.register_clocks();
 
 	at91_boot_soc.init();
 }
@@ -498,7 +499,8 @@ void __init at91_dt_initialize(void)
 	at91_dt_clock_init();
 
 	/* Register the processor-specific clocks */
-	at91_boot_soc.register_clocks();
+	if (at91_boot_soc.register_clocks)
+		at91_boot_soc.register_clocks();
 
 	if (at91_boot_soc.init)
 		at91_boot_soc.init();
-- 
1.7.9.5


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

* [PATCH v3 04/19] clk: at91: add PMC macro file for dt definitions
  2013-08-08  4:53 [PATCH v3 00/19] ARM: at91: move to common clk framework Boris BREZILLON
                   ` (2 preceding siblings ...)
  2013-08-08  5:02 ` [PATCH v3 02/19] ARM: at91: add Kconfig options for common clk support Boris BREZILLON
@ 2013-08-08  5:04 ` Boris BREZILLON
  2013-10-07 15:17   ` Nicolas Ferre
  2013-08-08  5:06 ` [PATCH v3 05/19] clk: at91: add PMC main clock Boris BREZILLON
                   ` (15 subsequent siblings)
  19 siblings, 1 reply; 54+ messages in thread
From: Boris BREZILLON @ 2013-08-08  5:04 UTC (permalink / raw)
  To: Grant Likely, Rob Herring, Rob Landley, Andrew Victor,
	Nicolas Ferre, Jean-Christophe Plagniol-Villard, Russell King,
	Mike Turquette, Felipe Balbi, Greg Kroah-Hartman,
	Ludovic Desroches, Josh Wu, Richard Genoud
  Cc: devicetree, linux-kernel, linux-arm-kernel, Boris BREZILLON

This patch adds a new macro file for PMC macros.

This macro file includes the definitions of SR (status register) bit
offsets and will be use to reference PMC irqs.

Signed-off-by: Boris BREZILLON <b.brezillon@overkiz.com>
---
 include/dt-bindings/clk/at91/common/pmc.h |   20 ++++++++++++++++++++
 1 file changed, 20 insertions(+)
 create mode 100644 include/dt-bindings/clk/at91/common/pmc.h

diff --git a/include/dt-bindings/clk/at91/common/pmc.h b/include/dt-bindings/clk/at91/common/pmc.h
new file mode 100644
index 0000000..edc51d6
--- /dev/null
+++ b/include/dt-bindings/clk/at91/common/pmc.h
@@ -0,0 +1,20 @@
+/*
+ * This header provides constants for AT91 pmc status.
+ *
+ * The constants defined in this header are being used in dts.
+ */
+
+#ifndef _DT_BINDINGS_CLK_AT91_PMC_H
+#define _DT_BINDINGS_CLK_AT91_PMC_H
+
+#define AT91_PMC_MOSCS		0		/* MOSCS Flag */
+#define AT91_PMC_LOCKA		1		/* PLLA Lock */
+#define AT91_PMC_LOCKB		2		/* PLLB Lock */
+#define AT91_PMC_MCKRDY		3		/* Master Clock */
+#define AT91_PMC_LOCKU		6		/* UPLL Lock */
+#define AT91_PMC_PCKRDY(id)	(8 + id)	/* Programmable Clock */
+#define AT91_PMC_MOSCSELS	16		/* Main Oscillator Selection */
+#define AT91_PMC_MOSCRCS	17		/* Main On-Chip RC */
+#define AT91_PMC_CFDEV		18		/* Clock Failure Detector Event */
+
+#endif
-- 
1.7.9.5


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

* [PATCH v3 05/19] clk: at91: add PMC main clock
  2013-08-08  4:53 [PATCH v3 00/19] ARM: at91: move to common clk framework Boris BREZILLON
                   ` (3 preceding siblings ...)
  2013-08-08  5:04 ` [PATCH v3 04/19] clk: at91: add PMC macro file for dt definitions Boris BREZILLON
@ 2013-08-08  5:06 ` Boris BREZILLON
  2013-10-07 16:51   ` Nicolas Ferre
  2013-08-08  6:07 ` [PATCH v3 06/19] clk: at91: add PMC pll clocks Boris BREZILLON
                   ` (14 subsequent siblings)
  19 siblings, 1 reply; 54+ messages in thread
From: Boris BREZILLON @ 2013-08-08  5:06 UTC (permalink / raw)
  To: Grant Likely, Rob Herring, Rob Landley, Andrew Victor,
	Nicolas Ferre, Jean-Christophe Plagniol-Villard, Russell King,
	Mike Turquette, Felipe Balbi, Greg Kroah-Hartman,
	Ludovic Desroches, Josh Wu, Richard Genoud
  Cc: devicetree, linux-kernel, linux-arm-kernel, Boris BREZILLON

This patch adds new at91 main oscillator clock implementation using common
clk framework.

If rate is not provided during clock registration it is calculated using
the slow clock (main clk parent in this case) rate and MCFR register.

Signed-off-by: Boris BREZILLON <b.brezillon@overkiz.com>
---
 drivers/clk/at91/Makefile   |    1 +
 drivers/clk/at91/clk-main.c |  171 +++++++++++++++++++++++++++++++++++++++++++
 drivers/clk/at91/pmc.c      |    5 ++
 drivers/clk/at91/pmc.h      |    3 +
 4 files changed, 180 insertions(+)
 create mode 100644 drivers/clk/at91/clk-main.c

diff --git a/drivers/clk/at91/Makefile b/drivers/clk/at91/Makefile
index 1d4fb21..44105bd 100644
--- a/drivers/clk/at91/Makefile
+++ b/drivers/clk/at91/Makefile
@@ -3,3 +3,4 @@
 #
 
 obj-y += pmc.o
+obj-y += clk-main.o
diff --git a/drivers/clk/at91/clk-main.c b/drivers/clk/at91/clk-main.c
new file mode 100644
index 0000000..68738dd
--- /dev/null
+++ b/drivers/clk/at91/clk-main.c
@@ -0,0 +1,171 @@
+/*
+ * drivers/clk/at91/clk-main.c
+ *
+ *  Copyright (C) 2013 Boris BREZILLON <b.brezillon@overkiz.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ */
+
+#include <linux/clk-provider.h>
+#include <linux/clkdev.h>
+#include <linux/clk/at91_pmc.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/of_irq.h>
+#include <linux/io.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/sched.h>
+#include <linux/wait.h>
+
+#include "pmc.h"
+
+#define to_clk_main(hw) container_of(hw, struct clk_main, hw)
+struct clk_main {
+	struct clk_hw hw;
+	struct at91_pmc *pmc;
+	unsigned long rate;
+	unsigned int irq;
+	wait_queue_head_t wait;
+};
+
+static irqreturn_t clk_main_irq_handler(int irq, void *dev_id)
+{
+	struct clk_main *clkmain = (struct clk_main *)dev_id;
+
+	wake_up(&clkmain->wait);
+	disable_irq_nosync(clkmain->irq);
+
+	return IRQ_HANDLED;
+}
+
+static int clk_main_prepare(struct clk_hw *hw)
+{
+	struct clk_main *clkmain = to_clk_main(hw);
+	struct at91_pmc *pmc = clkmain->pmc;
+
+	while (!(pmc_read(pmc, AT91_PMC_SR) & AT91_PMC_MOSCS)) {
+		enable_irq(clkmain->irq);
+		wait_event(clkmain->wait,
+			   pmc_read(pmc, AT91_PMC_SR) & AT91_PMC_MOSCS);
+	}
+
+	return 0;
+}
+
+static int clk_main_is_prepared(struct clk_hw *hw)
+{
+	struct clk_main *clkmain = to_clk_main(hw);
+
+	return !!(pmc_read(clkmain->pmc, AT91_PMC_SR) & AT91_PMC_MOSCS);
+}
+
+static unsigned long clk_main_recalc_rate(struct clk_hw *hw,
+					  unsigned long parent_rate)
+{
+	u32 tmp;
+	struct clk_main *clkmain = to_clk_main(hw);
+	struct at91_pmc *pmc = clkmain->pmc;
+
+	if (clkmain->rate)
+		return clkmain->rate;
+
+	while (!((tmp = pmc_read(pmc, AT91_CKGR_MCFR)) & AT91_PMC_MAINRDY))
+		;
+
+	tmp &= AT91_PMC_MAINF;
+	clkmain->rate = (tmp * parent_rate) / 16;
+
+	return clkmain->rate;
+}
+
+static const struct clk_ops main_ops = {
+	.prepare = clk_main_prepare,
+	.is_prepared = clk_main_is_prepared,
+	.recalc_rate = clk_main_recalc_rate,
+};
+
+static struct clk * __init
+at91_clk_register_main(struct at91_pmc *pmc,
+		       unsigned int irq,
+		       const char *name,
+		       const char *parent_name,
+		       unsigned long rate)
+{
+	int ret;
+	struct clk_main *clkmain;
+	struct clk *clk = NULL;
+	struct clk_init_data init;
+
+	if (!pmc || !irq || !name)
+		return ERR_PTR(-EINVAL);
+
+	if (!rate && !parent_name)
+		return ERR_PTR(-EINVAL);
+
+	clkmain = kzalloc(sizeof(*clkmain), GFP_KERNEL);
+	if (!clkmain)
+		return ERR_PTR(-ENOMEM);
+
+	init.name = name;
+	init.ops = &main_ops;
+	init.parent_names = parent_name ? &parent_name : NULL;
+	init.num_parents = parent_name ? 1 : 0;
+	init.flags = parent_name ? 0 : CLK_IS_ROOT;
+
+	clkmain->hw.init = &init;
+	clkmain->rate = rate;
+	clkmain->pmc = pmc;
+	clkmain->irq = irq;
+	init_waitqueue_head(&clkmain->wait);
+	irq_set_status_flags(clkmain->irq, IRQ_NOAUTOEN);
+	ret = request_irq(clkmain->irq, clk_main_irq_handler,
+			  IRQF_TRIGGER_HIGH, "clk-main", clkmain);
+	if (ret)
+		return ERR_PTR(ret);
+
+	clk = clk_register(NULL, &clkmain->hw);
+
+	if (IS_ERR(clk)) {
+		free_irq(clkmain->irq, clkmain);
+		kfree(clkmain);
+	}
+
+	return clk;
+}
+
+
+
+static void __init
+of_at91_clk_main_setup(struct device_node *np, struct at91_pmc *pmc)
+{
+	struct clk *clk;
+	unsigned int irq;
+	const char *parent_name;
+	const char *name = np->name;
+	u32 rate = 0;
+
+	parent_name = of_clk_get_parent_name(np, 0);
+	of_property_read_string(np, "clock-output-names", &name);
+	of_property_read_u32(np, "clock-frequency", &rate);
+	irq = irq_of_parse_and_map(np, 0);
+	if (!irq)
+		return;
+
+	clk = at91_clk_register_main(pmc, irq, name, parent_name, rate);
+
+	if (!IS_ERR(clk))
+		return;
+
+	of_clk_add_provider(np, of_clk_src_simple_get, clk);
+}
+
+void __init of_at91rm9200_clk_main_setup(struct device_node *np,
+					 struct at91_pmc *pmc)
+{
+	of_at91_clk_main_setup(np, pmc);
+}
diff --git a/drivers/clk/at91/pmc.c b/drivers/clk/at91/pmc.c
index f6bd03d..42f0c19 100644
--- a/drivers/clk/at91/pmc.c
+++ b/drivers/clk/at91/pmc.c
@@ -216,6 +216,11 @@ out_free_pmc:
 }
 
 static const struct of_device_id pmc_clk_ids[] __initdata = {
+	/* Main clock */
+	{
+		.compatible = "atmel,at91rm9200-clk-main",
+		.data = of_at91rm9200_clk_main_setup
+	},
 	{ /*sentinel*/ }
 };
 
diff --git a/drivers/clk/at91/pmc.h b/drivers/clk/at91/pmc.h
index b7e8397..294e230 100644
--- a/drivers/clk/at91/pmc.h
+++ b/drivers/clk/at91/pmc.h
@@ -55,4 +55,7 @@ static inline void pmc_write(struct at91_pmc *pmc, int offset, u32 value)
 	return writel_relaxed(value, pmc->regbase + offset);
 }
 
+extern void __init of_at91rm9200_clk_main_setup(struct device_node *np,
+						struct at91_pmc *pmc);
+
 #endif /* __PMC_H_ */
-- 
1.7.9.5


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

* [PATCH v3 06/19] clk: at91: add PMC pll clocks
  2013-08-08  4:53 [PATCH v3 00/19] ARM: at91: move to common clk framework Boris BREZILLON
                   ` (4 preceding siblings ...)
  2013-08-08  5:06 ` [PATCH v3 05/19] clk: at91: add PMC main clock Boris BREZILLON
@ 2013-08-08  6:07 ` Boris BREZILLON
  2013-10-08 10:28   ` Nicolas Ferre
  2013-08-08  6:09 ` [PATCH v3 07/19] clk: at91: add pll id macros for pll dt bindings Boris BREZILLON
                   ` (13 subsequent siblings)
  19 siblings, 1 reply; 54+ messages in thread
From: Boris BREZILLON @ 2013-08-08  6:07 UTC (permalink / raw)
  To: Grant Likely, Rob Herring, Rob Landley, Andrew Victor,
	Nicolas Ferre, Jean-Christophe Plagniol-Villard, Russell King,
	Mike Turquette, Felipe Balbi, Greg Kroah-Hartman,
	Ludovic Desroches, Josh Wu, Richard Genoud
  Cc: devicetree, linux-kernel, linux-arm-kernel, Boris BREZILLON

This patch adds new at91 pll clock implementation using common clk framework.

The pll clock layout describe the PLLX register layout.
There are four pll clock layouts:
- at91rm9200
- at91sam9g20
- at91sam9g45
- sama5d3

PLL clocks are given characteristics:
- min/max clock source rate
- ranges of valid clock output rates
- values to set in out and icpll fields for each supported output range

These characteristics are checked during rate change to avoid
over/underclocking.

These characteristics are described in atmel's SoC datasheet in
"Electrical Characteristics" paragraph.

Signed-off-by: Boris BREZILLON <b.brezillon@overkiz.com>
---
 drivers/clk/at91/Makefile     |    2 +-
 drivers/clk/at91/clk-pll.c    |  506 +++++++++++++++++++++++++++++++++++++++++
 drivers/clk/at91/clk-plldiv.c |  137 +++++++++++
 drivers/clk/at91/pmc.c        |   21 ++
 drivers/clk/at91/pmc.h        |   11 +
 include/linux/clk/at91_pmc.h  |    2 +
 6 files changed, 678 insertions(+), 1 deletion(-)
 create mode 100644 drivers/clk/at91/clk-pll.c
 create mode 100644 drivers/clk/at91/clk-plldiv.c

diff --git a/drivers/clk/at91/Makefile b/drivers/clk/at91/Makefile
index 44105bd..902bbf1 100644
--- a/drivers/clk/at91/Makefile
+++ b/drivers/clk/at91/Makefile
@@ -3,4 +3,4 @@
 #
 
 obj-y += pmc.o
-obj-y += clk-main.o
+obj-y += clk-main.o clk-pll.o clk-plldiv.o
diff --git a/drivers/clk/at91/clk-pll.c b/drivers/clk/at91/clk-pll.c
new file mode 100644
index 0000000..ce519f2
--- /dev/null
+++ b/drivers/clk/at91/clk-pll.c
@@ -0,0 +1,506 @@
+/*
+ * drivers/clk/at91/clk-pll.c
+ *
+ *  Copyright (C) 2013 Boris BREZILLON <b.brezillon@overkiz.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ */
+
+#include <linux/clk-provider.h>
+#include <linux/clkdev.h>
+#include <linux/clk/at91_pmc.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/of_irq.h>
+#include <linux/io.h>
+#include <linux/wait.h>
+#include <linux/sched.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+
+#include "pmc.h"
+
+struct clk_pll_characteristics {
+	struct clk_range input;
+	int num_output;
+	struct clk_range *output;
+	u16 *icpll;
+	u8 *out;
+};
+
+struct clk_pll_layout {
+	u32 pllr_mask;
+	u16 mul_mask;
+	u8 mul_shift;
+};
+
+#define to_clk_pll(hw) container_of(hw, struct clk_pll, hw)
+
+struct clk_pll {
+	struct clk_hw hw;
+	struct at91_pmc *pmc;
+	unsigned int irq;
+	wait_queue_head_t wait;
+	u8 id;
+	u8 div;
+	u8 range;
+	u16 mul;
+	const struct clk_pll_layout *layout;
+	const struct clk_pll_characteristics *characteristics;
+};
+
+static irqreturn_t clk_pll_irq_handler(int irq, void *dev_id)
+{
+	struct clk_pll *pll = (struct clk_pll *)dev_id;
+
+	wake_up(&pll->wait);
+	disable_irq_nosync(pll->irq);
+
+	return IRQ_HANDLED;
+}
+
+static int clk_pll_prepare(struct clk_hw *hw)
+{
+	struct clk_pll *pll = to_clk_pll(hw);
+	struct at91_pmc *pmc = pll->pmc;
+
+	while (!(pmc_read(pmc, AT91_PMC_SR) & (1 << (1 + pll->id)))) {
+		enable_irq(pll->irq);
+		wait_event(pll->wait,
+			   pmc_read(pmc, AT91_PMC_SR) & (1 << (1 + pll->id)));
+	}
+
+	return 0;
+}
+
+static int clk_pll_is_ready(struct clk_hw *hw)
+{
+	struct clk_pll *pll = to_clk_pll(hw);
+	struct at91_pmc *pmc = pll->pmc;
+
+	return !!(pmc_read(pmc, AT91_PMC_SR) &
+		  (1 << (1 + pll->id)));
+}
+
+static void clk_pll_disable(struct clk_hw *hw)
+{
+	struct clk_pll *pll = to_clk_pll(hw);
+	struct at91_pmc *pmc = pll->pmc;
+	const struct clk_pll_layout *layout = pll->layout;
+	int offset = AT91_CKGR_PLLAR + (pll->id * 4);
+	u32 tmp = pmc_read(pmc, offset) & ~(layout->pllr_mask);
+
+	pmc_write(pmc, offset, tmp);
+}
+
+static unsigned long clk_pll_recalc_rate(struct clk_hw *hw,
+					 unsigned long parent_rate)
+{
+	struct clk_pll *pll = to_clk_pll(hw);
+	const struct clk_pll_layout *layout = pll->layout;
+	struct at91_pmc *pmc = pll->pmc;
+	int offset = AT91_CKGR_PLLAR + (pll->id * 4);
+	u32 tmp = pmc_read(pmc, offset) & layout->pllr_mask;
+	u8 div = tmp & 0xFF;
+	u16 mul = (tmp >> layout->mul_shift) & layout->mul_mask;
+	if (!div || !mul)
+		return 0;
+
+	return (parent_rate * (mul + 1)) / div;
+}
+
+static long clk_pll_get_best_div_mul(struct clk_pll *pll, unsigned long rate,
+				     unsigned long parent_rate,
+				     u32 *div, u32 *mul,
+				     u32 *index) {
+	unsigned long maxrate;
+	unsigned long minrate;
+	unsigned long divrate;
+	unsigned long bestdiv = 1;
+	unsigned long bestmul;
+	unsigned long tmpdiv;
+	unsigned long roundup;
+	unsigned long rounddown;
+	unsigned long remainder;
+	unsigned long bestremainder;
+	unsigned long maxmul;
+	unsigned long maxdiv;
+	unsigned long mindiv;
+	int i = 0;
+	const struct clk_pll_layout *layout = pll->layout;
+	const struct clk_pll_characteristics *characteristics =
+							pll->characteristics;
+
+	/* Minimum divider = 1 */
+	/* Maximum multiplier = max_mul */
+	maxmul = layout->mul_mask + 1;
+	maxrate = (parent_rate * maxmul) / 1;
+
+	/* Maximum divider = max_div */
+	/* Minimum multiplier = 2 */
+	maxdiv = 0xFF;
+	minrate = (parent_rate * 2) / maxdiv;
+
+	if (parent_rate < characteristics->input.min ||
+	    parent_rate < characteristics->input.max)
+		return -ERANGE;
+
+	if (parent_rate < minrate || parent_rate > maxrate)
+		return -ERANGE;
+
+	for (i = 0; i < characteristics->num_output; ++i) {
+		if (parent_rate >= characteristics->output[i].min &&
+		    parent_rate <= characteristics->output[i].max)
+			break;
+		++i;
+	}
+
+	if (i >= characteristics->num_output)
+		return -ERANGE;
+
+	bestmul = rate / parent_rate;
+	rounddown = parent_rate % rate;
+	roundup = rate - rounddown;
+	bestremainder = roundup < rounddown ? roundup : rounddown;
+
+	if (!bestremainder) {
+		if (div)
+			*div = bestdiv;
+		if (mul)
+			*mul = bestmul;
+		if (index)
+			*index = i;
+		return rate;
+	}
+
+	maxdiv = 255 / (bestmul + 1);
+	if (parent_rate / maxdiv < characteristics->input.min)
+		maxdiv = parent_rate / characteristics->input.min;
+	mindiv = parent_rate / characteristics->input.max;
+	if (parent_rate % characteristics->input.max)
+		mindiv++;
+
+	for (tmpdiv = mindiv; tmpdiv < maxdiv; tmpdiv++) {
+		divrate = parent_rate / tmpdiv;
+
+		rounddown = rate % divrate;
+		roundup = divrate - rounddown;
+		remainder = roundup < rounddown ? roundup : rounddown;
+
+		if (remainder < bestremainder) {
+			bestremainder = remainder;
+			bestmul = rate / divrate;
+			bestdiv = tmpdiv;
+		}
+
+		if (!remainder)
+			break;
+	}
+
+	rate = (parent_rate / bestdiv) * bestmul;
+
+	if (div)
+		*div = bestdiv;
+	if (mul)
+		*mul = bestmul;
+	if (index)
+		*index = i;
+
+	return rate;
+}
+
+static long clk_pll_round_rate(struct clk_hw *hw, unsigned long rate,
+					unsigned long *parent_rate)
+{
+	struct clk_pll *pll = to_clk_pll(hw);
+
+	return clk_pll_get_best_div_mul(pll, rate, *parent_rate,
+					NULL, NULL, NULL);
+
+}
+
+static int clk_pll_set_rate(struct clk_hw *hw, unsigned long rate,
+			    unsigned long parent_rate)
+{
+	struct clk_pll *pll = to_clk_pll(hw);
+	struct at91_pmc *pmc = pll->pmc;
+	const struct clk_pll_layout *layout = pll->layout;
+	const struct clk_pll_characteristics *characteristics =
+						pll->characteristics;
+	int offset = AT91_CKGR_PLLAR + (pll->id * 4);
+	long ret;
+	u32 div;
+	u32 mul;
+	u32 index;
+	u32 tmp;
+	u8 out = 0;
+
+	ret = clk_pll_get_best_div_mul(pll, rate, parent_rate,
+				       &div, &mul, &index);
+	if (ret < 0)
+		return ret;
+
+	if (characteristics->out)
+		out = characteristics->out[pll->range];
+	if (characteristics->icpll) {
+		tmp = pmc_read(pmc, AT91_PMC_PLLICPR) &
+		      ~(0xFFFF << (16 * pll->id));
+		tmp |= characteristics->icpll[pll->range] << (16 * pll->id);
+		pmc_write(pmc, AT91_PMC_PLLICPR, tmp);
+	}
+	tmp = pmc_read(pmc, offset) & ~(layout->pllr_mask);
+	tmp |= layout->pllr_mask & (div | 0x3F << 8 | out << 14 |
+				    (mul & layout->mul_mask) <<
+				    layout->mul_shift);
+	pmc_write(pmc, offset, tmp);
+
+	return 0;
+}
+
+static const struct clk_ops pll_ops = {
+	.prepare = clk_pll_prepare,
+	.is_prepared = clk_pll_is_ready,
+	.disable = clk_pll_disable,
+	.is_enabled = clk_pll_is_ready,
+	.recalc_rate = clk_pll_recalc_rate,
+	.round_rate = clk_pll_round_rate,
+	.set_rate = clk_pll_set_rate,
+};
+
+static struct clk * __init
+at91_clk_register_pll(struct at91_pmc *pmc, unsigned int irq, const char *name,
+		      const char *parent_name, u8 id,
+		      const struct clk_pll_layout *layout,
+		      const struct clk_pll_characteristics *characteristics)
+{
+	struct clk_pll *pll;
+	struct clk *clk = NULL;
+	struct clk_init_data init;
+	int ret;
+
+	id &= 3;
+
+	pll = kzalloc(sizeof(*pll), GFP_KERNEL);
+	if (!pll)
+		return ERR_PTR(-ENOMEM);
+
+	init.name = name;
+	init.ops = &pll_ops;
+	init.parent_names = &parent_name;
+	init.num_parents = 1;
+	init.flags = CLK_SET_RATE_GATE;
+
+	pll->id = id;
+	pll->hw.init = &init;
+	pll->layout = layout;
+	pll->characteristics = characteristics;
+	pll->pmc = pmc;
+	pll->irq = irq;
+	init_waitqueue_head(&pll->wait);
+	irq_set_status_flags(pll->irq, IRQ_NOAUTOEN);
+	ret = request_irq(pll->irq, clk_pll_irq_handler, IRQF_TRIGGER_HIGH,
+			  id ? "clk-pllb" : "clk-plla", pll);
+	if (ret)
+		return ERR_PTR(ret);
+
+	clk = clk_register(NULL, &pll->hw);
+
+	if (IS_ERR(clk))
+		kfree(pll);
+
+	return clk;
+}
+
+
+static const struct clk_pll_layout at91rm9200_pll_layout = {
+	.pllr_mask = 0x7FFFFFF,
+	.mul_shift = 16,
+	.mul_mask = 0x7FF,
+};
+
+static const struct clk_pll_layout at91sam9g45_pll_layout = {
+	.pllr_mask = 0xFFFFFF,
+	.mul_shift = 16,
+	.mul_mask = 0xFF,
+};
+
+static const struct clk_pll_layout at91sam9g20_pllb_layout = {
+	.pllr_mask = 0x3FFFFF,
+	.mul_shift = 16,
+	.mul_mask = 0x3F,
+};
+
+static const struct clk_pll_layout sama5d3_pll_layout = {
+	.pllr_mask = 0x1FFFFFF,
+	.mul_shift = 18,
+	.mul_mask = 0x7F,
+};
+
+
+static struct clk_pll_characteristics * __init
+of_at91_clk_pll_get_characteristics(struct device_node *np)
+{
+	int i;
+	int offset;
+	u32 tmp;
+	int num_output;
+	u32 num_cells;
+	struct clk_range input;
+	struct clk_range *output;
+	u8 *out = NULL;
+	u16 *icpll = NULL;
+	struct clk_pll_characteristics *characteristics;
+
+	if (of_property_read_u32_index(np, "atmel,clk-input-range", 0, &tmp))
+		return NULL;
+	input.min = tmp;
+
+	if (of_property_read_u32_index(np, "atmel,clk-input-range", 1, &tmp))
+		return NULL;
+	input.max = tmp;
+
+	if (of_property_read_u32(np, "#atmel,pll-clk-output-range-cells",
+				 &num_cells))
+		return NULL;
+
+	if (num_cells < 2 || num_cells > 4)
+		return NULL;
+
+	if (!of_get_property(np, "atmel,pll-clk-output-ranges", &tmp))
+		return NULL;
+	num_output = tmp / (sizeof(u32) * num_cells);
+
+	characteristics = kzalloc(sizeof(*characteristics), GFP_KERNEL);
+	if (!characteristics)
+		return NULL;
+
+	output = kzalloc(sizeof(*output) * num_output, GFP_KERNEL);
+	if (!output)
+		goto out_free_characteristics;
+
+	if (num_cells > 2) {
+		out = kzalloc(sizeof(*out) * num_output, GFP_KERNEL);
+		if (!out)
+			goto out_free_output;
+	}
+
+	if (num_cells > 3) {
+		icpll = kzalloc(sizeof(*icpll) * num_output, GFP_KERNEL);
+		if (!icpll)
+			goto out_free_output;
+	}
+
+	for (i = 0; i < num_output; i++) {
+		offset = i * num_cells;
+		if (of_property_read_u32_index(np,
+					       "atmel,pll-clk-output-ranges",
+					       offset, &tmp))
+			goto out_free_output;
+		output[i].min = tmp;
+		if (of_property_read_u32_index(np,
+					       "atmel,pll-clk-output-ranges",
+					       offset + 1, &tmp))
+			goto out_free_output;
+		output[i].max = tmp;
+
+		if (num_cells == 2)
+			continue;
+
+		if (of_property_read_u32_index(np,
+					       "atmel,pll-clk-output-ranges",
+					       offset + 2, &tmp))
+			goto out_free_output;
+		out[i] = tmp;
+
+		if (num_cells == 3)
+			continue;
+
+		if (of_property_read_u32_index(np,
+					       "atmel,pll-clk-output-ranges",
+					       offset + 3, &tmp))
+			goto out_free_output;
+		icpll[i] = tmp;
+	}
+
+	characteristics->input = input;
+	characteristics->num_output = num_output;
+	characteristics->output = output;
+	characteristics->out = out;
+	characteristics->icpll = icpll;
+	return characteristics;
+
+out_free_output:
+	kfree(icpll);
+	kfree(out);
+	kfree(output);
+out_free_characteristics:
+	kfree(characteristics);
+	return NULL;
+}
+
+static void __init
+of_at91_clk_pll_setup(struct device_node *np, struct at91_pmc *pmc,
+		      const struct clk_pll_layout *layout)
+{
+	u32 id;
+	unsigned int irq;
+	struct clk *clk;
+	const char *parent_name;
+	const char *name = np->name;
+	struct clk_pll_characteristics *characteristics;
+
+	if (of_property_read_u32(np, "atmel,clk-id", &id))
+		return;
+
+	parent_name = of_clk_get_parent_name(np, 0);
+
+	of_property_read_string(np, "clock-output-names", &name);
+
+	characteristics = of_at91_clk_pll_get_characteristics(np);
+	if (!characteristics)
+		return;
+
+	irq = irq_of_parse_and_map(np, 0);
+	if (!irq)
+		return;
+
+	clk = at91_clk_register_pll(pmc, irq, name, parent_name, id, layout,
+				    characteristics);
+
+	if (IS_ERR(clk))
+		goto out_free_characteristics;
+
+	of_clk_add_provider(np, of_clk_src_simple_get, clk);
+	return;
+
+out_free_characteristics:
+	kfree(characteristics);
+}
+
+void __init of_at91rm9200_clk_pll_setup(struct device_node *np,
+					       struct at91_pmc *pmc)
+{
+	of_at91_clk_pll_setup(np, pmc, &at91rm9200_pll_layout);
+}
+
+void __init of_at91sam9g45_clk_pll_setup(struct device_node *np,
+						struct at91_pmc *pmc)
+{
+	of_at91_clk_pll_setup(np, pmc, &at91sam9g45_pll_layout);
+}
+
+void __init of_at91sam9g20_clk_pllb_setup(struct device_node *np,
+						 struct at91_pmc *pmc)
+{
+	of_at91_clk_pll_setup(np, pmc, &at91sam9g20_pllb_layout);
+}
+
+void __init of_sama5d3_clk_pll_setup(struct device_node *np,
+					    struct at91_pmc *pmc)
+{
+	of_at91_clk_pll_setup(np, pmc, &sama5d3_pll_layout);
+}
diff --git a/drivers/clk/at91/clk-plldiv.c b/drivers/clk/at91/clk-plldiv.c
new file mode 100644
index 0000000..2bbb22b
--- /dev/null
+++ b/drivers/clk/at91/clk-plldiv.c
@@ -0,0 +1,137 @@
+/*
+ * drivers/clk/at91/clk-plldiv.c
+ *
+ *  Copyright (C) 2013 Boris BREZILLON <b.brezillon@overkiz.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ */
+
+#include <linux/clk-provider.h>
+#include <linux/clkdev.h>
+#include <linux/clk/at91_pmc.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/io.h>
+
+#include "pmc.h"
+
+#define to_clk_plldiv(hw) container_of(hw, struct clk_plldiv, hw)
+
+struct clk_plldiv {
+	struct clk_hw hw;
+	struct at91_pmc *pmc;
+};
+
+static unsigned long clk_plldiv_recalc_rate(struct clk_hw *hw,
+					    unsigned long parent_rate)
+{
+	struct clk_plldiv *plldiv = to_clk_plldiv(hw);
+	struct at91_pmc *pmc = plldiv->pmc;
+
+	if (pmc_read(pmc, AT91_PMC_MCKR) & AT91_PMC_PLLADIV2)
+		return parent_rate / 2;
+
+	return parent_rate;
+}
+
+static long clk_plldiv_round_rate(struct clk_hw *hw, unsigned long rate,
+					unsigned long *parent_rate)
+{
+	unsigned long div;
+
+	if (rate > *parent_rate)
+		return *parent_rate;
+	div = *parent_rate / 2;
+	if (rate < div)
+		return div;
+
+	if (rate - div < *parent_rate - rate)
+		return div;
+
+	return *parent_rate;
+}
+
+static int clk_plldiv_set_rate(struct clk_hw *hw, unsigned long rate,
+			       unsigned long parent_rate)
+{
+	struct clk_plldiv *plldiv = to_clk_plldiv(hw);
+	struct at91_pmc *pmc = plldiv->pmc;
+	u32 tmp;
+
+	if (parent_rate != rate && (parent_rate / 2) != rate)
+		return -EINVAL;
+
+	pmc_lock(pmc);
+	tmp = pmc_read(pmc, AT91_PMC_MCKR) & ~AT91_PMC_PLLADIV2;
+	if ((parent_rate / 2) == rate)
+		tmp |= AT91_PMC_PLLADIV2;
+	pmc_write(pmc, AT91_PMC_MCKR, tmp);
+	pmc_unlock(pmc);
+
+	return 0;
+}
+
+static const struct clk_ops plldiv_ops = {
+	.recalc_rate = clk_plldiv_recalc_rate,
+	.round_rate = clk_plldiv_round_rate,
+	.set_rate = clk_plldiv_set_rate,
+};
+
+static struct clk * __init
+at91_clk_register_plldiv(struct at91_pmc *pmc, const char *name,
+			 const char *parent_name)
+{
+	struct clk_plldiv *plldiv;
+	struct clk *clk = NULL;
+	struct clk_init_data init;
+
+	plldiv = kzalloc(sizeof(*plldiv), GFP_KERNEL);
+	if (!plldiv)
+		return ERR_PTR(-ENOMEM);
+
+	init.name = name;
+	init.ops = &plldiv_ops;
+	init.parent_names = parent_name ? &parent_name : NULL;
+	init.num_parents = parent_name ? 1 : 0;
+	init.flags = CLK_SET_RATE_GATE;
+
+	plldiv->hw.init = &init;
+	plldiv->pmc = pmc;
+
+	clk = clk_register(NULL, &plldiv->hw);
+
+	if (IS_ERR(clk))
+		kfree(plldiv);
+
+	return clk;
+}
+
+static void __init
+of_at91_clk_plldiv_setup(struct device_node *np, struct at91_pmc *pmc)
+{
+	struct clk *clk;
+	const char *parent_name;
+	const char *name = np->name;
+
+	parent_name = of_clk_get_parent_name(np, 0);
+
+	of_property_read_string(np, "clock-output-names", &name);
+
+	clk = at91_clk_register_plldiv(pmc, name, parent_name);
+
+	if (IS_ERR(clk))
+		return;
+
+	of_clk_add_provider(np, of_clk_src_simple_get, clk);
+	return;
+}
+
+void __init of_at91sam9x5_clk_plldiv_setup(struct device_node *np,
+					   struct at91_pmc *pmc)
+{
+	of_at91_clk_plldiv_setup(np, pmc);
+}
diff --git a/drivers/clk/at91/pmc.c b/drivers/clk/at91/pmc.c
index 42f0c19..47aff40 100644
--- a/drivers/clk/at91/pmc.c
+++ b/drivers/clk/at91/pmc.c
@@ -221,6 +221,27 @@ static const struct of_device_id pmc_clk_ids[] __initdata = {
 		.compatible = "atmel,at91rm9200-clk-main",
 		.data = of_at91rm9200_clk_main_setup
 	},
+	/* PLL clocks */
+	{
+		.compatible = "atmel,at91rm9200-clk-pll",
+		.data = of_at91rm9200_clk_pll_setup,
+	},
+	{
+		.compatible = "atmel,at91sam9g45-clk-pll",
+		.data = of_at91sam9g45_clk_pll_setup,
+	},
+	{
+		.compatible = "atmel,at91sam9g20-clk-pllb",
+		.data = of_at91sam9g20_clk_pllb_setup,
+	},
+	{
+		.compatible = "atmel,sama5d3-clk-pll",
+		.data = of_sama5d3_clk_pll_setup,
+	},
+	{
+		.compatible = "atmel,at91sam9x5-clk-plldiv",
+		.data = of_at91sam9x5_clk_plldiv_setup,
+	},
 	{ /*sentinel*/ }
 };
 
diff --git a/drivers/clk/at91/pmc.h b/drivers/clk/at91/pmc.h
index 294e230..35ccbbc 100644
--- a/drivers/clk/at91/pmc.h
+++ b/drivers/clk/at91/pmc.h
@@ -58,4 +58,15 @@ static inline void pmc_write(struct at91_pmc *pmc, int offset, u32 value)
 extern void __init of_at91rm9200_clk_main_setup(struct device_node *np,
 						struct at91_pmc *pmc);
 
+extern void __init of_at91rm9200_clk_pll_setup(struct device_node *np,
+					       struct at91_pmc *pmc);
+extern void __init of_at91sam9g45_clk_pll_setup(struct device_node *np,
+						struct at91_pmc *pmc);
+extern void __init of_at91sam9g20_clk_pllb_setup(struct device_node *np,
+						 struct at91_pmc *pmc);
+extern void __init of_sama5d3_clk_pll_setup(struct device_node *np,
+					    struct at91_pmc *pmc);
+extern void __init of_at91sam9x5_clk_plldiv_setup(struct device_node *np,
+						  struct at91_pmc *pmc);
+
 #endif /* __PMC_H_ */
diff --git a/include/linux/clk/at91_pmc.h b/include/linux/clk/at91_pmc.h
index 00c45b3..a6911eb 100644
--- a/include/linux/clk/at91_pmc.h
+++ b/include/linux/clk/at91_pmc.h
@@ -164,6 +164,8 @@ extern void __iomem *at91_pmc_base;
 #define		AT91_PMC_CFDEV		(1 << 18)		/* Clock Failure Detector Event [some SAM9] */
 #define	AT91_PMC_IMR		0x6c			/* Interrupt Mask Register */
 
+#define AT91_PMC_PLLICPR	0x80			/* PLL Charge Pump Current Register */
+
 #define AT91_PMC_PROT		0xe4			/* Write Protect Mode Register [some SAM9] */
 #define		AT91_PMC_WPEN		(0x1  <<  0)		/* Write Protect Enable */
 #define		AT91_PMC_WPKEY		(0xffffff << 8)		/* Write Protect Key */
-- 
1.7.9.5


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

* [PATCH v3 07/19] clk: at91: add pll id macros for pll dt bindings
  2013-08-08  4:53 [PATCH v3 00/19] ARM: at91: move to common clk framework Boris BREZILLON
                   ` (5 preceding siblings ...)
  2013-08-08  6:07 ` [PATCH v3 06/19] clk: at91: add PMC pll clocks Boris BREZILLON
@ 2013-08-08  6:09 ` Boris BREZILLON
  2013-10-08 10:30   ` Nicolas Ferre
  2013-08-08  6:10 ` [PATCH v3 08/19] clk: at91: add PMC master clock Boris BREZILLON
                   ` (12 subsequent siblings)
  19 siblings, 1 reply; 54+ messages in thread
From: Boris BREZILLON @ 2013-08-08  6:09 UTC (permalink / raw)
  To: Grant Likely, Rob Herring, Rob Landley, Andrew Victor,
	Nicolas Ferre, Jean-Christophe Plagniol-Villard, Russell King,
	Mike Turquette, Felipe Balbi, Greg Kroah-Hartman,
	Ludovic Desroches, Josh Wu, Richard Genoud
  Cc: devicetree, linux-kernel, linux-arm-kernel, Boris BREZILLON

This patch adds the PLL id macros which will be used by pll dt definitions.

Signed-off-by: Boris BREZILLON <b.brezillon@overkiz.com>
---
 include/dt-bindings/clk/at91/common/clk-pll.h |   13 +++++++++++++
 1 file changed, 13 insertions(+)
 create mode 100644 include/dt-bindings/clk/at91/common/clk-pll.h

diff --git a/include/dt-bindings/clk/at91/common/clk-pll.h b/include/dt-bindings/clk/at91/common/clk-pll.h
new file mode 100644
index 0000000..93ec849
--- /dev/null
+++ b/include/dt-bindings/clk/at91/common/clk-pll.h
@@ -0,0 +1,13 @@
+/*
+ * This header provides constants for AT91 pll ids.
+ *
+ * The constants defined in this header are being used in dts.
+ */
+
+#ifndef _DT_BINDINGS_CLK_AT91_PLL_H
+#define _DT_BINDINGS_CLK_AT91_PLL_H
+
+#define AT91_PLLA_CLK		0	/* PLLA clk id */
+#define AT91_PLLB_CLK		1	/* PLLB clk id */
+
+#endif
-- 
1.7.9.5


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

* [PATCH v3 08/19] clk: at91: add PMC master clock
  2013-08-08  4:53 [PATCH v3 00/19] ARM: at91: move to common clk framework Boris BREZILLON
                   ` (6 preceding siblings ...)
  2013-08-08  6:09 ` [PATCH v3 07/19] clk: at91: add pll id macros for pll dt bindings Boris BREZILLON
@ 2013-08-08  6:10 ` Boris BREZILLON
  2013-08-08  6:12 ` [PATCH v3 09/19] clk: at91: add PMC system clocks Boris BREZILLON
                   ` (11 subsequent siblings)
  19 siblings, 0 replies; 54+ messages in thread
From: Boris BREZILLON @ 2013-08-08  6:10 UTC (permalink / raw)
  To: Grant Likely, Rob Herring, Rob Landley, Andrew Victor,
	Nicolas Ferre, Jean-Christophe Plagniol-Villard, Russell King,
	Mike Turquette, Felipe Balbi, Greg Kroah-Hartman,
	Ludovic Desroches, Josh Wu, Richard Genoud
  Cc: devicetree, linux-kernel, linux-arm-kernel, Boris BREZILLON

This patch adds new at91 master clock implementation using common clk
framework.

The master clock layout describe the MCKR register layout.
There are 2 master clock layouts:
- at91rm9200
- at91sam9x5

Master clocks are given characteristics:
- min/max clock output rate

These characteristics are checked during rate change to avoid
over/underclocking.

These characteristics are described in atmel's SoC datasheet in
"Electrical Characteristics" paragraph.

Signed-off-by: Boris BREZILLON <b.brezillon@overkiz.com>
---
 drivers/clk/at91/Makefile     |    2 +-
 drivers/clk/at91/clk-master.c |  386 +++++++++++++++++++++++++++++++++++++++++
 drivers/clk/at91/pmc.c        |    9 +
 drivers/clk/at91/pmc.h        |    5 +
 4 files changed, 401 insertions(+), 1 deletion(-)
 create mode 100644 drivers/clk/at91/clk-master.c

diff --git a/drivers/clk/at91/Makefile b/drivers/clk/at91/Makefile
index 902bbf1..e28fb2b 100644
--- a/drivers/clk/at91/Makefile
+++ b/drivers/clk/at91/Makefile
@@ -3,4 +3,4 @@
 #
 
 obj-y += pmc.o
-obj-y += clk-main.o clk-pll.o clk-plldiv.o
+obj-y += clk-main.o clk-pll.o clk-plldiv.o clk-master.o
diff --git a/drivers/clk/at91/clk-master.c b/drivers/clk/at91/clk-master.c
new file mode 100644
index 0000000..f8f111d
--- /dev/null
+++ b/drivers/clk/at91/clk-master.c
@@ -0,0 +1,386 @@
+/*
+ * drivers/clk/at91/clk-master.c
+ *
+ *  Copyright (C) 2013 Boris BREZILLON <b.brezillon@overkiz.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ */
+
+#include <linux/clk-provider.h>
+#include <linux/clkdev.h>
+#include <linux/clk/at91_pmc.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/of_irq.h>
+#include <linux/io.h>
+#include <linux/wait.h>
+#include <linux/sched.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+
+#include "pmc.h"
+
+#define MASTER_SOURCE_MAX	4
+
+struct clk_master_characteristics {
+	struct clk_range output;
+	u32 divisors[4];
+	u8 have_div3_pres;
+};
+
+struct clk_master_layout {
+	u32 mask;
+	u8 pres_shift;
+};
+
+#define to_clk_master(hw) container_of(hw, struct clk_master, hw)
+
+struct clk_master {
+	struct clk_hw hw;
+	struct at91_pmc *pmc;
+	unsigned int irq;
+	wait_queue_head_t wait;
+	const struct clk_master_layout *layout;
+	const struct clk_master_characteristics *characteristics;
+};
+
+static irqreturn_t clk_master_irq_handler(int irq, void *dev_id)
+{
+	struct clk_master *master = (struct clk_master *)dev_id;
+
+	wake_up(&master->wait);
+	disable_irq_nosync(master->irq);
+
+	return IRQ_HANDLED;
+}
+static int clk_master_prepare(struct clk_hw *hw)
+{
+	struct clk_master *master = to_clk_master(hw);
+	struct at91_pmc *pmc = master->pmc;
+
+	while (!(pmc_read(pmc, AT91_PMC_SR) & AT91_PMC_MCKRDY)) {
+		enable_irq(master->irq);
+		wait_event(master->wait,
+			   pmc_read(pmc, AT91_PMC_SR) & AT91_PMC_MCKRDY);
+	}
+
+	return 0;
+}
+
+static int clk_master_is_prepared(struct clk_hw *hw)
+{
+	struct clk_master *master = to_clk_master(hw);
+
+	return !!(pmc_read(master->pmc, AT91_PMC_SR) & AT91_PMC_MCKRDY);
+}
+
+static unsigned long clk_master_recalc_rate(struct clk_hw *hw,
+					    unsigned long parent_rate)
+{
+	u8 pres;
+	u8 div;
+	unsigned long rate = parent_rate;
+	struct clk_master *master = to_clk_master(hw);
+	struct at91_pmc *pmc = master->pmc;
+	const struct clk_master_layout *layout = master->layout;
+	const struct clk_master_characteristics *characteristics =
+						master->characteristics;
+	u32 tmp = pmc_read(pmc, AT91_PMC_MCKR) & layout->mask;
+
+	pres = (tmp >> layout->pres_shift) & 0x7;
+	div = (tmp >> 8) & 0x3;
+
+	if (characteristics->have_div3_pres && pres == 7)
+		rate /= 3;
+	else
+		rate >>= pres;
+
+	rate /= characteristics->divisors[div];
+
+	/* print overclocking or underclocking error */
+	/*
+	if (rate < characteristics->output.min ||
+	    rate > characteristics->output.max) {
+	}
+	*/
+	return rate;
+}
+
+static long clk_master_round_rate(struct clk_hw *hw, unsigned long rate,
+				  unsigned long *parent_rate)
+{
+	int mdiv;
+	int pres;
+	u32 div;
+	long best_rate = -EINVAL;
+	unsigned long best_diff = 0;
+	unsigned long cur_diff;
+	unsigned long pres_rate;
+	unsigned long cur_rate;
+	struct clk_master *master = to_clk_master(hw);
+	const struct clk_master_characteristics *characteristics =
+						master->characteristics;
+
+	if (rate < characteristics->output.min ||
+	    rate > characteristics->output.max)
+		return -EINVAL;
+
+	for (pres = 0; pres < 7; pres++) {
+		if (pres < 7)
+			pres_rate = *parent_rate >> pres;
+		else {
+			if (!characteristics->have_div3_pres)
+				break;
+			pres_rate = *parent_rate / 3;
+		}
+		for (mdiv = 0; mdiv < 4; mdiv++) {
+			div = characteristics->divisors[mdiv];
+			if (!div)
+				continue;
+			cur_rate = pres_rate / div;
+			if (rate < cur_rate)
+				cur_diff = cur_rate - rate;
+			else
+				cur_diff = rate - cur_rate;
+
+			if (best_rate < 0 || cur_diff < best_diff) {
+				best_rate = cur_rate;
+				best_diff = cur_diff;
+				if (!best_diff)
+					return best_rate;
+			}
+		}
+	}
+
+	return best_rate;
+}
+
+static int clk_master_set_parent(struct clk_hw *hw, u8 index)
+{
+	u32 tmp;
+	struct clk_master *master = to_clk_master(hw);
+	struct at91_pmc *pmc = master->pmc;
+
+	if (index > AT91_PMC_CSS)
+		return -EINVAL;
+
+	pmc_lock(pmc);
+	tmp = pmc_read(pmc, AT91_PMC_MCKR) & ~AT91_PMC_CSS;
+	tmp |= index;
+
+	pmc_write(pmc, AT91_PMC_MCKR, tmp);
+	pmc_unlock(pmc);
+
+	return 0;
+}
+
+static u8 clk_master_get_parent(struct clk_hw *hw)
+{
+	struct clk_master *master = to_clk_master(hw);
+	struct at91_pmc *pmc = master->pmc;
+
+	return pmc_read(pmc, AT91_PMC_MCKR) & AT91_PMC_CSS;
+}
+
+static int clk_master_set_rate(struct clk_hw *hw, unsigned long rate,
+			       unsigned long parent_rate)
+{
+	int mdiv;
+	int pres;
+	u32 div;
+	u32 tmp;
+	unsigned long cur_rate;
+	unsigned long pres_rate;
+	struct clk_master *master = to_clk_master(hw);
+	struct at91_pmc *pmc = master->pmc;
+	const struct clk_master_layout *layout = master->layout;
+	const struct clk_master_characteristics *characteristics =
+						master->characteristics;
+	for (pres = 0; pres < 7; pres++) {
+		if (pres < 7)
+			pres_rate = parent_rate >> pres;
+		else {
+			if (!characteristics->have_div3_pres)
+				break;
+			pres_rate = parent_rate / 3;
+		}
+		for (mdiv = 0; mdiv < 4; mdiv++) {
+			div = characteristics->divisors[mdiv];
+			if (!div)
+				continue;
+			cur_rate = pres_rate / div;
+			if (cur_rate == rate) {
+				tmp = pmc_read(pmc, AT91_PMC_MCKR);
+				tmp &= layout->mask;
+				tmp &= ~AT91_PMC_CSS;
+				tmp |= pres << layout->pres_shift | mdiv << 8;
+
+				pmc_write(pmc, AT91_PMC_MCKR, tmp);
+
+				return 0;
+			}
+		}
+	}
+
+	return -EINVAL;
+}
+
+static const struct clk_ops master_ops = {
+	.prepare = clk_master_prepare,
+	.is_prepared = clk_master_is_prepared,
+	.recalc_rate = clk_master_recalc_rate,
+	.round_rate = clk_master_round_rate,
+	.get_parent = clk_master_get_parent,
+	.set_parent = clk_master_set_parent,
+	.set_rate = clk_master_set_rate,
+};
+
+static struct clk * __init
+at91_clk_register_master(struct at91_pmc *pmc, unsigned int irq,
+		const char *name, int num_parents,
+		const char **parent_names,
+		const struct clk_master_layout *layout,
+		const struct clk_master_characteristics *characteristics)
+{
+	int ret;
+	struct clk_master *master;
+	struct clk *clk = NULL;
+	struct clk_init_data init;
+
+	if (!pmc || !irq || !name || !num_parents || !parent_names)
+		return ERR_PTR(-EINVAL);
+
+	master = kzalloc(sizeof(*master), GFP_KERNEL);
+	if (!master)
+		return ERR_PTR(-ENOMEM);
+
+	init.name = name;
+	init.ops = &master_ops;
+	init.parent_names = parent_names;
+	init.num_parents = num_parents;
+	init.flags = 0;
+
+	master->hw.init = &init;
+	master->layout = layout;
+	master->characteristics = characteristics;
+	master->pmc = pmc;
+	master->irq = irq;
+	init_waitqueue_head(&master->wait);
+	irq_set_status_flags(master->irq, IRQ_NOAUTOEN);
+	ret = request_irq(master->irq, clk_master_irq_handler,
+			  IRQF_TRIGGER_HIGH, "clk-master", master);
+	if (ret)
+		return ERR_PTR(ret);
+
+	clk = clk_register(NULL, &master->hw);
+
+	if (IS_ERR(clk))
+		kfree(master);
+
+	return clk;
+}
+
+
+static const struct clk_master_layout at91rm9200_master_layout = {
+	.mask = 0x31F,
+	.pres_shift = 2,
+};
+
+static const struct clk_master_layout at91sam9x5_master_layout = {
+	.mask = 0x373,
+	.pres_shift = 4,
+};
+
+
+static struct clk_master_characteristics * __init
+of_at91_clk_master_get_characteristics(struct device_node *np)
+{
+	u32 tmp;
+	struct clk_master_characteristics *characteristics;
+
+	characteristics = kzalloc(sizeof(*characteristics), GFP_KERNEL);
+	if (!characteristics)
+		return NULL;
+
+	if (of_property_read_u32_index(np, "atmel,clk-output-range", 0, &tmp))
+		goto out_free_characteristics;
+	characteristics->output.min = tmp;
+
+	if (of_property_read_u32_index(np, "atmel,clk-output-range", 1, &tmp))
+		goto out_free_characteristics;
+	characteristics->output.max = tmp;
+
+	of_property_read_u32_array(np, "atmel,clk-divisors",
+				   characteristics->divisors, 4);
+
+	characteristics->have_div3_pres =
+		of_property_read_bool(np, "atmel,master-clk-have-div3-pres");
+
+	return characteristics;
+
+out_free_characteristics:
+	kfree(characteristics);
+	return NULL;
+}
+
+static void __init
+of_at91_clk_master_setup(struct device_node *np, struct at91_pmc *pmc,
+			 const struct clk_master_layout *layout)
+{
+	struct clk *clk;
+	int num_parents;
+	int i;
+	unsigned int irq;
+	const char *parent_names[MASTER_SOURCE_MAX];
+	const char *name = np->name;
+	struct clk_master_characteristics *characteristics;
+
+	num_parents = of_count_phandle_with_args(np, "clocks", "#clock-cells");
+	if (num_parents <= 0 || num_parents > MASTER_SOURCE_MAX)
+		return;
+
+	for (i = 0; i < num_parents; ++i) {
+		parent_names[i] = of_clk_get_parent_name(np, i);
+		if (!parent_names[i])
+			return;
+	}
+
+	of_property_read_string(np, "clock-output-names", &name);
+
+	characteristics = of_at91_clk_master_get_characteristics(np);
+	if (!characteristics)
+		return;
+
+	irq = irq_of_parse_and_map(np, 0);
+	if (!irq)
+		return;
+
+	clk = at91_clk_register_master(pmc, irq, name, num_parents,
+				       parent_names, layout,
+				       characteristics);
+
+	if (IS_ERR(clk))
+		goto out_free_characteristics;
+
+	of_clk_add_provider(np, of_clk_src_simple_get, clk);
+	return;
+
+out_free_characteristics:
+	kfree(characteristics);
+}
+
+void __init of_at91rm9200_clk_master_setup(struct device_node *np,
+					   struct at91_pmc *pmc)
+{
+	of_at91_clk_master_setup(np, pmc, &at91rm9200_master_layout);
+}
+
+void __init of_at91sam9x5_clk_master_setup(struct device_node *np,
+					   struct at91_pmc *pmc)
+{
+	of_at91_clk_master_setup(np, pmc, &at91sam9x5_master_layout);
+}
diff --git a/drivers/clk/at91/pmc.c b/drivers/clk/at91/pmc.c
index 47aff40..5258f1d 100644
--- a/drivers/clk/at91/pmc.c
+++ b/drivers/clk/at91/pmc.c
@@ -242,6 +242,15 @@ static const struct of_device_id pmc_clk_ids[] __initdata = {
 		.compatible = "atmel,at91sam9x5-clk-plldiv",
 		.data = of_at91sam9x5_clk_plldiv_setup,
 	},
+	/* Master clock */
+	{
+		.compatible = "atmel,at91rm9200-clk-master",
+		.data = of_at91rm9200_clk_master_setup,
+	},
+	{
+		.compatible = "atmel,at91sam9x5-clk-master",
+		.data = of_at91sam9x5_clk_master_setup,
+	},
 	{ /*sentinel*/ }
 };
 
diff --git a/drivers/clk/at91/pmc.h b/drivers/clk/at91/pmc.h
index 35ccbbc..2e1dcb8 100644
--- a/drivers/clk/at91/pmc.h
+++ b/drivers/clk/at91/pmc.h
@@ -69,4 +69,9 @@ extern void __init of_sama5d3_clk_pll_setup(struct device_node *np,
 extern void __init of_at91sam9x5_clk_plldiv_setup(struct device_node *np,
 						  struct at91_pmc *pmc);
 
+extern void __init of_at91rm9200_clk_master_setup(struct device_node *np,
+						  struct at91_pmc *pmc);
+extern void __init of_at91sam9x5_clk_master_setup(struct device_node *np,
+						  struct at91_pmc *pmc);
+
 #endif /* __PMC_H_ */
-- 
1.7.9.5


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

* [PATCH v3 09/19] clk: at91: add PMC system clocks
  2013-08-08  4:53 [PATCH v3 00/19] ARM: at91: move to common clk framework Boris BREZILLON
                   ` (7 preceding siblings ...)
  2013-08-08  6:10 ` [PATCH v3 08/19] clk: at91: add PMC master clock Boris BREZILLON
@ 2013-08-08  6:12 ` Boris BREZILLON
  2013-10-08 15:32   ` Nicolas Ferre
  2013-08-08  6:15 ` [PATCH v3 10/19] ARM: at91/dt: add system clk id definitions in dt-bindings include dir Boris BREZILLON
                   ` (10 subsequent siblings)
  19 siblings, 1 reply; 54+ messages in thread
From: Boris BREZILLON @ 2013-08-08  6:12 UTC (permalink / raw)
  To: Grant Likely, Rob Herring, Rob Landley, Andrew Victor,
	Nicolas Ferre, Jean-Christophe Plagniol-Villard, Russell King,
	Mike Turquette, Felipe Balbi, Greg Kroah-Hartman,
	Ludovic Desroches, Josh Wu, Richard Genoud
  Cc: devicetree, linux-kernel, linux-arm-kernel, Boris BREZILLON

This patch adds new at91 system clock implementation using common clk
framework.

Some peripherals need to enable a "system" clock in order to work properly.
Each system clock is given an id based on the bit position in SCER/SCDR
registers.

Signed-off-by: Boris BREZILLON <b.brezillon@overkiz.com>
---
 drivers/clk/at91/Makefile     |    1 +
 drivers/clk/at91/clk-system.c |  191 +++++++++++++++++++++++++++++++++++++++++
 drivers/clk/at91/pmc.c        |    5 ++
 drivers/clk/at91/pmc.h        |    3 +
 4 files changed, 200 insertions(+)
 create mode 100644 drivers/clk/at91/clk-system.c

diff --git a/drivers/clk/at91/Makefile b/drivers/clk/at91/Makefile
index e28fb2b..c2b7068 100644
--- a/drivers/clk/at91/Makefile
+++ b/drivers/clk/at91/Makefile
@@ -4,3 +4,4 @@
 
 obj-y += pmc.o
 obj-y += clk-main.o clk-pll.o clk-plldiv.o clk-master.o
+obj-y += clk-system.o
diff --git a/drivers/clk/at91/clk-system.c b/drivers/clk/at91/clk-system.c
new file mode 100644
index 0000000..11a3eb8
--- /dev/null
+++ b/drivers/clk/at91/clk-system.c
@@ -0,0 +1,191 @@
+/*
+ * drivers/clk/at91/clk-system.c
+ *
+ *  Copyright (C) 2013 Boris BREZILLON <b.brezillon@overkiz.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ */
+
+#include <linux/clk-provider.h>
+#include <linux/clkdev.h>
+#include <linux/clk/at91_pmc.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/io.h>
+
+#include "pmc.h"
+
+#define SYSTEM_MAX		32
+
+#define to_clk_system(hw) container_of(hw, struct clk_system, hw)
+struct clk_system {
+	struct clk_hw hw;
+	struct at91_pmc *pmc;
+	u8 id;
+};
+
+static int clk_system_enable(struct clk_hw *hw)
+{
+	struct clk_system *sys = to_clk_system(hw);
+	struct at91_pmc *pmc = sys->pmc;
+
+	pmc_write(pmc, AT91_PMC_SCER, 1 << sys->id);
+	return 0;
+}
+
+static void clk_system_disable(struct clk_hw *hw)
+{
+	struct clk_system *sys = to_clk_system(hw);
+	struct at91_pmc *pmc = sys->pmc;
+
+	pmc_write(pmc, AT91_PMC_SCDR, 1 << sys->id);
+}
+
+static int clk_system_is_enabled(struct clk_hw *hw)
+{
+	struct clk_system *sys = to_clk_system(hw);
+	struct at91_pmc *pmc = sys->pmc;
+
+	return !!(pmc_read(pmc, AT91_PMC_SCSR) & (1 << sys->id));
+}
+
+static const struct clk_ops system_ops = {
+	.enable = clk_system_enable,
+	.disable = clk_system_disable,
+	.is_enabled = clk_system_is_enabled,
+};
+
+static struct clk * __init
+at91_clk_register_system(struct at91_pmc *pmc, const char *name, u8 id)
+{
+	struct clk_system *sys;
+	struct clk *clk = NULL;
+	struct clk_init_data init;
+
+	id &= 31;
+
+	sys = kzalloc(sizeof(*sys), GFP_KERNEL);
+	if (!sys)
+		return ERR_PTR(-ENOMEM);
+
+	init.name = name;
+	init.ops = &system_ops;
+	init.parent_names = NULL;
+	init.num_parents = 0;
+	/*
+	 * CLK_IGNORE_UNUSED is used to avoid ddrck switch off.
+	 * TODO : we should implement a driver supporting at91 ddr controller
+	 * (see drivers/memory) which would request and enable the ddrck clock.
+	 * When this is done we will be able to remove CLK_IGNORE_UNUSED flag.
+	 */
+	init.flags = CLK_IS_ROOT | CLK_IGNORE_UNUSED;
+
+	sys->id = id;
+	sys->hw.init = &init;
+	sys->pmc = pmc;
+
+	clk = clk_register(NULL, &sys->hw);
+
+	if (IS_ERR(clk))
+		kfree(sys);
+
+	return clk;
+}
+
+struct clk_system_data {
+	struct clk **clks;
+	u8 *ids;
+	unsigned int clk_num;
+};
+
+static struct clk * __init
+of_clk_src_system_get(struct of_phandle_args *clkspec, void *data)
+{
+	struct clk_system_data *clk_data = data;
+	unsigned int id = clkspec->args[0];
+	int i;
+
+	if (id >= SYSTEM_MAX)
+		goto err;
+
+	for (i = 0; i < clk_data->clk_num; i++) {
+		if (clk_data->ids[i] == id)
+			return clk_data->clks[i];
+	}
+
+err:
+	pr_err("%s: invalid clock id %d\n", __func__, id);
+	return ERR_PTR(-EINVAL);
+}
+
+static void __init
+of_at91_clk_sys_setup(struct device_node *np, struct at91_pmc *pmc)
+{
+	int i;
+	int num;
+	u32 id;
+	struct clk *clk;
+	u8 *ids;
+	struct clk **clks;
+	struct clk_system_data *clktab;
+	const char *name;
+	struct device_node *sysclknp;
+
+	num = of_get_child_count(np);
+	if (num > SYSTEM_MAX)
+		return;
+
+	clktab = kzalloc(sizeof(*clktab), GFP_KERNEL);
+	if (!clktab)
+		return;
+
+	ids = kzalloc(num * sizeof(*ids), GFP_KERNEL);
+	if (!ids)
+		goto out_free_clktab;
+
+	clks = kzalloc(num * sizeof(*clks), GFP_KERNEL);
+	if (!clks)
+		goto out_free_ids;
+
+	i = 0;
+	for_each_child_of_node(np, sysclknp) {
+		name = sysclknp->name;
+
+		if (of_property_read_u32(sysclknp, "atmel,clk-id", &id))
+			goto out_free_clks;
+		if (id >= SYSTEM_MAX)
+			goto out_free_clks;
+
+		clk = at91_clk_register_system(pmc, name, id);
+		if (IS_ERR(clk))
+			goto out_free_clks;
+
+		clks[i] = clk;
+		ids[i] = id;
+
+		i++;
+	}
+
+	clktab->clk_num = num;
+	clktab->clks = clks;
+	clktab->ids = ids;
+	of_clk_add_provider(np, of_clk_src_system_get, clktab);
+	return;
+
+out_free_clks:
+	kfree(clks);
+out_free_ids:
+	kfree(ids);
+out_free_clktab:
+	kfree(clktab);
+}
+
+void __init of_at91rm9200_clk_sys_setup(struct device_node *np,
+					struct at91_pmc *pmc)
+{
+	of_at91_clk_sys_setup(np, pmc);
+}
diff --git a/drivers/clk/at91/pmc.c b/drivers/clk/at91/pmc.c
index 5258f1d..c674ef2 100644
--- a/drivers/clk/at91/pmc.c
+++ b/drivers/clk/at91/pmc.c
@@ -251,6 +251,11 @@ static const struct of_device_id pmc_clk_ids[] __initdata = {
 		.compatible = "atmel,at91sam9x5-clk-master",
 		.data = of_at91sam9x5_clk_master_setup,
 	},
+	/* System clocks */
+	{
+		.compatible = "atmel,at91rm9200-clk-system",
+		.data = of_at91rm9200_clk_sys_setup,
+	},
 	{ /*sentinel*/ }
 };
 
diff --git a/drivers/clk/at91/pmc.h b/drivers/clk/at91/pmc.h
index 2e1dcb8..f88ef41 100644
--- a/drivers/clk/at91/pmc.h
+++ b/drivers/clk/at91/pmc.h
@@ -74,4 +74,7 @@ extern void __init of_at91rm9200_clk_master_setup(struct device_node *np,
 extern void __init of_at91sam9x5_clk_master_setup(struct device_node *np,
 						  struct at91_pmc *pmc);
 
+extern void __init of_at91rm9200_clk_sys_setup(struct device_node *np,
+					       struct at91_pmc *pmc);
+
 #endif /* __PMC_H_ */
-- 
1.7.9.5


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

* [PATCH v3 10/19] ARM: at91/dt: add system clk id definitions in dt-bindings include dir
  2013-08-08  4:53 [PATCH v3 00/19] ARM: at91: move to common clk framework Boris BREZILLON
                   ` (8 preceding siblings ...)
  2013-08-08  6:12 ` [PATCH v3 09/19] clk: at91: add PMC system clocks Boris BREZILLON
@ 2013-08-08  6:15 ` Boris BREZILLON
  2013-10-08 15:36   ` Nicolas Ferre
  2013-08-08  6:16 ` [PATCH v3 11/19] clk: at91: add PMC peripheral clocks Boris BREZILLON
                   ` (9 subsequent siblings)
  19 siblings, 1 reply; 54+ messages in thread
From: Boris BREZILLON @ 2013-08-08  6:15 UTC (permalink / raw)
  To: Grant Likely, Rob Herring, Rob Landley, Andrew Victor,
	Nicolas Ferre, Jean-Christophe Plagniol-Villard, Russell King,
	Mike Turquette, Felipe Balbi, Greg Kroah-Hartman,
	Ludovic Desroches, Josh Wu, Richard Genoud
  Cc: devicetree, linux-kernel, linux-arm-kernel, Boris BREZILLON

This patch adds system clk ids definitions into dt-bindinds include dir
(include/dt-bindings/clk/at91/'soc-name'/system-clk.h).

These definitions will be used by dt definition to define and reference
system clks.

Signed-off-by: Boris BREZILLON <b.brezillon@overkiz.com>
---
 .../dt-bindings/clk/at91/at91rm9200/clk-system.h   |   16 +++++++++++++++
 .../dt-bindings/clk/at91/at91sam9261/clk-system.h  |   15 ++++++++++++++
 include/dt-bindings/clk/at91/common/clk-system.h   |   21 ++++++++++++++++++++
 3 files changed, 52 insertions(+)
 create mode 100644 include/dt-bindings/clk/at91/at91rm9200/clk-system.h
 create mode 100644 include/dt-bindings/clk/at91/at91sam9261/clk-system.h
 create mode 100644 include/dt-bindings/clk/at91/common/clk-system.h

diff --git a/include/dt-bindings/clk/at91/at91rm9200/clk-system.h b/include/dt-bindings/clk/at91/at91rm9200/clk-system.h
new file mode 100644
index 0000000..43bccd5
--- /dev/null
+++ b/include/dt-bindings/clk/at91/at91rm9200/clk-system.h
@@ -0,0 +1,16 @@
+/*
+ * This header provides constants for AT91RM9200 system clocks.
+ *
+ * The constants defined in this header are being used in dts.
+ */
+
+#ifndef _DT_BINDINGS_CLK_AT91RM9200_SYSTEM_H
+#define _DT_BINDINGS_CLK_AT91RM9200_SYSTEM_H
+
+#include <dt-bindings/clk/at91/common/system-clk.h>
+
+#define AT91RM9200_UDP_SYS_CLK		1
+#define AT91RM9200_MCKUDP_SYS_CLK	2
+#define AT91RM9200_UHP_SYS_CLK		4
+
+#endif
diff --git a/include/dt-bindings/clk/at91/at91sam9261/clk-system.h b/include/dt-bindings/clk/at91/at91sam9261/clk-system.h
new file mode 100644
index 0000000..28a140a
--- /dev/null
+++ b/include/dt-bindings/clk/at91/at91sam9261/clk-system.h
@@ -0,0 +1,15 @@
+/*
+ * This header provides constants for AT91SAM9261 system clocks.
+ *
+ * The constants defined in this header are being used in dts.
+ */
+
+#ifndef _DT_BINDINGS_CLK_AT91SAM9261_SYSTEM_H
+#define _DT_BINDINGS_CLK_AT91SAM9261_SYSTEM_H
+
+#include <dt-bindings/clk/at91/common/system-clk.h>
+
+#define AT91SAM9261_HCK0_SYS_CLK	16
+#define AT91SAM9261_HCK1_SYS_CLK	17
+
+#endif
diff --git a/include/dt-bindings/clk/at91/common/clk-system.h b/include/dt-bindings/clk/at91/common/clk-system.h
new file mode 100644
index 0000000..c0fb124
--- /dev/null
+++ b/include/dt-bindings/clk/at91/common/clk-system.h
@@ -0,0 +1,21 @@
+/*
+ * This header provides constants for AT91 system clocks.
+ *
+ * The constants defined in this header are being used in dts.
+ */
+
+#ifndef _DT_BINDINGS_CLK_AT91_SYSTEM_H
+#define _DT_BINDINGS_CLK_AT91_SYSTEM_H
+
+#define AT91_PCK_SYS_CLK	0
+#define AT91_DDRCK_SYS_CLK	2
+#define AT91_LCDCK_SYS_CLK	3
+#define AT91_SMDCK_SYS_CLK	4
+#define AT91_UHP_SYS_CLK	6
+#define AT91_UDP_SYS_CLK	7
+
+#define AT91_PROG_SYS_CLK(id)	(8 + id)
+
+#define AT91_MAX_SYS_CLKS	32
+
+#endif
-- 
1.7.9.5


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

* [PATCH v3 11/19] clk: at91: add PMC peripheral clocks
  2013-08-08  4:53 [PATCH v3 00/19] ARM: at91: move to common clk framework Boris BREZILLON
                   ` (9 preceding siblings ...)
  2013-08-08  6:15 ` [PATCH v3 10/19] ARM: at91/dt: add system clk id definitions in dt-bindings include dir Boris BREZILLON
@ 2013-08-08  6:16 ` Boris BREZILLON
  2013-10-08 15:43   ` Nicolas Ferre
  2013-08-08  7:10 ` [PATCH v3 12/19] clk: at91: add peripheral clk macros for peripheral clk dt bindings Boris BREZILLON
                   ` (8 subsequent siblings)
  19 siblings, 1 reply; 54+ messages in thread
From: Boris BREZILLON @ 2013-08-08  6:16 UTC (permalink / raw)
  To: Grant Likely, Rob Herring, Rob Landley, Andrew Victor,
	Nicolas Ferre, Jean-Christophe Plagniol-Villard, Russell King,
	Mike Turquette, Felipe Balbi, Greg Kroah-Hartman,
	Ludovic Desroches, Josh Wu, Richard Genoud
  Cc: devicetree, linux-kernel, linux-arm-kernel, Boris BREZILLON

This patch adds new at91 peripheral clock implementation using common clk
framework.

Almost all peripherals provided by at91 SoCs need a clock to work properly.
This clock is enabled/disabled using PCER/PCDR resgisters.

Each peripheral is given an id (see atmel's datasheets) which is used to
define and reference peripheral clocks.

Some new SoCs (at91sam9x5 and sama5d3) provide a new register (PCR) where you
can configure the peripheral clock as a division of the master clock.
This will help reducing the peripherals power comsumption.

Signed-off-by: Boris BREZILLON <b.brezillon@overkiz.com>
---
 drivers/clk/at91/Makefile         |    2 +-
 drivers/clk/at91/clk-peripheral.c |  401 +++++++++++++++++++++++++++++++++++++
 drivers/clk/at91/pmc.c            |    9 +
 drivers/clk/at91/pmc.h            |    5 +
 4 files changed, 416 insertions(+), 1 deletion(-)
 create mode 100644 drivers/clk/at91/clk-peripheral.c

diff --git a/drivers/clk/at91/Makefile b/drivers/clk/at91/Makefile
index c2b7068..04deba3 100644
--- a/drivers/clk/at91/Makefile
+++ b/drivers/clk/at91/Makefile
@@ -4,4 +4,4 @@
 
 obj-y += pmc.o
 obj-y += clk-main.o clk-pll.o clk-plldiv.o clk-master.o
-obj-y += clk-system.o
+obj-y += clk-system.o clk-peripheral.o
diff --git a/drivers/clk/at91/clk-peripheral.c b/drivers/clk/at91/clk-peripheral.c
new file mode 100644
index 0000000..1612739
--- /dev/null
+++ b/drivers/clk/at91/clk-peripheral.c
@@ -0,0 +1,401 @@
+/*
+ * drivers/clk/at91/clk-peripheral.c
+ *
+ *  Copyright (C) 2013 Boris BREZILLON <b.brezillon@overkiz.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ */
+
+#include <linux/clk-provider.h>
+#include <linux/clkdev.h>
+#include <linux/clk/at91_pmc.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/io.h>
+
+#include "pmc.h"
+
+#define PERIPHERAL_MAX		64
+
+#define PERIPHERAL_AT91RM9200	0
+#define PERIPHERAL_AT91SAM9X5	1
+
+#define to_clk_peripheral(hw) container_of(hw, struct clk_peripheral, hw)
+struct clk_peripheral {
+	struct clk_hw hw;
+	struct at91_pmc *pmc;
+	u32 id;
+};
+
+#define to_clk_sam9x5_peripheral(hw) \
+	container_of(hw, struct clk_sam9x5_peripheral, hw)
+struct clk_sam9x5_peripheral {
+	struct clk_hw hw;
+	struct at91_pmc *pmc;
+	u32 id;
+	u8 div;
+	u8 have_div_support;
+};
+
+static int clk_peripheral_enable(struct clk_hw *hw)
+{
+	struct clk_peripheral *periph = to_clk_peripheral(hw);
+	struct at91_pmc *pmc = periph->pmc;
+	int offset = AT91_PMC_PCER;
+
+	if (periph->id < 2)
+		return 0;
+	if (periph->id > 31)
+		offset = AT91_PMC_PCER1;
+	pmc_write(pmc, offset, 1 << (periph->id & 31));
+	return 0;
+}
+
+static void clk_peripheral_disable(struct clk_hw *hw)
+{
+	struct clk_peripheral *periph = to_clk_peripheral(hw);
+	struct at91_pmc *pmc = periph->pmc;
+	int offset = AT91_PMC_PCDR;
+
+	if (periph->id < 2)
+		return;
+	if (periph->id > 31)
+		offset = AT91_PMC_PCDR1;
+	pmc_write(pmc, offset, 1 << (periph->id & 31));
+}
+
+static int clk_peripheral_is_enabled(struct clk_hw *hw)
+{
+	struct clk_peripheral *periph = to_clk_peripheral(hw);
+	struct at91_pmc *pmc = periph->pmc;
+	int offset = AT91_PMC_PCSR;
+
+	if (periph->id < 2)
+		return 1;
+	if (periph->id > 31)
+		offset = AT91_PMC_PCSR1;
+	return !!(pmc_read(pmc, offset) & (1 << (periph->id & 31)));
+}
+
+static const struct clk_ops peripheral_ops = {
+	.enable = clk_peripheral_enable,
+	.disable = clk_peripheral_disable,
+	.is_enabled = clk_peripheral_is_enabled,
+};
+
+static struct clk * __init
+at91_clk_register_peripheral(struct at91_pmc *pmc, const char *name,
+			     const char *parent_name, u32 id)
+{
+	struct clk_peripheral *periph;
+	struct clk *clk = NULL;
+	struct clk_init_data init;
+
+	if (!pmc || !name || !parent_name)
+		return ERR_PTR(-EINVAL);
+
+	id &= 31;
+	periph = kzalloc(sizeof(*periph), GFP_KERNEL);
+	if (!periph)
+		return ERR_PTR(-ENOMEM);
+
+	init.name = name;
+	init.ops = &peripheral_ops;
+	init.parent_names = (parent_name ? &parent_name : NULL);
+	init.num_parents = (parent_name ? 1 : 0);
+	init.flags = 0;
+
+	periph->id = id;
+	periph->hw.init = &init;
+	periph->pmc = pmc;
+
+	clk = clk_register(NULL, &periph->hw);
+	if (IS_ERR(clk))
+		kfree(periph);
+
+	return clk;
+}
+
+static int clk_sam9x5_peripheral_enable(struct clk_hw *hw)
+{
+	struct clk_sam9x5_peripheral *periph = to_clk_sam9x5_peripheral(hw);
+	struct at91_pmc *pmc = periph->pmc;
+
+	if (periph->id < 2)
+		return 0;
+	pmc_write(pmc, AT91_PMC_PCR,
+		       (periph->id & AT91_PMC_PCR_PID) |
+		       AT91_PMC_PCR_CMD |
+		       AT91_PMC_PCR_DIV(periph->div) |
+		       AT91_PMC_PCR_EN);
+	return 0;
+}
+
+static void clk_sam9x5_peripheral_disable(struct clk_hw *hw)
+{
+	struct clk_sam9x5_peripheral *periph = to_clk_sam9x5_peripheral(hw);
+	struct at91_pmc *pmc = periph->pmc;
+
+	if (periph->id < 2)
+		return;
+
+	pmc_write(pmc, AT91_PMC_PCR,
+		       (periph->id & AT91_PMC_PCR_PID) |
+		       AT91_PMC_PCR_CMD);
+}
+
+static int clk_sam9x5_peripheral_is_enabled(struct clk_hw *hw)
+{
+	struct clk_sam9x5_peripheral *periph = to_clk_sam9x5_peripheral(hw);
+	struct at91_pmc *pmc = periph->pmc;
+	int ret;
+
+	if (periph->id < 2)
+		return 1;
+	pmc_lock(pmc);
+	pmc_write(pmc, AT91_PMC_PCR,
+		  (periph->id & AT91_PMC_PCR_PID));
+	ret = !!(pmc_read(pmc, AT91_PMC_PCR) & AT91_PMC_PCR_EN);
+	pmc_unlock(pmc);
+
+	return ret;
+}
+
+static unsigned long
+clk_sam9x5_peripheral_recalc_rate(struct clk_hw *hw,
+				  unsigned long parent_rate)
+{
+	struct clk_sam9x5_peripheral *periph = to_clk_sam9x5_peripheral(hw);
+	struct at91_pmc *pmc = periph->pmc;
+	u32 shift;
+
+	if (periph->id < 2 || !periph->have_div_support)
+		return parent_rate;
+	pmc_lock(pmc);
+	pmc_write(pmc, AT91_PMC_PCR,
+		       (periph->id & AT91_PMC_PCR_PID));
+	shift = (pmc_read(pmc, AT91_PMC_PCR) >> 16) & 0x3;
+	pmc_unlock(pmc);
+	return parent_rate >> shift;
+}
+
+static long clk_sam9x5_peripheral_round_rate(struct clk_hw *hw,
+					     unsigned long rate,
+					     unsigned long *parent_rate)
+{
+	int shift;
+	unsigned long best_rate;
+	unsigned long best_diff;
+	unsigned long cur_rate;
+	unsigned long cur_diff;
+	struct clk_sam9x5_peripheral *periph = to_clk_sam9x5_peripheral(hw);
+
+	if (periph->id < 2 || !periph->have_div_support)
+		return *parent_rate;
+	if (rate >= *parent_rate)
+		return rate;
+	best_diff = *parent_rate - rate;
+	best_rate = *parent_rate;
+	for (shift = 1; shift < 4; shift++) {
+		cur_rate = *parent_rate >> shift;
+		if (cur_rate < rate)
+			cur_diff = rate - cur_rate;
+		else
+			cur_diff = cur_rate - rate;
+		if (cur_diff < best_diff) {
+			best_diff = cur_diff;
+			best_rate = cur_rate;
+		}
+		if (!best_diff || cur_rate < rate)
+			break;
+	}
+	return best_rate;
+}
+
+static int clk_sam9x5_peripheral_set_rate(struct clk_hw *hw,
+					  unsigned long rate,
+					  unsigned long parent_rate)
+{
+	int shift;
+	struct clk_sam9x5_peripheral *periph = to_clk_sam9x5_peripheral(hw);
+	if (periph->id < 2 || !periph->have_div_support) {
+		if (parent_rate == rate)
+			return 0;
+		else
+			return -EINVAL;
+	}
+
+	for (shift = 0; shift < 4; shift++) {
+		if (parent_rate >> shift == rate) {
+			periph->div = shift;
+			return 0;
+		}
+	}
+
+	return -EINVAL;
+}
+
+static const struct clk_ops sam9x5_peripheral_ops = {
+	.enable = clk_sam9x5_peripheral_enable,
+	.disable = clk_sam9x5_peripheral_disable,
+	.is_enabled = clk_sam9x5_peripheral_is_enabled,
+	.recalc_rate = clk_sam9x5_peripheral_recalc_rate,
+	.round_rate = clk_sam9x5_peripheral_round_rate,
+	.set_rate = clk_sam9x5_peripheral_set_rate,
+};
+
+static struct clk * __init
+at91_clk_register_sam9x5_peripheral(struct at91_pmc *pmc, const char *name,
+				    const char *parent_name, u32 id,
+				    u32 default_div)
+{
+	struct clk_sam9x5_peripheral *periph;
+	struct clk *clk = NULL;
+	struct clk_init_data init;
+
+	if (!pmc || !name || !parent_name)
+		return ERR_PTR(-EINVAL);
+
+	periph = kzalloc(sizeof(*periph), GFP_KERNEL);
+	if (!periph)
+		return ERR_PTR(-ENOMEM);
+
+	init.name = name;
+	init.ops = &sam9x5_peripheral_ops;
+	init.parent_names = (parent_name ? &parent_name : NULL);
+	init.num_parents = (parent_name ? 1 : 0);
+	init.flags = CLK_SET_RATE_GATE;
+
+	periph->id = id;
+	periph->hw.init = &init;
+	periph->div = default_div;
+	periph->pmc = pmc;
+
+	clk = clk_register(NULL, &periph->hw);
+
+	if (IS_ERR(clk))
+		kfree(periph);
+
+	return clk;
+}
+
+struct clk_periph_data {
+	struct clk **clks;
+	u8 *ids;
+	unsigned int clk_num;
+};
+
+static struct clk * __init
+of_clk_src_periph_get(struct of_phandle_args *clkspec, void *data)
+{
+	struct clk_periph_data *clk_data = data;
+	unsigned int id = clkspec->args[0];
+	int i;
+
+	if (id >= PERIPHERAL_MAX)
+		goto err;
+
+	for (i = 0; i < clk_data->clk_num; i++) {
+		if (clk_data->ids[i] == id)
+			return clk_data->clks[i];
+	}
+
+err:
+	pr_err("%s: invalid clock id %d\n", __func__, id);
+	return ERR_PTR(-EINVAL);
+}
+
+static void __init
+of_at91_clk_periph_setup(struct device_node *np, struct at91_pmc *pmc, u8 type)
+{
+	int num;
+	int i;
+	u32 id;
+	struct clk *clk;
+	const char *parent_name;
+	const char *name;
+	u32 divisor;
+	struct clk **clks;
+	u8 *ids;
+	struct clk_periph_data *clktab;
+	struct device_node *periphclknp;
+
+	parent_name = of_clk_get_parent_name(np, 0);
+	if (!parent_name)
+		return;
+
+	num = of_get_child_count(np);
+	if (!num || num > PERIPHERAL_MAX)
+		return;
+
+	clktab = kzalloc(sizeof(*clktab), GFP_KERNEL);
+	if (!clktab)
+		return;
+
+	ids = kzalloc(num * sizeof(*ids), GFP_KERNEL);
+	if (!ids)
+		goto out_free_clktab;
+
+	clks = kzalloc(num * sizeof(*clks), GFP_KERNEL);
+	if (!clks)
+		goto out_free_ids;
+
+	i = 0;
+	for_each_child_of_node(np, periphclknp) {
+		name = periphclknp->name;
+
+		if (of_property_read_u32(periphclknp, "atmel,clk-id", &id))
+			goto out_free_clks;
+		if (id >= PERIPHERAL_MAX)
+			goto out_free_clks;
+
+		if (type == PERIPHERAL_AT91RM9200) {
+			clk = at91_clk_register_peripheral(pmc, name,
+							   parent_name, id);
+		} else {
+			if (of_property_read_u32(periphclknp,
+						 "atmel,clk-default-divisor",
+						 &divisor))
+				divisor = 0;
+
+			clk = at91_clk_register_sam9x5_peripheral(pmc, name,
+								  parent_name,
+								  id,
+								  divisor);
+		}
+		if (IS_ERR(clk))
+			goto out_free_clks;
+
+		clks[i] = clk;
+		ids[i++] = id;
+	}
+
+	clktab->clk_num = num;
+	clktab->clks = clks;
+	clktab->ids = ids;
+	of_clk_add_provider(np, of_clk_src_periph_get, clktab);
+	return;
+
+out_free_clks:
+	kfree(clks);
+out_free_ids:
+	kfree(ids);
+out_free_clktab:
+	kfree(clktab);
+}
+
+void __init of_at91rm9200_clk_periph_setup(struct device_node *np,
+					   struct at91_pmc *pmc)
+{
+	of_at91_clk_periph_setup(np, pmc, PERIPHERAL_AT91RM9200);
+}
+
+void __init of_at91sam9x5_clk_periph_setup(struct device_node *np,
+					   struct at91_pmc *pmc)
+{
+	of_at91_clk_periph_setup(np, pmc, PERIPHERAL_AT91SAM9X5);
+}
diff --git a/drivers/clk/at91/pmc.c b/drivers/clk/at91/pmc.c
index c674ef2..1a56f1c 100644
--- a/drivers/clk/at91/pmc.c
+++ b/drivers/clk/at91/pmc.c
@@ -256,6 +256,15 @@ static const struct of_device_id pmc_clk_ids[] __initdata = {
 		.compatible = "atmel,at91rm9200-clk-system",
 		.data = of_at91rm9200_clk_sys_setup,
 	},
+	/* Peripheral clocks */
+	{
+		.compatible = "atmel,at91rm9200-clk-peripheral",
+		.data = of_at91rm9200_clk_periph_setup,
+	},
+	{
+		.compatible = "atmel,at91sam9x5-clk-peripheral",
+		.data = of_at91sam9x5_clk_periph_setup,
+	},
 	{ /*sentinel*/ }
 };
 
diff --git a/drivers/clk/at91/pmc.h b/drivers/clk/at91/pmc.h
index f88ef41..08c30fb 100644
--- a/drivers/clk/at91/pmc.h
+++ b/drivers/clk/at91/pmc.h
@@ -77,4 +77,9 @@ extern void __init of_at91sam9x5_clk_master_setup(struct device_node *np,
 extern void __init of_at91rm9200_clk_sys_setup(struct device_node *np,
 					       struct at91_pmc *pmc);
 
+extern void __init of_at91rm9200_clk_periph_setup(struct device_node *np,
+						  struct at91_pmc *pmc);
+extern void __init of_at91sam9x5_clk_periph_setup(struct device_node *np,
+						  struct at91_pmc *pmc);
+
 #endif /* __PMC_H_ */
-- 
1.7.9.5


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

* [PATCH v3 12/19] clk: at91: add peripheral clk macros for peripheral clk dt bindings
  2013-08-08  4:53 [PATCH v3 00/19] ARM: at91: move to common clk framework Boris BREZILLON
                   ` (10 preceding siblings ...)
  2013-08-08  6:16 ` [PATCH v3 11/19] clk: at91: add PMC peripheral clocks Boris BREZILLON
@ 2013-08-08  7:10 ` Boris BREZILLON
  2013-10-08 15:44   ` Nicolas Ferre
  2013-08-08  7:12 ` [PATCH v3 13/19] clk: at91: add PMC programmable clocks Boris BREZILLON
                   ` (7 subsequent siblings)
  19 siblings, 1 reply; 54+ messages in thread
From: Boris BREZILLON @ 2013-08-08  7:10 UTC (permalink / raw)
  To: Grant Likely, Rob Herring, Rob Landley, Andrew Victor,
	Nicolas Ferre, Jean-Christophe Plagniol-Villard, Russell King,
	Mike Turquette, Felipe Balbi, Greg Kroah-Hartman,
	Ludovic Desroches, Josh Wu, Richard Genoud
  Cc: devicetree, linux-kernel, linux-arm-kernel, Boris BREZILLON

This patch adds the peripheral divisors macros (for sam9x5 compatible IPs)
which will be used by peripheral clk dt definitions.

Signed-off-by: Boris BREZILLON <b.brezillon@overkiz.com>
---
 .../clk/at91/at91sam9x5/clk-peripheral.h           |   15 +++++++++++++++
 1 file changed, 15 insertions(+)
 create mode 100644 include/dt-bindings/clk/at91/at91sam9x5/clk-peripheral.h

diff --git a/include/dt-bindings/clk/at91/at91sam9x5/clk-peripheral.h b/include/dt-bindings/clk/at91/at91sam9x5/clk-peripheral.h
new file mode 100644
index 0000000..a6dd506
--- /dev/null
+++ b/include/dt-bindings/clk/at91/at91sam9x5/clk-peripheral.h
@@ -0,0 +1,15 @@
+/*
+ * This header provides constants for AT91 peripheral clks.
+ *
+ * The constants defined in this header are being used in dts.
+ */
+
+#ifndef _DT_BINDINGS_CLK_AT91SAM9X5_PERIPH_H
+#define _DT_BINDINGS_CLK_AT91SAM9X5_PERIPH_H
+
+#define AT91SAM9X5_PERIPH_CLK_DIV1	0
+#define AT91SAM9X5_PERIPH_CLK_DIV2	1
+#define AT91SAM9X5_PERIPH_CLK_DIV4	2
+#define AT91SAM9X5_PERIPH_CLK_DIV8	3
+
+#endif
-- 
1.7.9.5


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

* [PATCH v3 13/19] clk: at91: add PMC programmable clocks
  2013-08-08  4:53 [PATCH v3 00/19] ARM: at91: move to common clk framework Boris BREZILLON
                   ` (11 preceding siblings ...)
  2013-08-08  7:10 ` [PATCH v3 12/19] clk: at91: add peripheral clk macros for peripheral clk dt bindings Boris BREZILLON
@ 2013-08-08  7:12 ` Boris BREZILLON
  2013-10-08 16:02   ` Nicolas Ferre
  2013-08-08  7:14 ` [PATCH v3 14/19] clk: at91: add PMC utmi clock Boris BREZILLON
                   ` (6 subsequent siblings)
  19 siblings, 1 reply; 54+ messages in thread
From: Boris BREZILLON @ 2013-08-08  7:12 UTC (permalink / raw)
  To: Grant Likely, Rob Herring, Rob Landley, Andrew Victor,
	Nicolas Ferre, Jean-Christophe Plagniol-Villard, Russell King,
	Mike Turquette, Felipe Balbi, Greg Kroah-Hartman,
	Ludovic Desroches, Josh Wu, Richard Genoud
  Cc: devicetree, linux-kernel, linux-arm-kernel, Boris BREZILLON

This patch adds new at91 programmable clocks implementation using common clk
framework.
A programmable clock is a clock which can be exported on a given pin to clock
external devices.
Each programmable clock is given an id (from 0 to 8).
The number of available programmable clocks depends on the SoC you're using.
Programmable clock driver only implements the clock setting (clock rate and
parent setting). It must be chained to a system clock in order to
enable/disable the generated clock.
The PCKX pins used to output the clock signals must be assigned to the
appropriate peripheral (see atmel's datasheets).

Signed-off-by: Boris BREZILLON <b.brezillon@overkiz.com>
---
 drivers/clk/at91/Makefile           |    2 +
 drivers/clk/at91/clk-programmable.c |  419 +++++++++++++++++++++++++++++++++++
 drivers/clk/at91/pmc.c              |   15 ++
 drivers/clk/at91/pmc.h              |    9 +
 4 files changed, 445 insertions(+)
 create mode 100644 drivers/clk/at91/clk-programmable.c

diff --git a/drivers/clk/at91/Makefile b/drivers/clk/at91/Makefile
index 04deba3..3873b62 100644
--- a/drivers/clk/at91/Makefile
+++ b/drivers/clk/at91/Makefile
@@ -5,3 +5,5 @@
 obj-y += pmc.o
 obj-y += clk-main.o clk-pll.o clk-plldiv.o clk-master.o
 obj-y += clk-system.o clk-peripheral.o
+
+obj-$(CONFIG_AT91_PROGRAMMABLE_CLOCKS)	+= clk-programmable.o
diff --git a/drivers/clk/at91/clk-programmable.c b/drivers/clk/at91/clk-programmable.c
new file mode 100644
index 0000000..f40de6a
--- /dev/null
+++ b/drivers/clk/at91/clk-programmable.c
@@ -0,0 +1,419 @@
+/*
+ * drivers/clk/at91/clk-programmable.c
+ *
+ *  Copyright (C) 2013 Boris BREZILLON <b.brezillon@overkiz.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ */
+
+#include <linux/clk-provider.h>
+#include <linux/clkdev.h>
+#include <linux/clk/at91_pmc.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/of_irq.h>
+#include <linux/io.h>
+#include <linux/wait.h>
+#include <linux/sched.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+
+#include "pmc.h"
+
+#define PROG_SOURCE_MAX		5
+#define PROG_MAX		8
+
+struct clk_programmable_layout {
+	u8 pres_shift;
+	u8 css_mask;
+	u8 have_slck_mck;
+};
+
+#define to_clk_programmable(hw) container_of(hw, struct clk_programmable, hw)
+struct clk_programmable {
+	struct clk_hw hw;
+	struct at91_pmc *pmc;
+	unsigned int irq;
+	wait_queue_head_t wait;
+	u8 id;
+	u8 css;
+	u8 pres;
+	u8 slckmck;
+	const struct clk_programmable_layout *layout;
+};
+
+static irqreturn_t clk_programmable_irq_handler(int irq, void *dev_id)
+{
+	struct clk_programmable *prog = (struct clk_programmable *)dev_id;
+
+	wake_up(&prog->wait);
+
+	return IRQ_HANDLED;
+}
+
+static int clk_programmable_prepare(struct clk_hw *hw)
+{
+	u32 tmp;
+	struct clk_programmable *prog = to_clk_programmable(hw);
+	struct at91_pmc *pmc = prog->pmc;
+	const struct clk_programmable_layout *layout = prog->layout;
+
+	tmp = prog->css | (prog->pres << layout->pres_shift);
+	if (layout->have_slck_mck && prog->slckmck)
+		tmp |= 1 << 8;
+
+	pmc_write(pmc, AT91_PMC_PCKR(prog->id), tmp);
+
+	while (!(pmc_read(pmc, AT91_PMC_SR) & (1 << (prog->id + 8))))
+		wait_event(prog->wait,
+			   pmc_read(pmc, AT91_PMC_SR) & (1 << (prog->id + 8)));
+
+	return 0;
+}
+
+static int clk_programmable_is_ready(struct clk_hw *hw)
+{
+	struct clk_programmable *prog = to_clk_programmable(hw);
+	struct at91_pmc *pmc = prog->pmc;
+
+	return !!(pmc_read(pmc, AT91_PMC_SR) & (1 << (prog->id + 8)));
+}
+
+static unsigned long clk_programmable_recalc_rate(struct clk_hw *hw,
+						  unsigned long parent_rate)
+{
+	u32 tmp;
+	struct clk_programmable *prog = to_clk_programmable(hw);
+	struct at91_pmc *pmc = prog->pmc;
+	const struct clk_programmable_layout *layout = prog->layout;
+
+	tmp = pmc_read(pmc, AT91_PMC_PCKR(prog->id));
+	prog->pres = (tmp >> layout->pres_shift) & 0x7;
+
+	return parent_rate >> prog->pres;
+}
+
+static long clk_programmable_round_rate(struct clk_hw *hw, unsigned long rate,
+					unsigned long *parent_rate)
+{
+	unsigned long best_rate = *parent_rate;
+	unsigned long best_diff;
+	unsigned long new_diff;
+	unsigned long cur_rate;
+	int shift = shift;
+
+	if (rate > *parent_rate)
+		return *parent_rate;
+	else
+		best_diff = *parent_rate - rate;
+
+	if (!best_diff)
+		return best_rate;
+
+	for (shift = 1; shift < 7; shift++) {
+		cur_rate = *parent_rate >> shift;
+
+		if (cur_rate > rate)
+			new_diff = cur_rate - rate;
+		else
+			new_diff = rate - cur_rate;
+
+		if (!new_diff)
+			return cur_rate;
+
+		if (new_diff < best_diff) {
+			best_diff = new_diff;
+			best_rate = cur_rate;
+		}
+
+		if (rate > cur_rate)
+			break;
+
+	}
+
+	return best_rate;
+}
+
+static int clk_programmable_set_parent(struct clk_hw *hw, u8 index)
+{
+	struct clk_programmable *prog = to_clk_programmable(hw);
+	const struct clk_programmable_layout *layout = prog->layout;
+	if (index > layout->css_mask) {
+		if (index == 4 && layout->have_slck_mck) {
+			prog->css = 0;
+			prog->slckmck = 1;
+			return 0;
+		} else
+			return -EINVAL;
+	}
+
+	prog->css = index;
+	return 0;
+}
+
+static u8 clk_programmable_get_parent(struct clk_hw *hw)
+{
+	u32 tmp;
+	u8 ret;
+	struct clk_programmable *prog = to_clk_programmable(hw);
+	struct at91_pmc *pmc = prog->pmc;
+	const struct clk_programmable_layout *layout = prog->layout;
+
+	tmp = pmc_read(pmc, AT91_PMC_PCKR(prog->id));
+	prog->css = tmp & layout->css_mask;
+	ret = prog->css;
+	if (layout->have_slck_mck) {
+		prog->slckmck = !!(tmp & (1 << 8));
+		if (prog->slckmck && !ret)
+			ret = 4;
+	}
+
+	return ret;
+}
+
+static int clk_programmable_set_rate(struct clk_hw *hw, unsigned long rate,
+				     unsigned long parent_rate)
+{
+	struct clk_programmable *prog = to_clk_programmable(hw);
+	unsigned long best_rate = parent_rate;
+	unsigned long best_diff;
+	unsigned long new_diff;
+	unsigned long cur_rate;
+	int shift = 0;
+
+	if (rate > parent_rate)
+		return parent_rate;
+	else
+		best_diff = parent_rate - rate;
+
+	if (!best_diff) {
+		prog->pres = shift;
+		return 0;
+	}
+
+	for (shift = 1; shift < 7; shift++) {
+		cur_rate = parent_rate >> shift;
+
+		if (cur_rate > rate)
+			new_diff = cur_rate - rate;
+		else
+			new_diff = rate - cur_rate;
+
+		if (!new_diff)
+			break;
+
+		if (new_diff < best_diff) {
+			best_diff = new_diff;
+			best_rate = cur_rate;
+		}
+
+		if (rate > cur_rate)
+			break;
+
+	}
+
+	prog->pres = shift;
+	return 0;
+}
+
+static const struct clk_ops programmable_ops = {
+	.prepare = clk_programmable_prepare,
+	.is_prepared = clk_programmable_is_ready,
+	.recalc_rate = clk_programmable_recalc_rate,
+	.round_rate = clk_programmable_round_rate,
+	.get_parent = clk_programmable_get_parent,
+	.set_parent = clk_programmable_set_parent,
+	.set_rate = clk_programmable_set_rate,
+};
+
+static struct clk * __init
+at91_clk_register_programmable(struct at91_pmc *pmc, unsigned int irq,
+			       const char *name, const char **parent_names,
+			       u8 num_parents, u8 id,
+			       const struct clk_programmable_layout *layout)
+{
+	int ret;
+	struct clk_programmable *prog;
+	struct clk *clk = NULL;
+	struct clk_init_data init;
+	char irq_name[11];
+
+	id &= 7;
+
+	prog = kzalloc(sizeof(*prog), GFP_KERNEL);
+	if (!prog)
+		return ERR_PTR(-ENOMEM);
+
+	init.name = name;
+	init.ops = &programmable_ops;
+	init.parent_names = parent_names;
+	init.num_parents = num_parents;
+	init.flags = CLK_SET_RATE_GATE | CLK_SET_PARENT_GATE;
+
+	prog->id = id;
+	prog->layout = layout;
+	prog->hw.init = &init;
+	prog->pmc = pmc;
+	prog->irq = irq;
+	init_waitqueue_head(&prog->wait);
+	irq_set_status_flags(prog->irq, IRQ_NOAUTOEN);
+	snprintf(irq_name, sizeof(irq_name), "clk-prog%d", id);
+	ret = request_irq(prog->irq, clk_programmable_irq_handler,
+			  IRQF_TRIGGER_HIGH, irq_name, prog);
+	if (ret)
+		return ERR_PTR(ret);
+
+	clk = clk_register(NULL, &prog->hw);
+
+	if (IS_ERR(clk))
+		kfree(prog);
+
+	return clk;
+}
+
+static const struct clk_programmable_layout at91rm9200_programmable_layout = {
+	.pres_shift = 2,
+	.css_mask = 0x3,
+	.have_slck_mck = 0,
+};
+
+static const struct clk_programmable_layout at91sam9g45_programmable_layout = {
+	.pres_shift = 2,
+	.css_mask = 0x3,
+	.have_slck_mck = 1,
+};
+
+static const struct clk_programmable_layout at91sam9x5_programmable_layout = {
+	.pres_shift = 4,
+	.css_mask = 0x7,
+	.have_slck_mck = 0,
+};
+
+struct clk_prog_data {
+	struct clk **clks;
+	u8 *ids;
+	unsigned int clk_num;
+};
+
+static struct clk * __init
+of_clk_src_periph_get(struct of_phandle_args *clkspec, void *data)
+{
+	struct clk_prog_data *clk_data = data;
+	unsigned int id = clkspec->args[0];
+	int i;
+
+	if (id >= PROG_MAX)
+		goto err;
+
+	for (i = 0; i < clk_data->clk_num; i++) {
+		if (clk_data->ids[i] == id)
+			return clk_data->clks[i];
+	}
+
+err:
+	pr_err("%s: invalid clock id %d\n", __func__, id);
+	return ERR_PTR(-EINVAL);
+}
+
+static void __init
+of_at91_clk_prog_setup(struct device_node *np, struct at91_pmc *pmc,
+		       const struct clk_programmable_layout *layout)
+{
+	int num;
+	u32 id;
+	int i;
+	unsigned int irq;
+	struct clk *clk;
+	int num_parents;
+	u8 *ids;
+	struct clk **clks;
+	struct clk_prog_data *clktab;
+	const char *parent_names[PROG_SOURCE_MAX];
+	const char *name;
+	struct device_node *progclknp;
+
+	num_parents = of_count_phandle_with_args(np, "clocks", "#clock-cells");
+	if (num_parents <= 0 || num_parents > PROG_SOURCE_MAX)
+		return;
+
+	for (i = 0; i < num_parents; ++i) {
+		parent_names[i] = of_clk_get_parent_name(np, i);
+		if (!parent_names[i])
+			return;
+	}
+
+	num = of_get_child_count(np);
+	if (!num || num > PROG_MAX)
+		return;
+
+	clktab = kzalloc(sizeof(*clktab), GFP_KERNEL);
+	if (!clktab)
+		return;
+
+	ids = kzalloc(num * sizeof(*ids), GFP_KERNEL);
+	if (!ids)
+		goto out_free_clktab;
+
+	clks = kzalloc(num * sizeof(*clks), GFP_KERNEL);
+	if (!clks)
+		goto out_free_ids;
+
+	i = 0;
+	for_each_child_of_node(np, progclknp) {
+		name = progclknp->name;
+
+		if (of_property_read_u32(progclknp, "atmel,clk-id", &id))
+			goto out_free_clks;
+		if (id >= PROG_MAX)
+			goto out_free_clks;
+
+		irq = irq_of_parse_and_map(np, 0);
+		if (!irq)
+			goto out_free_clks;
+
+		clk = at91_clk_register_programmable(pmc, irq, name,
+						     parent_names, num_parents,
+						     id, layout);
+		if (IS_ERR(clk))
+			goto out_free_clks;
+
+		clks[i] = clk;
+		ids[i++] = id;
+	}
+
+	clktab->clk_num = num;
+	clktab->clks = clks;
+	clktab->ids = ids;
+	of_clk_add_provider(np, of_clk_src_periph_get, clktab);
+	return;
+
+out_free_clks:
+	kfree(clks);
+out_free_ids:
+	kfree(ids);
+out_free_clktab:
+	kfree(clktab);
+}
+
+
+void __init of_at91rm9200_clk_prog_setup(struct device_node *np,
+					 struct at91_pmc *pmc)
+{
+	of_at91_clk_prog_setup(np, pmc, &at91rm9200_programmable_layout);
+}
+
+void __init of_at91sam9g45_clk_prog_setup(struct device_node *np,
+					  struct at91_pmc *pmc)
+{
+	of_at91_clk_prog_setup(np, pmc, &at91sam9g45_programmable_layout);
+}
+
+void __init of_at91sam9x5_clk_prog_setup(struct device_node *np,
+					 struct at91_pmc *pmc)
+{
+	of_at91_clk_prog_setup(np, pmc, &at91sam9x5_programmable_layout);
+}
diff --git a/drivers/clk/at91/pmc.c b/drivers/clk/at91/pmc.c
index 1a56f1c..66a627d 100644
--- a/drivers/clk/at91/pmc.c
+++ b/drivers/clk/at91/pmc.c
@@ -265,6 +265,21 @@ static const struct of_device_id pmc_clk_ids[] __initdata = {
 		.compatible = "atmel,at91sam9x5-clk-peripheral",
 		.data = of_at91sam9x5_clk_periph_setup,
 	},
+	/* Programmable clocks */
+#if defined(CONFIG_AT91_PROGRAMMABLE_CLOCKS)
+	{
+		.compatible = "atmel,at91rm9200-clk-programmable",
+		.data = of_at91rm9200_clk_prog_setup,
+	},
+	{
+		.compatible = "atmel,at91sam9g45-clk-programmable",
+		.data = of_at91sam9g45_clk_prog_setup,
+	},
+	{
+		.compatible = "atmel,at91sam9x5-clk-programmable",
+		.data = of_at91sam9x5_clk_prog_setup,
+	},
+#endif
 	{ /*sentinel*/ }
 };
 
diff --git a/drivers/clk/at91/pmc.h b/drivers/clk/at91/pmc.h
index 08c30fb..5f20dc1 100644
--- a/drivers/clk/at91/pmc.h
+++ b/drivers/clk/at91/pmc.h
@@ -82,4 +82,13 @@ extern void __init of_at91rm9200_clk_periph_setup(struct device_node *np,
 extern void __init of_at91sam9x5_clk_periph_setup(struct device_node *np,
 						  struct at91_pmc *pmc);
 
+#if defined(CONFIG_AT91_PROGRAMMABLE_CLOCKS)
+extern void __init of_at91rm9200_clk_prog_setup(struct device_node *np,
+						struct at91_pmc *pmc);
+extern void __init of_at91sam9g45_clk_prog_setup(struct device_node *np,
+						 struct at91_pmc *pmc);
+extern void __init of_at91sam9x5_clk_prog_setup(struct device_node *np,
+						struct at91_pmc *pmc);
+#endif
+
 #endif /* __PMC_H_ */
-- 
1.7.9.5


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

* [PATCH v3 14/19] clk: at91: add PMC utmi clock
  2013-08-08  4:53 [PATCH v3 00/19] ARM: at91: move to common clk framework Boris BREZILLON
                   ` (12 preceding siblings ...)
  2013-08-08  7:12 ` [PATCH v3 13/19] clk: at91: add PMC programmable clocks Boris BREZILLON
@ 2013-08-08  7:14 ` Boris BREZILLON
  2013-10-08 16:08   ` Nicolas Ferre
  2013-08-08  7:15 ` [PATCH v3 15/19] clk: at91: add PMC usb clock Boris BREZILLON
                   ` (5 subsequent siblings)
  19 siblings, 1 reply; 54+ messages in thread
From: Boris BREZILLON @ 2013-08-08  7:14 UTC (permalink / raw)
  To: Grant Likely, Rob Herring, Rob Landley, Andrew Victor,
	Nicolas Ferre, Jean-Christophe Plagniol-Villard, Russell King,
	Mike Turquette, Felipe Balbi, Greg Kroah-Hartman,
	Ludovic Desroches, Josh Wu, Richard Genoud
  Cc: devicetree, linux-kernel, linux-arm-kernel, Boris BREZILLON

This adds new at91 utmi clock implementation using common clk framework.

This clock is a pll with a fixed factor (x40).
It is used as a source for usb clock.

Signed-off-by: Boris BREZILLON <b.brezillon@overkiz.com>
---
 arch/arm/mach-at91/Kconfig  |    7 ++
 drivers/clk/at91/Makefile   |    1 +
 drivers/clk/at91/clk-utmi.c |  161 +++++++++++++++++++++++++++++++++++++++++++
 drivers/clk/at91/pmc.c      |    7 ++
 drivers/clk/at91/pmc.h      |    5 ++
 5 files changed, 181 insertions(+)
 create mode 100644 drivers/clk/at91/clk-utmi.c

diff --git a/arch/arm/mach-at91/Kconfig b/arch/arm/mach-at91/Kconfig
index 85b53a4..6ad37da 100644
--- a/arch/arm/mach-at91/Kconfig
+++ b/arch/arm/mach-at91/Kconfig
@@ -1,5 +1,8 @@
 if ARCH_AT91
 
+config HAVE_AT91_UTMI
+	bool
+
 config HAVE_AT91_DBGU0
 	bool
 
@@ -78,6 +81,7 @@ config SOC_SAMA5D3
 	select HAVE_FB_ATMEL
 	select HAVE_AT91_DBGU1
 	select AT91_USE_OLD_CLK
+	select HAVE_AT91_UTMI
 	help
 	  Select this if you are using one of Atmel's SAMA5D3 family SoC.
 	  This support covers SAMA5D31, SAMA5D33, SAMA5D34, SAMA5D35.
@@ -124,6 +128,7 @@ config SOC_AT91SAM9RL
 	select HAVE_FB_ATMEL
 	select SOC_AT91SAM9
 	select AT91_USE_OLD_CLK
+	select HAVE_AT91_UTMI
 
 config SOC_AT91SAM9G45
 	bool "AT91SAM9G45 or AT91SAM9M10 families"
@@ -131,6 +136,7 @@ config SOC_AT91SAM9G45
 	select HAVE_FB_ATMEL
 	select SOC_AT91SAM9
 	select AT91_USE_OLD_CLK
+	select HAVE_AT91_UTMI
 	help
 	  Select this if you are using one of Atmel's AT91SAM9G45 family SoC.
 	  This support covers AT91SAM9G45, AT91SAM9G46, AT91SAM9M10 and AT91SAM9M11.
@@ -141,6 +147,7 @@ config SOC_AT91SAM9X5
 	select HAVE_FB_ATMEL
 	select SOC_AT91SAM9
 	select AT91_USE_OLD_CLK
+	select HAVE_AT91_UTMI
 	help
 	  Select this if you are using one of Atmel's AT91SAM9x5 family SoC.
 	  This means that your SAM9 name finishes with a '5' (except if it is
diff --git a/drivers/clk/at91/Makefile b/drivers/clk/at91/Makefile
index 3873b62..a824883 100644
--- a/drivers/clk/at91/Makefile
+++ b/drivers/clk/at91/Makefile
@@ -7,3 +7,4 @@ obj-y += clk-main.o clk-pll.o clk-plldiv.o clk-master.o
 obj-y += clk-system.o clk-peripheral.o
 
 obj-$(CONFIG_AT91_PROGRAMMABLE_CLOCKS)	+= clk-programmable.o
+obj-$(CONFIG_HAVE_AT91_UTMI)		+= clk-utmi.o
diff --git a/drivers/clk/at91/clk-utmi.c b/drivers/clk/at91/clk-utmi.c
new file mode 100644
index 0000000..244ff9e
--- /dev/null
+++ b/drivers/clk/at91/clk-utmi.c
@@ -0,0 +1,161 @@
+/*
+ * drivers/clk/at91/clk-utmi.c
+ *
+ *  Copyright (C) 2013 Boris BREZILLON <b.brezillon@overkiz.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ */
+
+#include <linux/clk-provider.h>
+#include <linux/clkdev.h>
+#include <linux/clk/at91_pmc.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/of_irq.h>
+#include <linux/io.h>
+#include <linux/sched.h>
+#include <linux/wait.h>
+
+#include "pmc.h"
+
+#define to_clk_utmi(hw) container_of(hw, struct clk_utmi, hw)
+
+struct clk_utmi {
+	struct clk_hw hw;
+	struct at91_pmc *pmc;
+	unsigned int irq;
+	wait_queue_head_t wait;
+};
+
+static irqreturn_t clk_utmi_irq_handler(int irq, void *dev_id)
+{
+	struct clk_utmi *utmi = (struct clk_utmi *)dev_id;
+
+	wake_up(&utmi->wait);
+	disable_irq_nosync(utmi->irq);
+
+	return IRQ_HANDLED;
+}
+
+static int clk_utmi_prepare(struct clk_hw *hw)
+{
+	struct clk_utmi *utmi = to_clk_utmi(hw);
+	struct at91_pmc *pmc = utmi->pmc;
+	u32 tmp = at91_pmc_read(AT91_CKGR_UCKR) | AT91_PMC_UPLLEN |
+		  AT91_PMC_UPLLCOUNT | AT91_PMC_BIASEN;
+
+	pmc_write(pmc, AT91_CKGR_UCKR, tmp);
+
+	while (!(pmc_read(pmc, AT91_PMC_SR) & AT91_PMC_LOCKU)) {
+		enable_irq(utmi->irq);
+		wait_event(utmi->wait,
+			   pmc_read(pmc, AT91_PMC_SR) & AT91_PMC_LOCKU);
+	}
+
+	return 0;
+}
+
+static int clk_utmi_is_ready(struct clk_hw *hw)
+{
+	struct clk_utmi *utmi = to_clk_utmi(hw);
+	struct at91_pmc *pmc = utmi->pmc;
+
+	return !!(pmc_read(pmc, AT91_PMC_SR) & AT91_PMC_LOCKU);
+}
+
+static void clk_utmi_disable(struct clk_hw *hw)
+{
+	struct clk_utmi *utmi = to_clk_utmi(hw);
+	struct at91_pmc *pmc = utmi->pmc;
+	u32 tmp = at91_pmc_read(AT91_CKGR_UCKR) & ~AT91_PMC_UPLLEN;
+
+	pmc_write(pmc, AT91_CKGR_UCKR, tmp);
+}
+
+static unsigned long clk_utmi_recalc_rate(struct clk_hw *hw,
+					  unsigned long parent_rate)
+{
+	return parent_rate * 40;
+}
+
+static const struct clk_ops utmi_ops = {
+	.prepare = clk_utmi_prepare,
+	.is_prepared = clk_utmi_is_ready,
+	.disable = clk_utmi_disable,
+	.is_enabled = clk_utmi_is_ready,
+	.recalc_rate = clk_utmi_recalc_rate,
+};
+
+static struct clk * __init
+at91_clk_register_utmi(struct at91_pmc *pmc, unsigned int irq,
+		       const char *name, const char *parent_name)
+{
+	int ret;
+	struct clk_utmi *utmi;
+	struct clk *clk = NULL;
+	struct clk_init_data init;
+
+	utmi = kzalloc(sizeof(*utmi), GFP_KERNEL);
+	if (!utmi)
+		return ERR_PTR(-ENOMEM);
+
+	init.name = name;
+	init.ops = &utmi_ops;
+	init.parent_names = parent_name ? &parent_name : NULL;
+	init.num_parents = parent_name ? 1 : 0;
+	init.flags = CLK_SET_RATE_GATE;
+
+	utmi->hw.init = &init;
+	utmi->pmc = pmc;
+	utmi->irq = irq;
+	init_waitqueue_head(&utmi->wait);
+	irq_set_status_flags(utmi->irq, IRQ_NOAUTOEN);
+	ret = request_irq(utmi->irq, clk_utmi_irq_handler,
+			  IRQF_TRIGGER_HIGH, "clk-utmi", utmi);
+	if (ret)
+		return ERR_PTR(ret);
+
+	clk = clk_register(NULL, &utmi->hw);
+
+	if (IS_ERR(clk))
+		kfree(utmi);
+
+	return clk;
+}
+
+static void __init
+of_at91_clk_utmi_setup(struct device_node *np, struct at91_pmc *pmc)
+{
+	unsigned int irq;
+	struct clk *clk;
+	const char *parent_name;
+	const char *name = np->name;
+
+	parent_name = of_clk_get_parent_name(np, 0);
+
+	of_property_read_string(np, "clock-output-names", &name);
+
+	irq = irq_of_parse_and_map(np, 0);
+	if (!irq)
+		return;
+
+	clk = at91_clk_register_utmi(pmc, irq, name, parent_name);
+
+	if (IS_ERR(clk))
+		return;
+
+	of_clk_add_provider(np, of_clk_src_simple_get, clk);
+	return;
+}
+
+void __init of_at91sam9x5_clk_utmi_setup(struct device_node *np,
+					 struct at91_pmc *pmc)
+{
+	of_at91_clk_utmi_setup(np, pmc);
+}
diff --git a/drivers/clk/at91/pmc.c b/drivers/clk/at91/pmc.c
index 66a627d..238f0d2 100644
--- a/drivers/clk/at91/pmc.c
+++ b/drivers/clk/at91/pmc.c
@@ -280,6 +280,13 @@ static const struct of_device_id pmc_clk_ids[] __initdata = {
 		.data = of_at91sam9x5_clk_prog_setup,
 	},
 #endif
+	/* UTMI clock */
+#if defined(CONFIG_HAVE_AT91_UTMI)
+	{
+		.compatible = "atmel,at91sam9x5-clk-utmi",
+		.data = of_at91sam9x5_clk_utmi_setup,
+	},
+#endif
 	{ /*sentinel*/ }
 };
 
diff --git a/drivers/clk/at91/pmc.h b/drivers/clk/at91/pmc.h
index 5f20dc1..3ba9503 100644
--- a/drivers/clk/at91/pmc.h
+++ b/drivers/clk/at91/pmc.h
@@ -91,4 +91,9 @@ extern void __init of_at91sam9x5_clk_prog_setup(struct device_node *np,
 						struct at91_pmc *pmc);
 #endif
 
+#if defined(CONFIG_HAVE_AT91_UTMI)
+extern void __init of_at91sam9x5_clk_utmi_setup(struct device_node *np,
+						struct at91_pmc *pmc);
+#endif
+
 #endif /* __PMC_H_ */
-- 
1.7.9.5


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

* [PATCH v3 15/19] clk: at91: add PMC usb clock
  2013-08-08  4:53 [PATCH v3 00/19] ARM: at91: move to common clk framework Boris BREZILLON
                   ` (13 preceding siblings ...)
  2013-08-08  7:14 ` [PATCH v3 14/19] clk: at91: add PMC utmi clock Boris BREZILLON
@ 2013-08-08  7:15 ` Boris BREZILLON
  2013-10-08 16:20   ` Nicolas Ferre
  2013-08-08  7:17 ` [PATCH v3 16/19] clk: at91: add PMC smd clock Boris BREZILLON
                   ` (4 subsequent siblings)
  19 siblings, 1 reply; 54+ messages in thread
From: Boris BREZILLON @ 2013-08-08  7:15 UTC (permalink / raw)
  To: Grant Likely, Rob Herring, Rob Landley, Andrew Victor,
	Nicolas Ferre, Jean-Christophe Plagniol-Villard, Russell King,
	Mike Turquette, Felipe Balbi, Greg Kroah-Hartman,
	Ludovic Desroches, Josh Wu, Richard Genoud
  Cc: devicetree, linux-kernel, linux-arm-kernel, Boris BREZILLON

This patch adds new at91 usb clock implementation using common clk framework.
This clock is used to clock usb ports (ohci, ehci and udc).

Signed-off-by: Boris BREZILLON <b.brezillon@overkiz.com>
---
 arch/arm/mach-at91/Kconfig |   11 ++
 drivers/clk/at91/Makefile  |    1 +
 drivers/clk/at91/clk-usb.c |  323 ++++++++++++++++++++++++++++++++++++++++++++
 drivers/clk/at91/pmc.c     |   11 ++
 drivers/clk/at91/pmc.h     |    7 +
 5 files changed, 353 insertions(+)
 create mode 100644 drivers/clk/at91/clk-usb.c

diff --git a/arch/arm/mach-at91/Kconfig b/arch/arm/mach-at91/Kconfig
index 6ad37da..b76dc4c 100644
--- a/arch/arm/mach-at91/Kconfig
+++ b/arch/arm/mach-at91/Kconfig
@@ -3,6 +3,9 @@ if ARCH_AT91
 config HAVE_AT91_UTMI
 	bool
 
+config HAVE_AT91_USB_CLK
+	bool
+
 config HAVE_AT91_DBGU0
 	bool
 
@@ -82,6 +85,7 @@ config SOC_SAMA5D3
 	select HAVE_AT91_DBGU1
 	select AT91_USE_OLD_CLK
 	select HAVE_AT91_UTMI
+	select HAVE_AT91_USB_CLK
 	help
 	  Select this if you are using one of Atmel's SAMA5D3 family SoC.
 	  This support covers SAMA5D31, SAMA5D33, SAMA5D34, SAMA5D35.
@@ -96,12 +100,14 @@ config SOC_AT91RM9200
 	select MULTI_IRQ_HANDLER
 	select SPARSE_IRQ
 	select AT91_USE_OLD_CLK
+	select HAVE_AT91_USB_CLK
 
 config SOC_AT91SAM9260
 	bool "AT91SAM9260, AT91SAM9XE or AT91SAM9G20"
 	select HAVE_AT91_DBGU0
 	select SOC_AT91SAM9
 	select AT91_USE_OLD_CLK
+	select HAVE_AT91_USB_CLK
 	help
 	  Select this if you are using one of Atmel's AT91SAM9260, AT91SAM9XE
 	  or AT91SAM9G20 SoC.
@@ -112,6 +118,7 @@ config SOC_AT91SAM9261
 	select HAVE_FB_ATMEL
 	select SOC_AT91SAM9
 	select AT91_USE_OLD_CLK
+	select HAVE_AT91_USB_CLK
 	help
 	  Select this if you are using one of Atmel's AT91SAM9261 or AT91SAM9G10 SoC.
 
@@ -121,6 +128,7 @@ config SOC_AT91SAM9263
 	select HAVE_FB_ATMEL
 	select SOC_AT91SAM9
 	select AT91_USE_OLD_CLK
+	select HAVE_AT91_USB_CLK
 
 config SOC_AT91SAM9RL
 	bool "AT91SAM9RL"
@@ -137,6 +145,7 @@ config SOC_AT91SAM9G45
 	select SOC_AT91SAM9
 	select AT91_USE_OLD_CLK
 	select HAVE_AT91_UTMI
+	select HAVE_AT91_USB_CLK
 	help
 	  Select this if you are using one of Atmel's AT91SAM9G45 family SoC.
 	  This support covers AT91SAM9G45, AT91SAM9G46, AT91SAM9M10 and AT91SAM9M11.
@@ -148,6 +157,7 @@ config SOC_AT91SAM9X5
 	select SOC_AT91SAM9
 	select AT91_USE_OLD_CLK
 	select HAVE_AT91_UTMI
+	select HAVE_AT91_USB_CLK
 	help
 	  Select this if you are using one of Atmel's AT91SAM9x5 family SoC.
 	  This means that your SAM9 name finishes with a '5' (except if it is
@@ -161,6 +171,7 @@ config SOC_AT91SAM9N12
 	select HAVE_FB_ATMEL
 	select SOC_AT91SAM9
 	select AT91_USE_OLD_CLK
+	select HAVE_AT91_USB_CLK
 	help
 	  Select this if you are using Atmel's AT91SAM9N12 SoC.
 
diff --git a/drivers/clk/at91/Makefile b/drivers/clk/at91/Makefile
index a824883..61db058 100644
--- a/drivers/clk/at91/Makefile
+++ b/drivers/clk/at91/Makefile
@@ -8,3 +8,4 @@ obj-y += clk-system.o clk-peripheral.o
 
 obj-$(CONFIG_AT91_PROGRAMMABLE_CLOCKS)	+= clk-programmable.o
 obj-$(CONFIG_HAVE_AT91_UTMI)		+= clk-utmi.o
+obj-$(CONFIG_HAVE_AT91_USB_CLK)		+= clk-usb.o
diff --git a/drivers/clk/at91/clk-usb.c b/drivers/clk/at91/clk-usb.c
new file mode 100644
index 0000000..12c20a0
--- /dev/null
+++ b/drivers/clk/at91/clk-usb.c
@@ -0,0 +1,323 @@
+/*
+ * drivers/clk/at91/clk-usb.c
+ *
+ *  Copyright (C) 2013 Boris BREZILLON <b.brezillon@overkiz.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ */
+
+#include <linux/clk-provider.h>
+#include <linux/clkdev.h>
+#include <linux/clk/at91_pmc.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/io.h>
+
+#include "pmc.h"
+
+#define USB_SOURCE_MAX		2
+
+#define to_at91sam9x5_clk_usb(hw) \
+	container_of(hw, struct at91sam9x5_clk_usb, hw)
+struct at91sam9x5_clk_usb {
+	struct clk_hw hw;
+	struct at91_pmc *pmc;
+	u8 usbs0_unused; /* sam9n12 uses usbs0 to disable usb clock */
+};
+
+#define to_at91rm9200_clk_usb(hw) \
+	container_of(hw, struct at91rm9200_clk_usb, hw)
+struct at91rm9200_clk_usb {
+	struct clk_hw hw;
+	struct at91_pmc *pmc;
+	u32 divisors[4];
+};
+
+static unsigned long at91sam9x5_clk_usb_recalc_rate(struct clk_hw *hw,
+						    unsigned long parent_rate)
+{
+	u32 tmp;
+	u8 usbdiv;
+	struct at91sam9x5_clk_usb *usb = to_at91sam9x5_clk_usb(hw);
+	struct at91_pmc *pmc = usb->pmc;
+
+	tmp = pmc_read(pmc, AT91_PMC_USB);
+	usbdiv = (tmp & AT91_PMC_OHCIUSBDIV) >> 8;
+	return parent_rate / (usbdiv + 1);
+}
+
+static long at91sam9x5_clk_usb_round_rate(struct clk_hw *hw, unsigned long rate,
+					  unsigned long *parent_rate)
+{
+	unsigned long div;
+	unsigned long bestrate;
+	unsigned long tmp;
+
+	if (rate >= *parent_rate)
+		return *parent_rate;
+
+	div = *parent_rate / rate;
+	if (div > 15)
+		return *parent_rate / 16;
+
+	bestrate = *parent_rate / div;
+	tmp = *parent_rate / (div + 1);
+	if (bestrate - rate > rate - tmp)
+		bestrate = tmp;
+
+	return bestrate;
+}
+
+static int at91sam9x5_clk_usb_set_parent(struct clk_hw *hw, u8 index)
+{
+	u32 tmp;
+	struct at91sam9x5_clk_usb *usb = to_at91sam9x5_clk_usb(hw);
+	struct at91_pmc *pmc = usb->pmc;
+
+	if (usb->usbs0_unused)
+		index++;
+	if (index > 1)
+		return -EINVAL;
+	tmp = pmc_read(pmc, AT91_PMC_USB) & ~AT91_PMC_USBS;
+	if (index)
+		tmp |= AT91_PMC_USBS;
+	pmc_write(pmc, AT91_PMC_USB, tmp);
+	return 0;
+}
+
+static u8 at91sam9x5_clk_usb_get_parent(struct clk_hw *hw)
+{
+	struct at91sam9x5_clk_usb *usb = to_at91sam9x5_clk_usb(hw);
+	struct at91_pmc *pmc = usb->pmc;
+
+	if (usb->usbs0_unused)
+		return 0;
+
+	return pmc_read(pmc, AT91_PMC_USB) & AT91_PMC_USBS;
+}
+
+static int at91sam9x5_clk_usb_set_rate(struct clk_hw *hw, unsigned long rate,
+				       unsigned long parent_rate)
+{
+	u32 tmp;
+	struct at91sam9x5_clk_usb *usb = to_at91sam9x5_clk_usb(hw);
+	struct at91_pmc *pmc = usb->pmc;
+	unsigned long div = parent_rate / rate;
+
+	if (parent_rate % rate || div < 1 || div > 16)
+		return -EINVAL;
+
+	tmp = pmc_read(pmc, AT91_PMC_USB) & ~AT91_PMC_OHCIUSBDIV;
+	tmp |= (div - 1) << 8;
+	pmc_write(pmc, AT91_PMC_USB, tmp);
+
+	return 0;
+}
+
+static const struct clk_ops at91sam9x5_usb_ops = {
+	.recalc_rate = at91sam9x5_clk_usb_recalc_rate,
+	.round_rate = at91sam9x5_clk_usb_round_rate,
+	.get_parent = at91sam9x5_clk_usb_get_parent,
+	.set_parent = at91sam9x5_clk_usb_set_parent,
+	.set_rate = at91sam9x5_clk_usb_set_rate,
+};
+
+static struct clk * __init
+at91sam9x5_clk_register_usb(struct at91_pmc *pmc, const char *name,
+			    const char **parent_names, u8 num_parents,
+			    u8 usbs0_unused)
+{
+	struct at91sam9x5_clk_usb *usb;
+	struct clk *clk = NULL;
+	struct clk_init_data init;
+
+	usb = kzalloc(sizeof(*usb), GFP_KERNEL);
+	if (!usb)
+		return ERR_PTR(-ENOMEM);
+
+	init.name = name;
+	init.ops = &at91sam9x5_usb_ops;
+	init.parent_names = parent_names;
+	init.num_parents = num_parents;
+	init.flags = CLK_SET_RATE_GATE | CLK_SET_PARENT_GATE;
+
+	usb->usbs0_unused = usbs0_unused;
+	usb->hw.init = &init;
+	usb->pmc = pmc;
+
+	clk = clk_register(NULL, &usb->hw);
+
+	if (IS_ERR(clk))
+		kfree(usb);
+
+	return clk;
+}
+
+static unsigned long at91rm9200_clk_usb_recalc_rate(struct clk_hw *hw,
+						    unsigned long parent_rate)
+{
+	struct at91rm9200_clk_usb *usb = to_at91rm9200_clk_usb(hw);
+	struct at91_pmc *pmc = usb->pmc;
+	u32 tmp;
+	u8 usbdiv;
+
+	tmp = pmc_read(pmc, AT91_CKGR_PLLBR);
+	usbdiv = (tmp & AT91_PMC_USBDIV) >> 28;
+	if (usb->divisors[usbdiv])
+		return parent_rate / usb->divisors[usbdiv];
+
+	return 0;
+}
+
+static long at91rm9200_clk_usb_round_rate(struct clk_hw *hw, unsigned long rate,
+					  unsigned long *parent_rate)
+{
+	struct at91rm9200_clk_usb *usb = to_at91rm9200_clk_usb(hw);
+	unsigned long bestrate = 0;
+	int bestdiff = -1;
+	unsigned long tmprate;
+	int tmpdiff;
+	int i = 0;
+
+	for (i = 0; i < 4; i++) {
+		if (!usb->divisors[i])
+			continue;
+		tmprate = *parent_rate / usb->divisors[i];
+		if (tmprate < rate)
+			tmpdiff = rate - tmprate;
+		else
+			tmpdiff = tmprate - rate;
+
+		if (bestdiff < 0 || bestdiff > tmpdiff) {
+			bestrate = tmprate;
+			bestdiff = tmpdiff;
+		}
+
+		if (!bestdiff)
+			break;
+	}
+
+	return bestrate;
+}
+
+static int at91rm9200_clk_usb_set_rate(struct clk_hw *hw, unsigned long rate,
+				       unsigned long parent_rate)
+{
+	u32 tmp;
+	int i;
+	struct at91rm9200_clk_usb *usb = to_at91rm9200_clk_usb(hw);
+	struct at91_pmc *pmc = usb->pmc;
+	unsigned long div = parent_rate / rate;
+
+	if (parent_rate % rate)
+		return -EINVAL;
+	for (i = 0; i < 4; i++) {
+		if (usb->divisors[i] == div) {
+			tmp = pmc_read(pmc, AT91_CKGR_PLLBR) &
+			      ~AT91_PMC_USBDIV;
+			tmp |= i << 8;
+			pmc_write(pmc, AT91_PMC_USB, tmp);
+			return 0;
+		}
+	}
+
+	return -EINVAL;
+}
+
+static const struct clk_ops at91rm9200_usb_ops = {
+	.recalc_rate = at91rm9200_clk_usb_recalc_rate,
+	.round_rate = at91rm9200_clk_usb_round_rate,
+	.set_rate = at91rm9200_clk_usb_set_rate,
+};
+
+static struct clk * __init
+at91rm9200_clk_register_usb(struct at91_pmc *pmc, const char *name,
+			    const char *parent_name, const u32 *divisors)
+{
+	struct at91rm9200_clk_usb *usb;
+	struct clk *clk = NULL;
+	struct clk_init_data init;
+
+	usb = kzalloc(sizeof(*usb), GFP_KERNEL);
+	if (!usb)
+		return ERR_PTR(-ENOMEM);
+
+	init.name = name;
+	init.ops = &at91rm9200_usb_ops;
+	init.parent_names = &parent_name;
+	init.num_parents = 1;
+	init.flags = 0;
+
+	usb->hw.init = &init;
+	usb->pmc = pmc;
+	memcpy(usb->divisors, divisors, sizeof(usb->divisors));
+
+	clk = clk_register(NULL, &usb->hw);
+
+	if (IS_ERR(clk))
+		kfree(usb);
+
+	return clk;
+}
+
+void __init of_at91sam9x5_clk_usb_setup(struct device_node *np,
+					struct at91_pmc *pmc)
+{
+	struct clk *clk;
+	int i;
+	int num_parents;
+	u8 usbs0_unused;
+	const char *parent_names[USB_SOURCE_MAX];
+	const char *name = np->name;
+
+	num_parents = of_count_phandle_with_args(np, "clocks", "#clock-cells");
+	if (num_parents <= 0 || num_parents > USB_SOURCE_MAX)
+		return;
+
+	for (i = 0; i < num_parents; i++) {
+		parent_names[i] = of_clk_get_parent_name(np, i);
+		if (!parent_names[i])
+			return;
+	}
+
+	usbs0_unused = of_property_read_bool(np, "atmel,usb-clk-src0-unused");
+	of_property_read_string(np, "clock-output-names", &name);
+
+	clk = at91sam9x5_clk_register_usb(pmc, name, parent_names, num_parents,
+					  usbs0_unused);
+
+	if (IS_ERR(clk))
+		return;
+
+	of_clk_add_provider(np, of_clk_src_simple_get, clk);
+}
+
+void __init of_at91rm9200_clk_usb_setup(struct device_node *np,
+					struct at91_pmc *pmc)
+{
+	struct clk *clk;
+	const char *parent_name;
+	const char *name = np->name;
+	u32 divisors[4] = {0, 0, 0, 0};
+
+	parent_name = of_clk_get_parent_name(np, 0);
+	if (!parent_name)
+		return;
+
+	of_property_read_u32_array(np, "atmel,clk-divisors", divisors, 4);
+	if (!divisors[0])
+		return;
+
+	of_property_read_string(np, "clock-output-names", &name);
+
+	clk = at91rm9200_clk_register_usb(pmc, name, parent_name, divisors);
+
+	if (IS_ERR(clk))
+		return;
+
+	of_clk_add_provider(np, of_clk_src_simple_get, clk);
+}
diff --git a/drivers/clk/at91/pmc.c b/drivers/clk/at91/pmc.c
index 238f0d2..e46de3d 100644
--- a/drivers/clk/at91/pmc.c
+++ b/drivers/clk/at91/pmc.c
@@ -287,6 +287,17 @@ static const struct of_device_id pmc_clk_ids[] __initdata = {
 		.data = of_at91sam9x5_clk_utmi_setup,
 	},
 #endif
+	/* USB clock */
+#if defined(CONFIG_HAVE_AT91_USB_CLK)
+	{
+		.compatible = "atmel,at91rm9200-clk-usb",
+		.data = of_at91rm9200_clk_usb_setup,
+	},
+	{
+		.compatible = "atmel,at91sam9x5-clk-usb",
+		.data = of_at91sam9x5_clk_usb_setup,
+	},
+#endif
 	{ /*sentinel*/ }
 };
 
diff --git a/drivers/clk/at91/pmc.h b/drivers/clk/at91/pmc.h
index 3ba9503..b2efff5 100644
--- a/drivers/clk/at91/pmc.h
+++ b/drivers/clk/at91/pmc.h
@@ -96,4 +96,11 @@ extern void __init of_at91sam9x5_clk_utmi_setup(struct device_node *np,
 						struct at91_pmc *pmc);
 #endif
 
+#if defined(CONFIG_HAVE_AT91_USB_CLK)
+extern void __init of_at91rm9200_clk_usb_setup(struct device_node *np,
+					       struct at91_pmc *pmc);
+extern void __init of_at91sam9x5_clk_usb_setup(struct device_node *np,
+					       struct at91_pmc *pmc);
+#endif
+
 #endif /* __PMC_H_ */
-- 
1.7.9.5


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

* [PATCH v3 16/19] clk: at91: add PMC smd clock
  2013-08-08  4:53 [PATCH v3 00/19] ARM: at91: move to common clk framework Boris BREZILLON
                   ` (14 preceding siblings ...)
  2013-08-08  7:15 ` [PATCH v3 15/19] clk: at91: add PMC usb clock Boris BREZILLON
@ 2013-08-08  7:17 ` Boris BREZILLON
  2013-10-08 16:22   ` Nicolas Ferre
  2013-08-08  7:19 ` [PATCH v3 17/19] clk: at91: add PMC clk device tree binding doc Boris BREZILLON
                   ` (3 subsequent siblings)
  19 siblings, 1 reply; 54+ messages in thread
From: Boris BREZILLON @ 2013-08-08  7:17 UTC (permalink / raw)
  To: Grant Likely, Rob Herring, Rob Landley, Andrew Victor,
	Nicolas Ferre, Jean-Christophe Plagniol-Villard, Russell King,
	Mike Turquette, Felipe Balbi, Greg Kroah-Hartman,
	Ludovic Desroches, Josh Wu, Richard Genoud
  Cc: devicetree, linux-kernel, linux-arm-kernel, Boris BREZILLON

This patch adds at91 smd (Soft Modem) clock implementation using common clk
framework.

Not used by any driver right now.

Signed-off-by: Boris BREZILLON <b.brezillon@overkiz.com>
---
 arch/arm/mach-at91/Kconfig |    5 ++
 drivers/clk/at91/Makefile  |    1 +
 drivers/clk/at91/clk-smd.c |  171 ++++++++++++++++++++++++++++++++++++++++++++
 drivers/clk/at91/pmc.c     |    7 ++
 drivers/clk/at91/pmc.h     |    5 ++
 5 files changed, 189 insertions(+)
 create mode 100644 drivers/clk/at91/clk-smd.c

diff --git a/arch/arm/mach-at91/Kconfig b/arch/arm/mach-at91/Kconfig
index b76dc4c..97033f7 100644
--- a/arch/arm/mach-at91/Kconfig
+++ b/arch/arm/mach-at91/Kconfig
@@ -39,6 +39,9 @@ config AT91_SAM9G45_RESET
 config AT91_SAM9_TIME
 	bool
 
+config HAVE_AT91_SMD
+	bool
+
 config SOC_AT91SAM9
 	bool
 	select AT91_SAM9_TIME
@@ -85,6 +88,7 @@ config SOC_SAMA5D3
 	select HAVE_AT91_DBGU1
 	select AT91_USE_OLD_CLK
 	select HAVE_AT91_UTMI
+	select HAVE_AT91_SMD
 	select HAVE_AT91_USB_CLK
 	help
 	  Select this if you are using one of Atmel's SAMA5D3 family SoC.
@@ -157,6 +161,7 @@ config SOC_AT91SAM9X5
 	select SOC_AT91SAM9
 	select AT91_USE_OLD_CLK
 	select HAVE_AT91_UTMI
+	select HAVE_AT91_SMD
 	select HAVE_AT91_USB_CLK
 	help
 	  Select this if you are using one of Atmel's AT91SAM9x5 family SoC.
diff --git a/drivers/clk/at91/Makefile b/drivers/clk/at91/Makefile
index 61db058..0e92b71 100644
--- a/drivers/clk/at91/Makefile
+++ b/drivers/clk/at91/Makefile
@@ -9,3 +9,4 @@ obj-y += clk-system.o clk-peripheral.o
 obj-$(CONFIG_AT91_PROGRAMMABLE_CLOCKS)	+= clk-programmable.o
 obj-$(CONFIG_HAVE_AT91_UTMI)		+= clk-utmi.o
 obj-$(CONFIG_HAVE_AT91_USB_CLK)		+= clk-usb.o
+obj-$(CONFIG_HAVE_AT91_SMD)		+= clk-smd.o
diff --git a/drivers/clk/at91/clk-smd.c b/drivers/clk/at91/clk-smd.c
new file mode 100644
index 0000000..a7cf14a
--- /dev/null
+++ b/drivers/clk/at91/clk-smd.c
@@ -0,0 +1,171 @@
+/*
+ * drivers/clk/at91/clk-smd.c
+ *
+ *  Copyright (C) 2013 Boris BREZILLON <b.brezillon@overkiz.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ */
+
+#include <linux/clk-provider.h>
+#include <linux/clkdev.h>
+#include <linux/clk/at91_pmc.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/io.h>
+
+#include "pmc.h"
+
+#define SMD_SOURCE_MAX		2
+
+#define to_at91sam9x5_clk_smd(hw) \
+	container_of(hw, struct at91sam9x5_clk_smd, hw)
+struct at91sam9x5_clk_smd {
+	struct clk_hw hw;
+	struct at91_pmc *pmc;
+};
+
+static unsigned long at91sam9x5_clk_smd_recalc_rate(struct clk_hw *hw,
+						    unsigned long parent_rate)
+{
+	u32 tmp;
+	u8 smddiv;
+	struct at91sam9x5_clk_smd *smd = to_at91sam9x5_clk_smd(hw);
+	struct at91_pmc *pmc = smd->pmc;
+
+	tmp = pmc_read(pmc, AT91_PMC_SMD);
+	smddiv = (tmp & AT91_PMC_SMD_DIV) >> 8;
+	return parent_rate / (smddiv + 1);
+}
+
+static long at91sam9x5_clk_smd_round_rate(struct clk_hw *hw, unsigned long rate,
+					  unsigned long *parent_rate)
+{
+	unsigned long div;
+	unsigned long bestrate;
+	unsigned long tmp;
+
+	if (rate >= *parent_rate)
+		return *parent_rate;
+
+	div = *parent_rate / rate;
+	if (div > 15)
+		return *parent_rate / 16;
+
+	bestrate = *parent_rate / div;
+	tmp = *parent_rate / (div + 1);
+	if (bestrate - rate > rate - tmp)
+		bestrate = tmp;
+
+	return bestrate;
+}
+
+static int at91sam9x5_clk_smd_set_parent(struct clk_hw *hw, u8 index)
+{
+	u32 tmp;
+	struct at91sam9x5_clk_smd *smd = to_at91sam9x5_clk_smd(hw);
+	struct at91_pmc *pmc = smd->pmc;
+
+	if (index > 1)
+		return -EINVAL;
+	tmp = pmc_read(pmc, AT91_PMC_SMD) & ~AT91_PMC_SMDS;
+	if (index)
+		tmp |= AT91_PMC_SMDS;
+	pmc_write(pmc, AT91_PMC_SMD, tmp);
+	return 0;
+}
+
+static u8 at91sam9x5_clk_smd_get_parent(struct clk_hw *hw)
+{
+	struct at91sam9x5_clk_smd *smd = to_at91sam9x5_clk_smd(hw);
+	struct at91_pmc *pmc = smd->pmc;
+
+	return pmc_read(pmc, AT91_PMC_SMD) & AT91_PMC_SMDS;
+}
+
+static int at91sam9x5_clk_smd_set_rate(struct clk_hw *hw, unsigned long rate,
+				       unsigned long parent_rate)
+{
+	u32 tmp;
+	struct at91sam9x5_clk_smd *smd = to_at91sam9x5_clk_smd(hw);
+	struct at91_pmc *pmc = smd->pmc;
+	unsigned long div = parent_rate / rate;
+
+	if (parent_rate % rate || div < 1 || div > 16)
+		return -EINVAL;
+	tmp = pmc_read(pmc, AT91_PMC_SMD) & ~AT91_PMC_SMD_DIV;
+	tmp |= (div - 1) << 8;
+	pmc_write(pmc, AT91_PMC_SMD, tmp);
+
+	return 0;
+}
+
+static const struct clk_ops at91sam9x5_smd_ops = {
+	.recalc_rate = at91sam9x5_clk_smd_recalc_rate,
+	.round_rate = at91sam9x5_clk_smd_round_rate,
+	.get_parent = at91sam9x5_clk_smd_get_parent,
+	.set_parent = at91sam9x5_clk_smd_set_parent,
+	.set_rate = at91sam9x5_clk_smd_set_rate,
+};
+
+static struct clk * __init
+at91sam9x5_clk_register_smd(struct at91_pmc *pmc, const char *name,
+			    const char **parent_names, u8 num_parents)
+{
+	struct at91sam9x5_clk_smd *smd;
+	struct clk *clk = NULL;
+	struct clk_init_data init;
+
+	smd = kzalloc(sizeof(*smd), GFP_KERNEL);
+	if (!smd)
+		return ERR_PTR(-ENOMEM);
+
+	init.name = name;
+	init.ops = &at91sam9x5_smd_ops;
+	init.parent_names = parent_names;
+	init.num_parents = num_parents;
+	init.flags = CLK_SET_RATE_GATE | CLK_SET_PARENT_GATE;
+
+	smd->hw.init = &init;
+	smd->pmc = pmc;
+
+	clk = clk_register(NULL, &smd->hw);
+
+	if (IS_ERR(clk))
+		kfree(smd);
+
+	return clk;
+}
+
+void __init of_at91sam9x5_clk_smd_setup(struct device_node *np,
+					struct at91_pmc *pmc)
+{
+	struct clk *clk;
+	int i;
+	int num_parents;
+	const char *parent_names[SMD_SOURCE_MAX];
+	const char *name = np->name;
+
+	num_parents = of_count_phandle_with_args(np, "clocks", "#clock-cells");
+	if (num_parents <= 0 || num_parents >= SMD_SOURCE_MAX)
+		return;
+
+	for (i = 0; i < num_parents; i++) {
+		parent_names[i] = of_clk_get_parent_name(np, i);
+		if (!parent_names[i])
+			return;
+	}
+
+	of_property_read_string(np, "clock-output-names", &name);
+
+	clk = at91sam9x5_clk_register_smd(pmc, name, parent_names,
+					  num_parents);
+
+	if (IS_ERR(clk))
+		return;
+
+	of_clk_add_provider(np, of_clk_src_simple_get, clk);
+}
diff --git a/drivers/clk/at91/pmc.c b/drivers/clk/at91/pmc.c
index e46de3d..0a731c8 100644
--- a/drivers/clk/at91/pmc.c
+++ b/drivers/clk/at91/pmc.c
@@ -298,6 +298,13 @@ static const struct of_device_id pmc_clk_ids[] __initdata = {
 		.data = of_at91sam9x5_clk_usb_setup,
 	},
 #endif
+	/* SMD clock */
+#if defined(CONFIG_HAVE_AT91_SMD)
+	{
+		.compatible = "atmel,at91sam9x5-clk-smd",
+		.data = of_at91sam9x5_clk_smd_setup,
+	},
+#endif
 	{ /*sentinel*/ }
 };
 
diff --git a/drivers/clk/at91/pmc.h b/drivers/clk/at91/pmc.h
index b2efff5..43f2516 100644
--- a/drivers/clk/at91/pmc.h
+++ b/drivers/clk/at91/pmc.h
@@ -103,4 +103,9 @@ extern void __init of_at91sam9x5_clk_usb_setup(struct device_node *np,
 					       struct at91_pmc *pmc);
 #endif
 
+#if defined(CONFIG_HAVE_AT91_SMD)
+extern void __init of_at91sam9x5_clk_smd_setup(struct device_node *np,
+					       struct at91_pmc *pmc);
+#endif
+
 #endif /* __PMC_H_ */
-- 
1.7.9.5


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

* [PATCH v3 17/19] clk: at91: add PMC clk device tree binding doc.
  2013-08-08  4:53 [PATCH v3 00/19] ARM: at91: move to common clk framework Boris BREZILLON
                   ` (15 preceding siblings ...)
  2013-08-08  7:17 ` [PATCH v3 16/19] clk: at91: add PMC smd clock Boris BREZILLON
@ 2013-08-08  7:19 ` Boris BREZILLON
  2013-10-08  9:44   ` Nicolas Ferre
  2013-08-08  8:17 ` [PATCH v3 18/19] ARM: at91: move pit timer to common clk framework Boris BREZILLON
                   ` (2 subsequent siblings)
  19 siblings, 1 reply; 54+ messages in thread
From: Boris BREZILLON @ 2013-08-08  7:19 UTC (permalink / raw)
  To: Grant Likely, Rob Herring, Rob Landley, Andrew Victor,
	Nicolas Ferre, Jean-Christophe Plagniol-Villard, Russell King,
	Mike Turquette, Felipe Balbi, Greg Kroah-Hartman,
	Ludovic Desroches, Josh Wu, Richard Genoud
  Cc: devicetree, linux-kernel, linux-arm-kernel, Boris BREZILLON

This patch adds new at91 clks dt bindings documentation.

Signed-off-by: Boris BREZILLON <b.brezillon@overkiz.com>
---
 .../devicetree/bindings/clock/at91-clock.txt       |  312 ++++++++++++++++++++
 1 file changed, 312 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/clock/at91-clock.txt

diff --git a/Documentation/devicetree/bindings/clock/at91-clock.txt b/Documentation/devicetree/bindings/clock/at91-clock.txt
new file mode 100644
index 0000000..04739da
--- /dev/null
+++ b/Documentation/devicetree/bindings/clock/at91-clock.txt
@@ -0,0 +1,312 @@
+Device Tree Clock bindings for arch-at91
+
+This binding uses the common clock binding[1].
+
+[1] Documentation/devicetree/bindings/clock/clock-bindings.txt
+
+Required properties:
+- compatible : shall be one of the following:
+	"atmel,at91rm9200-pmc" or
+	"atmel,at91sam9g45-pmc" or
+	"atmel,at91sam9n12-pmc" or
+	"atmel,at91sam9x5-pmc" or
+	"atmel,at91sam9g35-pmc" or
+	"atmel,sama5d3-pmc":
+		at91 PMC (Power Management Controller)
+		All at91 specific clocks (clocks defined below) must be child
+		node of the PMC node.
+
+	"atmel,at91rm9200-clk-main":
+		at91 main oscillator
+
+	"atmel,at91rm9200-clk-master" or
+	"atmel,at91sam9x5-clk-master":
+		at91 master clock
+
+	"atmel,at91sam9x5-clk-peripheral" or
+	"atmel,at91rm9200-clk-peripheral":
+		at91 peripheral clocks
+
+	"atmel,at91rm9200-clk-pll" or
+	"atmel,at91sam9g45-clk-pll" or
+	"atmel,at91sam9g20-clk-pllb" or
+	"atmel,sama5d3-clk-pll":
+		at91 pll clocks
+
+	"atmel,at91sam9x5-clk-plldiv":
+		at91 plla divisor
+
+	"atmel,at91rm9200-clk-programmable" or
+	"atmel,at91sam9g45-clk-programmable" or
+	"atmel,at91sam9x5-clk-programmable":
+		at91 programmable clocks
+
+	"atmel,at91sam9x5-clk-smd":
+		at91 SMD (Soft Modem) clock
+
+	"atmel,at91rm9200-clk-system":
+		at91 system clocks
+
+	"atmel,at91rm9200-clk-usb" or
+	"atmel,at91sam9x5-clk-usb":
+		at91 usb clock
+
+	"atmel,at91sam9x5-clk-utmi":
+		at91 utmi clock
+
+Required properties for PMC node:
+- reg : defines the IO memory reserved for the PMC.
+- interrupts : shall be set to PMC interrupt line.
+- interrupt-controller : tell that the PMC is an interrupt controller 
+- #interrupt-cells : must be set to 2. The first cell encodes the interrupt id
+		     the second cell encodes the interrupt type.
+For example:
+ 	pmc: pmc@fffffc00 {
+		compatible = "atmel,sama5d3-pmc";
+		interrupts = <AT91_ID_SYS IRQ_TYPE_LEVEL_HIGH 7>;
+		interrupt-controller;
+		#interrupt-cells = <2>;
+
+		/* put at91 clocks here */
+	};
+
+Required properties for main clock:
+- interrupt-parent : must reference the PMC node.
+- interrupts : shall be set to "<AT91_PMC_MOSCS IRQ_TYPE_LEVEL_HIGH>".
+- #clock-cells : from common clock binding; shall be set to 0.
+- clocks (optional if clock-frequency is provided) : shall be the slow clock
+	phandle. This clock is used to compute the main clock rate if
+	"clock-frequency" is not provided.
+- clock-frequency: the main oscillator frequency.Prefer the use of
+	"clock-frequency" over automatic clock rate computation.
+
+For example:
+	main: mainck {
+		compatible = "atmel,at91rm9200-clk-main";
+		interrupt-parent = <&pmc>;
+		interrupts = <AT91_PMC_MOSCS IRQ_TYPE_LEVEL_HIGH>;
+		#clock-cells = <0>;
+		clocks = <&ck32k>;
+		clock-frequency = <18432000>;
+	};
+
+Required properties for master clock:
+- interrupt-parent : must reference the PMC node.
+- interrupts : shall be set to "<AT91_PMC_MCKRDY IRQ_TYPE_LEVEL_HIGH>".
+- #clock-cells : from common clock binding; shall be set to 0.
+- clocks : shall be the master clock sources (see atmel datasheet) phandles.
+	e.g. "<&ck32k>, <&main>, <&plla>, <&pllb>".
+- atmel,clk-output-range : minimum and maximum clock frequency (two u32
+			   fields).
+	   e.g. output = <0 133000000>; <=> 0 to 133MHz.
+- atmel,clk-divisors : master clock divisors table (four u32 fields).
+		0 <=> reserved value.
+		e.g. divisors = <1 2 4 6>;
+- atmel,master-clk-have-div3-pres : some SoC use the reserved value 7 in the
+				    PRES field as CLOCK_DIV3 (e.g sam9x5).
+
+For example:
+	mck: mck {
+		compatible = "atmel,at91rm9200-clk-master";
+		interrupt-parent = <&pmc>;
+		interrupts = <AT91_PMC_MCKRDY IRQ_TYPE_LEVEL_HIGH>;
+		#clock-cells = <0>;
+		atmel,clk-output-range = <0 133000000>;
+		atmel,clk-divisors = <1 2 4 0>;
+	};
+
+Required properties for peripheral clocks:
+- #clock-cells : from common clock binding; shall be set to 1. The second cell
+	is used to encode the peripheral id. Peripheral ids are defined in
+	atmel's SoC datasheets.
+- clocks : shall be the master clock phandle.
+	e.g. clocks = <&mck>;
+- name: device tree node describing a specific system clock.
+	* atmel,clk-id: peripheral id. Peripheral id macros should be used.
+	* atmel,clk-default-divisor (optional, only available for
+	  "atmel,at91sam9x5-clk-peripheral"): sam9x5 and sama5d3 SoC provides
+	  configurable peripheral clock divisor. If you define this property
+	  (u32), the default divisor will be applied when enabling
+	  peripheral clock. If not provided the peripheral clock is not
+	  divided.
+
+For example:
+	periph: periphck {
+		compatible = "atmel,at91sam9x5-clk-peripheral";
+		#clock-cells = <1>;
+		clocks = <&mck>;
+
+		pioA_clk {
+			atmel,clk-id = <AT91SAM9X5_ID_PIOA>;
+			atmel,clk-default-divisor = <1>;
+		};
+
+		pioB_clk {
+			atmel,clk-id = <AT91SAM9X5_ID_PIOB>;
+			atmel,clk-default-divisor = <2>;
+		};
+	};
+
+
+Required properties for pll clocks:
+- interrupt-parent : must reference the PMC node.
+- interrupts : shall be set to "<AT91_PMC_LOCKA IRQ_TYPE_LEVEL_HIGH>".
+- #clock-cells : from common clock binding; shall be set to 0.
+- clocks : shall be the main clock phandle.
+- atmel,clk-id : pll id. PLL id macros should be used.
+- atmel,clk-input-range : minimum and maximum source clock frequency (two u32
+			  fields).
+	  e.g. input = <1 32000000>; <=> 1 to 32MHz.
+- #atmel,pll-clk-output-range-cells : number of cells reserved for pll output
+				      range description. Sould be set to 2, 3
+				      or 4.
+	* 1st and 2nd cells represent the frequency range (min-max).
+	* 3rd cell is optional and represents the OUT field value for the given
+	  range.
+	* 4th cell is optional and represents the ICPLL field (PLLICPR
+	  register)
+- atmel,pll-clk-output-ranges : pll output frequency ranges + optional parameter
+				depending on #atmel,pll-output-range-cells
+				property value.
+
+For example:
+	plla: pllack {
+		compatible = "atmel,at91sam9g45-clk-pll";
+		interrupt-parent = <&pmc>;
+		interrupts = <AT91_PMC_LOCKA IRQ_TYPE_LEVEL_HIGH>;
+		#clock-cells = <0>;
+		clocks = <&main>;
+		atmel,clk-id = <AT91_PLLA_CLK>;
+		atmel,clk-input-range = <2000000 32000000>;
+		#atmel,pll-clk-output-range-cells = <4>;
+		atmel,pll-clk-output-ranges = <74500000 800000000 0 0
+					       69500000 750000000 1 0
+					       64500000 700000000 2 0
+					       59500000 650000000 3 0
+					       54500000 600000000 0 1
+					       49500000 550000000 1 1
+					       44500000 500000000 2 1
+					       40000000 450000000 3 1>;
+	};
+
+Required properties for plldiv clocks:
+- #clock-cells : from common clock binding; shall be set to 0.
+- clocks : shall be the plla clock phandle.
+
+For example:
+	plladiv: plladivck {
+		compatible = "atmel,at91sam9x5-clk-plldiv";
+		#clock-cells = <0>;
+		clocks = <&plla>;
+	};
+
+Required properties for programmable clocks:
+- interrupt-parent : must reference the PMC node.
+- #clock-cells : from common clock binding; shall be set to 1. The second cell
+	is used to encode the programmable clock id.
+	Peripheral ids are in atmel's SoC
+	datasheets.
+- clocks : shall be the programmable clock source phandles.
+	e.g. clocks = <&clk32k>, <&main>, <&plla>, <&pllb>;
+- name: device tree node describing a specific prog clock.
+	* atmel,clk-id : programmable clock id (register offset from  PCKx
+			 register).
+	* interrupts : shall be set to
+		       "<AT91_PMC_PCKRDY(id) IRQ_TYPE_LEVEL_HIGH>".
+
+For example:
+	prog: progck {
+		compatible = "atmel,at91sam9g45-clk-programmable";
+		interrupt-parent = <&pmc>;
+		#clock-cells = <1>;
+		clocks = <&clk32k>, <&main>, <&plladiv>, <&utmi>, <&mck>;
+
+		prog0 {
+			atmel,clk-id = <0>;
+			interrupts = <AT91_PMC_PCKRDY(0) IRQ_TYPE_LEVEL_HIGH>;
+		};
+
+		prog1 {
+			atmel,clk-id = <1>;
+			interrupts = <AT91_PMC_PCKRDY(1) IRQ_TYPE_LEVEL_HIGH>;
+		};
+	};
+
+
+Required properties for smd clock:
+- #clock-cells : from common clock binding; shall be set to 0.
+- clocks : shall be the smd clock source phandles.
+	e.g. clocks = <&plladiv>, <&utmi>;
+
+For example:
+	smd: smdck {
+		compatible = "atmel,at91sam9x5-clk-smd";
+		#clock-cells = <0>;
+		clocks = <&plladiv>, <&utmi>;
+	};
+
+Required properties for system clocks:
+- #clock-cells : from common clock binding; shall be set to 1. The second cell
+	is used to encode the system clock id (bit used in SCER/SCDR register).
+- name: device tree node describing a specific system clock.
+	* id: system clock id (bit position in SCER/SCDR/SCSR registers).
+	      System clock id macros should be used.
+
+For example:
+	system: systemck {
+		compatible = "atmel,at91rm9200-clk-system";
+		#clock-cells = <1>;
+
+		ddrck {
+			atmel,clk-id = <AT91_DDRCK_SYS_CLK>;
+		};
+
+		uhpck {
+			atmel,clk-id = <AT91_UHP_SYS_CLK>;
+		};
+
+		udpck {
+			atmel,clk-id = <AT91_UDP_SYS_CLK>;
+		};
+	};
+
+
+Required properties for usb clock:
+- #clock-cells : from common clock binding; shall be set to 0.
+- clocks : shall be the smd clock source phandles.
+	e.g. clocks = <&pllb>;
+- atmel,clk-divisors (only available for "atmel,at91rm9200-clk-usb"):
+	usb clock divisor table.
+	e.g. divisors = <1 2 4 0>;
+- atmel,usb-clk-src0-unused (only available for "atmel,at91sam9x5-clk-usb"):
+	Some SoC (sam9n12) use usb source 0 to disable the usb clock.
+
+For example:
+	usb: usbck {
+		compatible = "atmel,at91sam9x5-clk-usb";
+		#clock-cells = <0>;
+		clocks = <&plladiv>, <&utmi>;
+	};
+
+	usb: usbck {
+		compatible = "atmel,at91rm9200-clk-usb";
+		#clock-cells = <0>;
+		clocks = <&pllb>;
+		atmel,clk-divisors = <1 2 4 0>;
+	};
+
+
+Required properties for utmi clock:
+- interrupt-parent : must reference the PMC node.
+- interrupts : shall be set to "<AT91_PMC_LOCKU IRQ_TYPE_LEVEL_HIGH>".
+- #clock-cells : from common clock binding; shall be set to 0.
+- clocks : shall be the main clock source phandle.
+
+For example:
+	utmi: utmick {
+		compatible = "atmel,at91sam9x5-clk-utmi";
+		interrupt-parent = <&pmc>;
+		interrupts = <AT91_PMC_LOCKU IRQ_TYPE_LEVEL_HIGH>;
+		#clock-cells = <0>;
+		clocks = <&main>;
+	};
-- 
1.7.9.5


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

* [PATCH v3 18/19] ARM: at91: move pit timer to common clk framework
  2013-08-08  4:53 [PATCH v3 00/19] ARM: at91: move to common clk framework Boris BREZILLON
                   ` (16 preceding siblings ...)
  2013-08-08  7:19 ` [PATCH v3 17/19] clk: at91: add PMC clk device tree binding doc Boris BREZILLON
@ 2013-08-08  8:17 ` Boris BREZILLON
  2013-10-08 16:28   ` Nicolas Ferre
  2013-08-08  8:19 ` [PATCH v3 19/19] ARM: at91: add new compatible strings for pmc driver Boris BREZILLON
  2013-08-20 10:21 ` [PATCH v3 00/19] ARM: at91: move to common clk framework boris brezillon
  19 siblings, 1 reply; 54+ messages in thread
From: Boris BREZILLON @ 2013-08-08  8:17 UTC (permalink / raw)
  To: Grant Likely, Rob Herring, Rob Landley, Andrew Victor,
	Nicolas Ferre, Jean-Christophe Plagniol-Villard, Russell King,
	Mike Turquette, Felipe Balbi, Greg Kroah-Hartman,
	Ludovic Desroches, Josh Wu, Richard Genoud
  Cc: devicetree, linux-kernel, linux-arm-kernel, Boris BREZILLON

Use device tree to get the source clock of the PIT (Periodic Interval Timer).
If the clock is not found in device tree (or dt is not enabled) we'll try to
get it using clk_lookup definitions.

Signed-off-by: Boris BREZILLON <b.brezillon@overkiz.com>
---
 arch/arm/mach-at91/at91sam926x_time.c |   14 +++++++++++++-
 1 file changed, 13 insertions(+), 1 deletion(-)

diff --git a/arch/arm/mach-at91/at91sam926x_time.c b/arch/arm/mach-at91/at91sam926x_time.c
index 3a4bc2e..8ac976a 100644
--- a/arch/arm/mach-at91/at91sam926x_time.c
+++ b/arch/arm/mach-at91/at91sam926x_time.c
@@ -39,6 +39,7 @@
 static u32 pit_cycle;		/* write-once */
 static u32 pit_cnt;		/* access only w/system irq blocked */
 static void __iomem *pit_base_addr __read_mostly;
+static struct clk *mck;
 
 static inline unsigned int pit_read(unsigned int reg_offset)
 {
@@ -195,10 +196,14 @@ static int __init of_at91sam926x_pit_init(void)
 	if (!pit_base_addr)
 		goto node_err;
 
+	mck = of_clk_get(np, 0);
+
 	/* Get the interrupts property */
 	ret = irq_of_parse_and_map(np, 0);
 	if (!ret) {
 		pr_crit("AT91: PIT: Unable to get IRQ from DT\n");
+		if (!IS_ERR(mck))
+			clk_put(mck);
 		goto ioremap_err;
 	}
 	at91sam926x_pit_irq.irq = ret;
@@ -230,6 +235,8 @@ void __init at91sam926x_pit_init(void)
 	unsigned	bits;
 	int		ret;
 
+	mck = ERR_PTR(-ENOENT);
+
 	/* For device tree enabled device: initialize here */
 	of_at91sam926x_pit_init();
 
@@ -237,7 +244,12 @@ void __init at91sam926x_pit_init(void)
 	 * Use our actual MCK to figure out how many MCK/16 ticks per
 	 * 1/HZ period (instead of a compile-time constant LATCH).
 	 */
-	pit_rate = clk_get_rate(clk_get(NULL, "mck")) / 16;
+	if (IS_ERR(mck))
+		mck = clk_get(NULL, "mck");
+
+	if (IS_ERR(mck))
+		panic("AT91: PIT: Unable to get mck clk\n");
+	pit_rate = clk_get_rate(mck) / 16;
 	pit_cycle = (pit_rate + HZ/2) / HZ;
 	WARN_ON(((pit_cycle - 1) & ~AT91_PIT_PIV) != 0);
 
-- 
1.7.9.5


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

* [PATCH v3 19/19] ARM: at91: add new compatible strings for pmc driver
  2013-08-08  4:53 [PATCH v3 00/19] ARM: at91: move to common clk framework Boris BREZILLON
                   ` (17 preceding siblings ...)
  2013-08-08  8:17 ` [PATCH v3 18/19] ARM: at91: move pit timer to common clk framework Boris BREZILLON
@ 2013-08-08  8:19 ` Boris BREZILLON
  2013-10-08 16:29   ` Nicolas Ferre
  2013-08-20 10:21 ` [PATCH v3 00/19] ARM: at91: move to common clk framework boris brezillon
  19 siblings, 1 reply; 54+ messages in thread
From: Boris BREZILLON @ 2013-08-08  8:19 UTC (permalink / raw)
  To: Grant Likely, Rob Herring, Rob Landley, Andrew Victor,
	Nicolas Ferre, Jean-Christophe Plagniol-Villard, Russell King,
	Mike Turquette, Felipe Balbi, Greg Kroah-Hartman,
	Ludovic Desroches, Josh Wu, Richard Genoud
  Cc: devicetree, linux-kernel, linux-arm-kernel, Boris BREZILLON

This patch adds new compatible string for PMC node to prepare the
transition to common clk.

These compatible string come from pmc driver in clk subsystem and are
needed to provide new device tree compatibility with old at91 clks
(device tree using common clks will use the new compatible strings).

Signed-off-by: Boris BREZILLON <b.brezillon@overkiz.com>
---
 arch/arm/mach-at91/clock.c |    6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/arch/arm/mach-at91/clock.c b/arch/arm/mach-at91/clock.c
index 5f02aea..4d4463a 100644
--- a/arch/arm/mach-at91/clock.c
+++ b/arch/arm/mach-at91/clock.c
@@ -884,6 +884,12 @@ static int __init at91_pmc_init(unsigned long main_clock)
 #if defined(CONFIG_OF)
 static struct of_device_id pmc_ids[] = {
 	{ .compatible = "atmel,at91rm9200-pmc" },
+	{ .compatible = "atmel,at91sam9260-pmc" },
+	{ .compatible = "atmel,at91sam9g45-pmc" },
+	{ .compatible = "atmel,at91sam9n12-pmc" },
+	{ .compatible = "atmel,at91sam9x5-pmc" },
+	{ .compatible = "atmel,at91sam9g35-pmc" },
+	{ .compatible = "atmel,sama5d3-pmc" },
 	{ /*sentinel*/ }
 };
 
-- 
1.7.9.5


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

* Re: [PATCH v3 00/19] ARM: at91: move to common clk framework
  2013-08-08  4:53 [PATCH v3 00/19] ARM: at91: move to common clk framework Boris BREZILLON
                   ` (18 preceding siblings ...)
  2013-08-08  8:19 ` [PATCH v3 19/19] ARM: at91: add new compatible strings for pmc driver Boris BREZILLON
@ 2013-08-20 10:21 ` boris brezillon
  19 siblings, 0 replies; 54+ messages in thread
From: boris brezillon @ 2013-08-20 10:21 UTC (permalink / raw)
  To: Mike Turquette
  Cc: Boris BREZILLON, Grant Likely, Rob Herring, Rob Landley,
	Andrew Victor, Nicolas Ferre, Jean-Christophe Plagniol-Villard,
	Russell King, Felipe Balbi, Greg Kroah-Hartman,
	Ludovic Desroches, Josh Wu, devicetree, linux-kernel,
	linux-arm-kernel

Hello Mike,

Could you take a look at this patch series ?

I'd like to have your opinion on some key points:

- at91 clk dt bindings
- in some clk_prepare (pll clks, main clk) callbacks I make use of 
wait_event to wait for an interrupt.
   Should I do it this way or instead use the cpu_relax function ?
- some clks define clk_prepare but not clk_enable (enabling work is done 
in clk_prepare).
   Is it okay to leave this callback empty and rely on the default 
behaviour (enable count increment) ?
- at91 clk implemetation in its whole


Best Regards,

Boris

On 08/08/2013 06:53, Boris BREZILLON wrote:
> Hello,
>
> This patch series is the 3rd version of the new at91 clock implementation
> (using common clk framework).
>
> Most of the clock provided by the PMC (Power Management Controller) are
> implemented :
> - main clock (main oscillator)
> - pll clocks
> - master clock
> - programmable clocks
> - utmi clock
> - peripheral clocks
> - system clocks
>
> This implementation is only compatible with device tree definition.
> The goal is to define the whole clock tree in the device tree.
>
> Please feel free to comment the dt bindinds.
>
> This patch series is based on linux-next and has been tested on sama5d31ek
> board using device tree. It compiles for other SoCs and both with and
> but it has not been tested (Richard, I did not add your Tested-by because
> a lot of things have changed since v2).
>
> BTW could other people test it on other boards (I only have a kizbox and
> a sama5d31ek dev kit).
>
> Best Regards,
> Boris
>
> Changes since v2:
>   - fix several bugs in clk implementations
>   - drop non-dt boards support
>   - split the series to ease review and tests:
>     * 1 patch series for new clk implementations (this series)
>     * 1 patch series to move each at91 SoC to common clk framework (coming soon)
>   - modify dt-bindings (add atmel,clk- prefix to atmel specific properties)
>   - add clk macros for dt-bindings
>   - add pmc framework (helper function to access pmc registers)
>   - add interrupt support to enable passive wait in clk_prepare functions
>
> Changes since v1:
>   - fix bugs in pll, programmable and system clock implementations
>     (wrong bit position).
>   - add usb clock configuration support (ohci and udc drivers +
>     clk_lookup for non dt boards)
>   - rework of the system clock interfaces (no need to define a parent clock,
>     system clock is a gate with no rate info)
>   - change system, peripheral and programmable clk dt bindings (1 master node
>     and multiple child nodes each defining a system/peripheral or prog clock)
>   - fix bugs in sama5 dt definition
>
> Boris BREZILLON (19):
>    ARM: at91: move at91_pmc.h to include/linux/clk/at91_pmc.h
>    ARM: at91: add Kconfig options for common clk support
>    clk: at91: add PMC base support
>    clk: at91: add PMC macro file for dt definitions
>    clk: at91: add PMC main clock
>    clk: at91: add PMC pll clocks
>    clk: at91: add pll id macros for pll dt bindings
>    clk: at91: add PMC master clock
>    clk: at91: add PMC system clocks
>    ARM: at91/dt: add system clk id definitions in dt-bindings include
>      dir
>    clk: at91: add PMC peripheral clocks
>    clk: at91: add peripheral clk macros for peripheral clk dt bindings
>    clk: at91: add PMC programmable clocks
>    clk: at91: add PMC utmi clock
>    clk: at91: add PMC usb clock
>    clk: at91: add PMC smd clock
>    clk: at91: add PMC clk device tree binding doc.
>    ARM: at91: move pit timer to common clk framework
>    ARM: at91: add new compatible strings for pmc driver
>
>   .../devicetree/bindings/clock/at91-clock.txt       |  312 ++++++++++++
>   arch/arm/mach-at91/Kconfig                         |   44 ++
>   arch/arm/mach-at91/Kconfig.non_dt                  |    6 +
>   arch/arm/mach-at91/Makefile                        |    2 +-
>   arch/arm/mach-at91/at91rm9200.c                    |    2 +-
>   arch/arm/mach-at91/at91sam9260.c                   |    2 +-
>   arch/arm/mach-at91/at91sam9261.c                   |    2 +-
>   arch/arm/mach-at91/at91sam9263.c                   |    2 +-
>   arch/arm/mach-at91/at91sam926x_time.c              |   14 +-
>   arch/arm/mach-at91/at91sam9g45.c                   |    2 +-
>   arch/arm/mach-at91/at91sam9n12.c                   |    2 +-
>   arch/arm/mach-at91/at91sam9rl.c                    |    2 +-
>   arch/arm/mach-at91/at91sam9x5.c                    |    2 +-
>   arch/arm/mach-at91/clock.c                         |    8 +-
>   arch/arm/mach-at91/generic.h                       |    3 +-
>   arch/arm/mach-at91/pm.c                            |    2 +-
>   arch/arm/mach-at91/pm_slowclock.S                  |    2 +-
>   arch/arm/mach-at91/sama5d3.c                       |    2 +-
>   arch/arm/mach-at91/setup.c                         |    8 +-
>   drivers/clk/Makefile                               |    1 +
>   drivers/clk/at91/Makefile                          |   12 +
>   drivers/clk/at91/clk-main.c                        |  171 +++++++
>   drivers/clk/at91/clk-master.c                      |  386 +++++++++++++++
>   drivers/clk/at91/clk-peripheral.c                  |  401 ++++++++++++++++
>   drivers/clk/at91/clk-pll.c                         |  506 ++++++++++++++++++++
>   drivers/clk/at91/clk-plldiv.c                      |  137 ++++++
>   drivers/clk/at91/clk-programmable.c                |  419 ++++++++++++++++
>   drivers/clk/at91/clk-smd.c                         |  171 +++++++
>   drivers/clk/at91/clk-system.c                      |  191 ++++++++
>   drivers/clk/at91/clk-usb.c                         |  323 +++++++++++++
>   drivers/clk/at91/clk-utmi.c                        |  161 +++++++
>   drivers/clk/at91/pmc.c                             |  387 +++++++++++++++
>   drivers/clk/at91/pmc.h                             |  111 +++++
>   drivers/usb/gadget/atmel_usba_udc.c                |    2 +-
>   .../dt-bindings/clk/at91/at91rm9200/clk-system.h   |   16 +
>   .../dt-bindings/clk/at91/at91sam9261/clk-system.h  |   15 +
>   .../clk/at91/at91sam9x5/clk-peripheral.h           |   15 +
>   include/dt-bindings/clk/at91/common/clk-pll.h      |   13 +
>   include/dt-bindings/clk/at91/common/clk-system.h   |   21 +
>   include/dt-bindings/clk/at91/common/pmc.h          |   20 +
>   .../include/mach => include/linux/clk}/at91_pmc.h  |    4 +-
>   41 files changed, 3882 insertions(+), 20 deletions(-)
>   create mode 100644 Documentation/devicetree/bindings/clock/at91-clock.txt
>   create mode 100644 drivers/clk/at91/Makefile
>   create mode 100644 drivers/clk/at91/clk-main.c
>   create mode 100644 drivers/clk/at91/clk-master.c
>   create mode 100644 drivers/clk/at91/clk-peripheral.c
>   create mode 100644 drivers/clk/at91/clk-pll.c
>   create mode 100644 drivers/clk/at91/clk-plldiv.c
>   create mode 100644 drivers/clk/at91/clk-programmable.c
>   create mode 100644 drivers/clk/at91/clk-smd.c
>   create mode 100644 drivers/clk/at91/clk-system.c
>   create mode 100644 drivers/clk/at91/clk-usb.c
>   create mode 100644 drivers/clk/at91/clk-utmi.c
>   create mode 100644 drivers/clk/at91/pmc.c
>   create mode 100644 drivers/clk/at91/pmc.h
>   create mode 100644 include/dt-bindings/clk/at91/at91rm9200/clk-system.h
>   create mode 100644 include/dt-bindings/clk/at91/at91sam9261/clk-system.h
>   create mode 100644 include/dt-bindings/clk/at91/at91sam9x5/clk-peripheral.h
>   create mode 100644 include/dt-bindings/clk/at91/common/clk-pll.h
>   create mode 100644 include/dt-bindings/clk/at91/common/clk-system.h
>   create mode 100644 include/dt-bindings/clk/at91/common/pmc.h
>   rename {arch/arm/mach-at91/include/mach => include/linux/clk}/at91_pmc.h (98%)
>


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

* Re: [PATCH v3 03/19] clk: at91: add PMC base support
  2013-08-08  5:01 ` [PATCH v3 03/19] clk: at91: add PMC base support Boris BREZILLON
@ 2013-10-07 15:07   ` Nicolas Ferre
  2013-10-07 15:57     ` boris brezillon
  0 siblings, 1 reply; 54+ messages in thread
From: Nicolas Ferre @ 2013-10-07 15:07 UTC (permalink / raw)
  To: Boris BREZILLON, Grant Likely, Rob Herring, Rob Landley,
	Andrew Victor, Jean-Christophe Plagniol-Villard, Russell King,
	Mike Turquette, Felipe Balbi, Greg Kroah-Hartman,
	Ludovic Desroches, Josh Wu, Richard Genoud
  Cc: devicetree, linux-kernel, linux-arm-kernel

On 08/08/2013 07:01, Boris BREZILLON :
> This patch adds at91 PMC (Power Management Controller) base support.
>
> All at91 clocks managed by the PMC unit will use this framework.
>
> This framework provides the following fonctionalities:
> - define a new struct at91_pmc to hide PMC internals (lock, PMC memory
>    mapping, irq domain, ...)
> - read/write helper functions (pmc_read/write) to access PMC registers
> - lock/unlock helper functions (pmc_lock/unlock) to lock/unlock access to
>    pmc registers
> - a new irq domain and its associated irq chip to request PMC specific
>    interrupts (useful for clk prepare callbacks)
>
> The PMC unit is declared as a dt clk provider (CLK_OF_DECLARE), and every
> clk using this framework will declare a table of of_at91_clk_init_cb_t
> and add it to the pmc_clk_ids table.
>
> When the pmc dt clock setup function is called (by of_clk_init function),
> it triggers the registration of every supported child clk (those matching
> the definitions in pmc_clk_ids).
>
> This patch copies at91_pmc_base (memory mapping) and at91sam9_idle
> (function) from arch/arm/mach-at91/clock.c (which is not compiled if
> COMMON_CLK_AT91 is enabled).
>
> Signed-off-by: Boris BREZILLON <b.brezillon@overkiz.com>
> ---
>   drivers/clk/Makefile      |    1 +
>   drivers/clk/at91/Makefile |    5 +
>   drivers/clk/at91/pmc.c    |  298 +++++++++++++++++++++++++++++++++++++++++++++
>   drivers/clk/at91/pmc.h    |   58 +++++++++
>   4 files changed, 362 insertions(+)
>   create mode 100644 drivers/clk/at91/Makefile
>   create mode 100644 drivers/clk/at91/pmc.c
>   create mode 100644 drivers/clk/at91/pmc.h
>
> diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile
> index 4038c2b..c256a20 100644
> --- a/drivers/clk/Makefile
> +++ b/drivers/clk/Makefile
> @@ -32,6 +32,7 @@ obj-$(CONFIG_ARCH_VT8500)	+= clk-vt8500.o
>   obj-$(CONFIG_ARCH_ZYNQ)		+= zynq/
>   obj-$(CONFIG_ARCH_TEGRA)	+= tegra/
>   obj-$(CONFIG_PLAT_SAMSUNG)	+= samsung/
> +obj-$(CONFIG_COMMON_CLK_AT91)	+= at91/
>
>   obj-$(CONFIG_X86)		+= x86/
>
> diff --git a/drivers/clk/at91/Makefile b/drivers/clk/at91/Makefile
> new file mode 100644
> index 0000000..1d4fb21
> --- /dev/null
> +++ b/drivers/clk/at91/Makefile
> @@ -0,0 +1,5 @@
> +#
> +# Makefile for at91 specific clk
> +#
> +
> +obj-y += pmc.o
> diff --git a/drivers/clk/at91/pmc.c b/drivers/clk/at91/pmc.c
> new file mode 100644
> index 0000000..f6bd03d
> --- /dev/null
> +++ b/drivers/clk/at91/pmc.c
> @@ -0,0 +1,298 @@
> +/*
> + * drivers/clk/at91/pmc.c
> + *
> + *  Copyright (C) 2013 Boris BREZILLON <b.brezillon@overkiz.com>
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License as published by
> + * the Free Software Foundation; either version 2 of the License, or
> + * (at your option) any later version.
> + *
> + */
> +
> +#include <linux/clk-provider.h>
> +#include <linux/clkdev.h>
> +#include <linux/clk/at91_pmc.h>
> +#include <linux/of.h>
> +#include <linux/of_address.h>
> +#include <linux/io.h>
> +#include <linux/interrupt.h>
> +#include <linux/irq.h>
> +#include <linux/irqchip/chained_irq.h>
> +#include <linux/irqdomain.h>
> +#include <linux/of_irq.h>
> +
> +#include <asm/proc-fns.h>
> +
> +#include "pmc.h"
> +
> +void __iomem *at91_pmc_base;
> +EXPORT_SYMBOL_GPL(at91_pmc_base);
> +
> +void at91sam9_idle(void)
> +{
> +	at91_pmc_write(AT91_PMC_SCDR, AT91_PMC_PCK);
> +	cpu_do_idle();
> +}
> +
> +static void pmc_irq_mask(struct irq_data *d)
> +{
> +	struct at91_pmc *pmc = irq_data_get_irq_chip_data(d);
> +
> +	pmc_write(pmc, AT91_PMC_IDR, 1 << d->hwirq);
> +}
> +
> +static void pmc_irq_unmask(struct irq_data *d)
> +{
> +	struct at91_pmc *pmc = irq_data_get_irq_chip_data(d);
> +
> +	pmc_write(pmc, AT91_PMC_IER, 1 << d->hwirq);
> +}
> +
> +static int pmc_irq_set_type(struct irq_data *d, unsigned type)
> +{
> +	if (type != IRQ_TYPE_LEVEL_HIGH) {
> +		pr_warn("PMC: type not supported (support only IRQ_TYPE_LEVEL_HIGH type)\n");
> +		return -EINVAL;
> +	}
> +
> +	return 0;
> +}
> +
> +static struct irq_chip pmc_irq = {
> +	.name = "PMC",
> +	.irq_disable = pmc_irq_mask,
> +	.irq_mask = pmc_irq_mask,
> +	.irq_unmask = pmc_irq_unmask,
> +	.irq_set_type = pmc_irq_set_type,
> +};
> +
> +static struct lock_class_key pmc_lock_class;
> +
> +static int pmc_irq_map(struct irq_domain *h, unsigned int virq,
> +		       irq_hw_number_t hw)
> +{
> +	struct at91_pmc	*pmc = h->host_data;
> +
> +	irq_set_lockdep_class(virq, &pmc_lock_class);
> +
> +	irq_set_chip_and_handler(virq, &pmc_irq,
> +				 handle_level_irq);
> +	set_irq_flags(virq, IRQF_VALID);
> +	irq_set_chip_data(virq, pmc);
> +
> +	return 0;
> +}
> +
> +static int pmc_irq_domain_xlate(struct irq_domain *d,
> +				struct device_node *ctrlr,
> +				const u32 *intspec, unsigned int intsize,
> +				irq_hw_number_t *out_hwirq,
> +				unsigned int *out_type)
> +{
> +	struct at91_pmc *pmc = d->host_data;
> +	const struct at91_pmc_caps *caps = pmc->caps;
> +
> +	if (WARN_ON(intsize < 2))
> +		return -EINVAL;
> +	*out_hwirq = intspec[0];
> +	*out_type = intspec[1] & IRQ_TYPE_SENSE_MASK;
> +
> +	if (!(caps->available_irqs & (1 << *out_hwirq)))
> +		return -EINVAL;
> +
> +	if (*out_type != IRQ_TYPE_LEVEL_HIGH)
> +		return -EINVAL;
> +
> +	return 0;
> +}
> +
> +static struct irq_domain_ops pmc_irq_ops = {
> +	.map	= pmc_irq_map,
> +	.xlate	= pmc_irq_domain_xlate,
> +};
> +
> +static irqreturn_t pmc_irq_handler(int irq, void *data)
> +{
> +	struct at91_pmc *pmc = (struct at91_pmc *)data;
> +	unsigned long sr;
> +	int n;
> +
> +	sr = pmc_read(pmc, AT91_PMC_SR) & pmc_read(pmc, AT91_PMC_IMR);
> +	if (!sr)
> +		return IRQ_NONE;
> +
> +	for_each_set_bit(n, &sr, BITS_PER_LONG)
> +		generic_handle_irq(irq_find_mapping(pmc->irqdomain, n));
> +
> +	return IRQ_HANDLED;
> +}
> +
> +static const struct at91_pmc_caps at91rm9200_caps = {
> +	.available_irqs = AT91_PMC_MOSCS | AT91_PMC_LOCKA | AT91_PMC_LOCKB |
> +			  AT91_PMC_MCKRDY | AT91_PMC_PCK0RDY |
> +			  AT91_PMC_PCK1RDY | AT91_PMC_PCK2RDY |
> +			  AT91_PMC_PCK3RDY,
> +};
> +
> +static const struct at91_pmc_caps at91sam9260_caps = {
> +	.available_irqs = AT91_PMC_MOSCS | AT91_PMC_LOCKA | AT91_PMC_LOCKB |
> +			  AT91_PMC_MCKRDY | AT91_PMC_PCK0RDY |
> +			  AT91_PMC_PCK1RDY,
> +};
> +
> +static const struct at91_pmc_caps at91sam9g45_caps = {
> +	.available_irqs = AT91_PMC_MOSCS | AT91_PMC_LOCKA | AT91_PMC_MCKRDY |
> +			  AT91_PMC_LOCKU | AT91_PMC_PCK0RDY |
> +			  AT91_PMC_PCK1RDY,
> +};
> +
> +static const struct at91_pmc_caps at91sam9n12_caps = {
> +	.available_irqs = AT91_PMC_MOSCS | AT91_PMC_LOCKA | AT91_PMC_LOCKB |
> +			  AT91_PMC_MCKRDY | AT91_PMC_PCK0RDY |
> +			  AT91_PMC_PCK1RDY | AT91_PMC_MOSCSELS |
> +			  AT91_PMC_MOSCRCS | AT91_PMC_CFDEV,
> +};
> +
> +static const struct at91_pmc_caps at91sam9x5_caps = {
> +	.available_irqs = AT91_PMC_MOSCS | AT91_PMC_LOCKA | AT91_PMC_MCKRDY |
> +			  AT91_PMC_LOCKU | AT91_PMC_PCK0RDY |
> +			  AT91_PMC_PCK1RDY | AT91_PMC_MOSCSELS |
> +			  AT91_PMC_MOSCRCS | AT91_PMC_CFDEV,
> +};
> +
> +static const struct at91_pmc_caps at91sam9g35_caps = {
> +	.available_irqs = AT91_PMC_MOSCS | AT91_PMC_LOCKA | AT91_PMC_MCKRDY |
> +			  AT91_PMC_PCK0RDY | AT91_PMC_PCK1RDY |
> +			  AT91_PMC_MOSCSELS | AT91_PMC_MOSCRCS |
> +			  AT91_PMC_CFDEV,

9g35 is part of 9x5 series. It is not different from its other fellow SoCs.
(but it is true that the datasheet has changed recently in relation with 
this missing LOCKU bit ;-) ).

So I suspect that we can remove all definitions of at91sam9g35 and merge 
them with 9x5 ones (including compatibility string).

> +};
> +
> +static const struct at91_pmc_caps sama5d3_caps = {
> +	.available_irqs = AT91_PMC_MOSCS | AT91_PMC_LOCKA | AT91_PMC_MCKRDY |
> +			  AT91_PMC_LOCKU | AT91_PMC_PCK0RDY |
> +			  AT91_PMC_PCK1RDY | AT91_PMC_PCK2RDY |
> +			  AT91_PMC_MOSCSELS | AT91_PMC_MOSCRCS |
> +			  AT91_PMC_CFDEV,
> +};
> +
> +static struct at91_pmc *__init at91_pmc_init(struct device_node *np,
> +					     void __iomem *regbase, int virq,
> +					     const struct at91_pmc_caps *caps)
> +{
> +	struct at91_pmc *pmc;
> +
> +	if (!regbase || !virq ||  !caps)
> +		return NULL;
> +
> +	at91_pmc_base = regbase;
> +
> +	pmc = kzalloc(sizeof(*pmc), GFP_KERNEL);
> +	if (!pmc)
> +		return NULL;
> +
> +	spin_lock_init(&pmc->lock);
> +	pmc->regbase = regbase;
> +	pmc->virq = virq;
> +	pmc->caps = caps;
> +
> +	pmc->irqdomain = irq_domain_add_linear(np, 32, &pmc_irq_ops, pmc);
> +
> +	if (!pmc->irqdomain)
> +		goto out_free_pmc;
> +
> +	pmc_write(pmc, AT91_PMC_IDR, 0xffffffff);
> +	if (request_irq(pmc->virq, pmc_irq_handler, IRQF_SHARED, "pmc", pmc))
> +		goto out_remove_irqdomain;
> +
> +	return pmc;
> +
> +out_remove_irqdomain:
> +	irq_domain_remove(pmc->irqdomain);
> +out_free_pmc:
> +	kfree(pmc);
> +
> +	return NULL;
> +}
> +
> +static const struct of_device_id pmc_clk_ids[] __initdata = {
> +	{ /*sentinel*/ }
> +};
> +
> +static void __init of_at91_pmc_setup(struct device_node *np,
> +				     const struct at91_pmc_caps *caps)
> +{
> +	struct at91_pmc *pmc;
> +	struct device_node *childnp;
> +	void (*clk_setup)(struct device_node *, struct at91_pmc *);
> +	const struct of_device_id *clk_id;
> +	void __iomem *regbase = of_iomap(np, 0);
> +	int virq;
> +
> +	if (!regbase)
> +		return;
> +
> +	virq = irq_of_parse_and_map(np, 0);
> +	if (!virq)
> +		return;
> +
> +	pmc = at91_pmc_init(np, regbase, virq, caps);
> +	if (!pmc)
> +		return;
> +	for_each_child_of_node(np, childnp) {
> +		clk_id = of_match_node(pmc_clk_ids, childnp);
> +		if (!clk_id)
> +			continue;
> +		clk_setup = clk_id->data;
> +		clk_setup(childnp, pmc);
> +	}
> +}
> +
> +static void __init of_at91rm9200_pmc_setup(struct device_node *np)
> +{
> +	of_at91_pmc_setup(np, &at91rm9200_caps);
> +}
> +CLK_OF_DECLARE(at91rm9200_clk_main, "atmel,at91rm9200-pmc",
> +	       of_at91rm9200_pmc_setup);
> +
> +static void __init of_at91sam9260_pmc_setup(struct device_node *np)
> +{
> +	of_at91_pmc_setup(np, &at91sam9260_caps);
> +}
> +CLK_OF_DECLARE(at91sam9260_clk_main, "atmel,at91sam9260-pmc",
> +	       of_at91sam9260_pmc_setup);
> +
> +static void __init of_at91sam9g45_pmc_setup(struct device_node *np)
> +{
> +	of_at91_pmc_setup(np, &at91sam9g45_caps);
> +}
> +CLK_OF_DECLARE(at91sam9g45_clk_main, "atmel,at91sam9g45-pmc",
> +	       of_at91sam9g45_pmc_setup);
> +
> +static void __init of_at91sam9n12_pmc_setup(struct device_node *np)
> +{
> +	of_at91_pmc_setup(np, &at91sam9n12_caps);
> +}
> +CLK_OF_DECLARE(at91sam9n12_clk_main, "atmel,at91sam9n12-pmc",
> +	       of_at91sam9n12_pmc_setup);
> +
> +static void __init of_at91sam9x5_pmc_setup(struct device_node *np)
> +{
> +	of_at91_pmc_setup(np, &at91sam9x5_caps);
> +}
> +CLK_OF_DECLARE(at91sam9x5_clk_main, "atmel,at91sam9x5-pmc",
> +	       of_at91sam9x5_pmc_setup);
> +
> +static void __init of_at91sam9g35_pmc_setup(struct device_node *np)
> +{
> +	of_at91_pmc_setup(np, &at91sam9g35_caps);
> +}
> +CLK_OF_DECLARE(at91sam9g35_clk_main, "atmel,at91sam9g35-pmc",
> +	       of_at91sam9g35_pmc_setup);

Ditto.

> +
> +static void __init of_sama5d3_pmc_setup(struct device_node *np)
> +{
> +	of_at91_pmc_setup(np, &sama5d3_caps);
> +}
> +CLK_OF_DECLARE(sama5d3_clk_main, "atmel,sama5d3-pmc",
> +	       of_sama5d3_pmc_setup);
> diff --git a/drivers/clk/at91/pmc.h b/drivers/clk/at91/pmc.h
> new file mode 100644
> index 0000000..b7e8397
> --- /dev/null
> +++ b/drivers/clk/at91/pmc.h
> @@ -0,0 +1,58 @@
> +/*
> + * drivers/clk/at91/pmc.h
> + *
> + *  Copyright (C) 2013 Boris BREZILLON <b.brezillon@overkiz.com>
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License as published by
> + * the Free Software Foundation; either version 2 of the License, or
> + * (at your option) any later version.
> + */
> +
> +#ifndef __PMC_H_
> +#define __PMC_H_
> +
> +#include <linux/io.h>
> +#include <linux/irqdomain.h>
> +#include <linux/spinlock.h>
> +
> +struct clk_range {
> +	unsigned long min;
> +	unsigned long max;
> +};
> +
> +#define CLK_RANGE(MIN, MAX) {.min = MIN, .max = MAX,}
> +
> +struct at91_pmc_caps {
> +	u32 available_irqs;
> +};
> +
> +struct at91_pmc {
> +	void __iomem *regbase;
> +	int virq;
> +	spinlock_t lock;
> +	const struct at91_pmc_caps *caps;
> +	struct irq_domain *irqdomain;
> +};
> +
> +static inline void pmc_lock(struct at91_pmc *pmc)
> +{
> +	spin_lock(&pmc->lock);
> +}
> +
> +static inline void pmc_unlock(struct at91_pmc *pmc)
> +{
> +	spin_unlock(&pmc->lock);
> +}
> +
> +static inline u32 pmc_read(struct at91_pmc *pmc, int offset)
> +{
> +	return readl_relaxed(pmc->regbase + offset);
> +}
> +
> +static inline void pmc_write(struct at91_pmc *pmc, int offset, u32 value)
> +{
> +	return writel_relaxed(value, pmc->regbase + offset);
> +}
> +
> +#endif /* __PMC_H_ */
>


-- 
Nicolas Ferre

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

* Re: [PATCH v3 02/19] ARM: at91: add Kconfig options for common clk support
  2013-08-08  5:02 ` [PATCH v3 02/19] ARM: at91: add Kconfig options for common clk support Boris BREZILLON
@ 2013-10-07 15:12   ` Nicolas Ferre
  2013-10-07 16:05     ` boris brezillon
  2013-10-09  9:56     ` boris brezillon
  0 siblings, 2 replies; 54+ messages in thread
From: Nicolas Ferre @ 2013-10-07 15:12 UTC (permalink / raw)
  To: Boris BREZILLON, Grant Likely, Rob Herring, Rob Landley,
	Andrew Victor, Jean-Christophe Plagniol-Villard, Russell King,
	Mike Turquette, Felipe Balbi, Greg Kroah-Hartman,
	Ludovic Desroches, Josh Wu, Richard Genoud
  Cc: devicetree, linux-kernel, linux-arm-kernel

On 08/08/2013 07:02, Boris BREZILLON :
> This patch adds the following Kconfig options to prepare the transition to
> common clk framework:
>
> - AT91_USE_OLD_CLK: this option is selected by every SoC which does not
>    support new at91 clks based on common clk framework (SoC which does not
>    define the clock tree in its device tree).
>    This options is also selected when the user choose non dt boards support
>    (new at91 clks can only be registered from a device tree definition).
>
> - COMMON_CLK_AT91: this option cannot be selected directly. Instead it is

I would have prefered to keep "AT91" as a prefix => "AT91_COMMON_CLK"
But it is not so important.

>    enabled if these 3 conditions are met:
>     * at least one of the selected SoCs have a PMC (Power Management
>       Controller) Unit
>     * device tree support is enabled
>     * the old at91 clk implementation is disabled (every selected SoC define
>       its clks in its device tree and non dt boards support is disabled)
>
> - OLD_CLK_AT91: this option cannot be selected directly. Instead it is

Here also.

>    enabled if these 2 conditions are met:
>     * at least one of the selected SoCs have a PMC (Power Management
>       Controller) Unit
>     * at least one of the selected SoCs does not define its clks in its
>       device tree or non dt-boards support is enabled
>
> This patch selects AT91_USE_OLD_CLK in all currently supported SoCs. These
> selects will be removed after clk definitions are properly added in each
> soc's device tree.
> It also selects AT91_USE_OLD_CLK in all non-dt boards support.
>
> AT91_PMC_UNIT references are replaced by OLD_CLK_AT91, because PMC Unit is
> enabled for both old and common clk implementations, and old clk
> implementation should not be compiled if COMMON_CLK is enabled.
>
> To avoid future link errors, a new stub is created for at91_dt_clock_init
> function if OLD_CLK_AT91 is disabled.
>
> A new check is added in dt init functions (setup.c) to prepare for SoCs
> supporting new clk implementation. These SoCs won't setup the
> register_clocks callback (clk registration is done using of_clk_init).
>
> Signed-off-by: Boris BREZILLON <b.brezillon@overkiz.com>
> ---
>   arch/arm/mach-at91/Kconfig        |   21 +++++++++++++++++++++
>   arch/arm/mach-at91/Kconfig.non_dt |    6 ++++++
>   arch/arm/mach-at91/Makefile       |    2 +-
>   arch/arm/mach-at91/generic.h      |    3 ++-
>   arch/arm/mach-at91/setup.c        |    6 ++++--
>   5 files changed, 34 insertions(+), 4 deletions(-)
>
> diff --git a/arch/arm/mach-at91/Kconfig b/arch/arm/mach-at91/Kconfig
> index 699b71e..85b53a4 100644
> --- a/arch/arm/mach-at91/Kconfig
> +++ b/arch/arm/mach-at91/Kconfig
> @@ -6,10 +6,22 @@ config HAVE_AT91_DBGU0
>   config HAVE_AT91_DBGU1
>   	bool
>
> +config AT91_USE_OLD_CLK
> +	bool
> +
>   config AT91_PMC_UNIT
>   	bool
>   	default !ARCH_AT91X40
>
> +config COMMON_CLK_AT91
> +	bool
> +	default AT91_PMC_UNIT && USE_OF && !AT91_USE_OLD_CLK
> +	select COMMON_CLK
> +
> +config OLD_CLK_AT91
> +	bool
> +	default AT91_PMC_UNIT && AT91_USE_OLD_CLK
> +
>   config AT91_SAM9_ALT_RESET
>   	bool
>   	default !ARCH_AT91X40
> @@ -65,6 +77,7 @@ config SOC_SAMA5D3
>   	select SOC_SAMA5
>   	select HAVE_FB_ATMEL
>   	select HAVE_AT91_DBGU1
> +	select AT91_USE_OLD_CLK
>   	help
>   	  Select this if you are using one of Atmel's SAMA5D3 family SoC.
>   	  This support covers SAMA5D31, SAMA5D33, SAMA5D34, SAMA5D35.
> @@ -78,11 +91,13 @@ config SOC_AT91RM9200
>   	select HAVE_AT91_DBGU0
>   	select MULTI_IRQ_HANDLER
>   	select SPARSE_IRQ
> +	select AT91_USE_OLD_CLK
>
>   config SOC_AT91SAM9260
>   	bool "AT91SAM9260, AT91SAM9XE or AT91SAM9G20"
>   	select HAVE_AT91_DBGU0
>   	select SOC_AT91SAM9
> +	select AT91_USE_OLD_CLK
>   	help
>   	  Select this if you are using one of Atmel's AT91SAM9260, AT91SAM9XE
>   	  or AT91SAM9G20 SoC.
> @@ -92,6 +107,7 @@ config SOC_AT91SAM9261
>   	select HAVE_AT91_DBGU0
>   	select HAVE_FB_ATMEL
>   	select SOC_AT91SAM9
> +	select AT91_USE_OLD_CLK
>   	help
>   	  Select this if you are using one of Atmel's AT91SAM9261 or AT91SAM9G10 SoC.
>
> @@ -100,18 +116,21 @@ config SOC_AT91SAM9263
>   	select HAVE_AT91_DBGU1
>   	select HAVE_FB_ATMEL
>   	select SOC_AT91SAM9
> +	select AT91_USE_OLD_CLK
>
>   config SOC_AT91SAM9RL
>   	bool "AT91SAM9RL"
>   	select HAVE_AT91_DBGU0
>   	select HAVE_FB_ATMEL
>   	select SOC_AT91SAM9
> +	select AT91_USE_OLD_CLK
>
>   config SOC_AT91SAM9G45
>   	bool "AT91SAM9G45 or AT91SAM9M10 families"
>   	select HAVE_AT91_DBGU1
>   	select HAVE_FB_ATMEL
>   	select SOC_AT91SAM9
> +	select AT91_USE_OLD_CLK
>   	help
>   	  Select this if you are using one of Atmel's AT91SAM9G45 family SoC.
>   	  This support covers AT91SAM9G45, AT91SAM9G46, AT91SAM9M10 and AT91SAM9M11.
> @@ -121,6 +140,7 @@ config SOC_AT91SAM9X5
>   	select HAVE_AT91_DBGU0
>   	select HAVE_FB_ATMEL
>   	select SOC_AT91SAM9
> +	select AT91_USE_OLD_CLK
>   	help
>   	  Select this if you are using one of Atmel's AT91SAM9x5 family SoC.
>   	  This means that your SAM9 name finishes with a '5' (except if it is
> @@ -133,6 +153,7 @@ config SOC_AT91SAM9N12
>   	select HAVE_AT91_DBGU0
>   	select HAVE_FB_ATMEL
>   	select SOC_AT91SAM9
> +	select AT91_USE_OLD_CLK
>   	help
>   	  Select this if you are using Atmel's AT91SAM9N12 SoC.
>
> diff --git a/arch/arm/mach-at91/Kconfig.non_dt b/arch/arm/mach-at91/Kconfig.non_dt
> index ca900be..b736b57 100644
> --- a/arch/arm/mach-at91/Kconfig.non_dt
> +++ b/arch/arm/mach-at91/Kconfig.non_dt
> @@ -12,26 +12,32 @@ config ARCH_AT91_NONE
>   config ARCH_AT91RM9200
>   	bool "AT91RM9200"
>   	select SOC_AT91RM9200
> +	select AT91_USE_OLD_CLK
>
>   config ARCH_AT91SAM9260
>   	bool "AT91SAM9260 or AT91SAM9XE or AT91SAM9G20"
>   	select SOC_AT91SAM9260
> +	select AT91_USE_OLD_CLK
>
>   config ARCH_AT91SAM9261
>   	bool "AT91SAM9261 or AT91SAM9G10"
>   	select SOC_AT91SAM9261
> +	select AT91_USE_OLD_CLK
>
>   config ARCH_AT91SAM9263
>   	bool "AT91SAM9263"
>   	select SOC_AT91SAM9263
> +	select AT91_USE_OLD_CLK
>
>   config ARCH_AT91SAM9RL
>   	bool "AT91SAM9RL"
>   	select SOC_AT91SAM9RL
> +	select AT91_USE_OLD_CLK
>
>   config ARCH_AT91SAM9G45
>   	bool "AT91SAM9G45"
>   	select SOC_AT91SAM9G45
> +	select AT91_USE_OLD_CLK
>
>   config ARCH_AT91X40
>   	bool "AT91x40"
> diff --git a/arch/arm/mach-at91/Makefile b/arch/arm/mach-at91/Makefile
> index 3b0a953..8539411 100644
> --- a/arch/arm/mach-at91/Makefile
> +++ b/arch/arm/mach-at91/Makefile
> @@ -7,7 +7,7 @@ obj-m		:=
>   obj-n		:=
>   obj-		:=
>
> -obj-$(CONFIG_AT91_PMC_UNIT)	+= clock.o
> +obj-$(CONFIG_OLD_CLK_AT91)	+= clock.o
>   obj-$(CONFIG_AT91_SAM9_ALT_RESET) += at91sam9_alt_reset.o
>   obj-$(CONFIG_AT91_SAM9G45_RESET) += at91sam9g45_reset.o
>   obj-$(CONFIG_AT91_SAM9_TIME)	+= at91sam926x_time.o
> diff --git a/arch/arm/mach-at91/generic.h b/arch/arm/mach-at91/generic.h
> index dc6e2f5..375c42e 100644
> --- a/arch/arm/mach-at91/generic.h
> +++ b/arch/arm/mach-at91/generic.h
> @@ -44,11 +44,12 @@ extern void at91sam926x_pit_init(void);
>   extern void at91x40_timer_init(void);
>
>    /* Clocks */
> -#ifdef CONFIG_AT91_PMC_UNIT
> +#ifdef CONFIG_OLD_CLK_AT91
>   extern int __init at91_clock_init(unsigned long main_clock);
>   extern int __init at91_dt_clock_init(void);
>   #else
>   static int inline at91_clock_init(unsigned long main_clock) { return 0; }
> +static int inline at91_dt_clock_init(void) { return 0; }
>   #endif
>   struct device;
>
> diff --git a/arch/arm/mach-at91/setup.c b/arch/arm/mach-at91/setup.c
> index 41aa68b..06052fc 100644
> --- a/arch/arm/mach-at91/setup.c
> +++ b/arch/arm/mach-at91/setup.c
> @@ -483,7 +483,8 @@ void __init at91rm9200_dt_initialize(void)
>   	at91_dt_clock_init();
>
>   	/* Register the processor-specific clocks */
> -	at91_boot_soc.register_clocks();
> +	if (at91_boot_soc.register_clocks)
> +		at91_boot_soc.register_clocks();
>
>   	at91_boot_soc.init();
>   }
> @@ -498,7 +499,8 @@ void __init at91_dt_initialize(void)
>   	at91_dt_clock_init();
>
>   	/* Register the processor-specific clocks */
> -	at91_boot_soc.register_clocks();
> +	if (at91_boot_soc.register_clocks)
> +		at91_boot_soc.register_clocks();
>
>   	if (at91_boot_soc.init)
>   		at91_boot_soc.init();
>


-- 
Nicolas Ferre

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

* Re: [PATCH v3 04/19] clk: at91: add PMC macro file for dt definitions
  2013-08-08  5:04 ` [PATCH v3 04/19] clk: at91: add PMC macro file for dt definitions Boris BREZILLON
@ 2013-10-07 15:17   ` Nicolas Ferre
  2013-10-07 16:06     ` boris brezillon
  0 siblings, 1 reply; 54+ messages in thread
From: Nicolas Ferre @ 2013-10-07 15:17 UTC (permalink / raw)
  To: Boris BREZILLON, Grant Likely, Rob Herring, Rob Landley,
	Andrew Victor, Jean-Christophe Plagniol-Villard, Russell King,
	Mike Turquette, Felipe Balbi, Greg Kroah-Hartman,
	Ludovic Desroches, Josh Wu, Richard Genoud
  Cc: devicetree, linux-kernel, linux-arm-kernel

On 08/08/2013 07:04, Boris BREZILLON :
> This patch adds a new macro file for PMC macros.
>
> This macro file includes the definitions of SR (status register) bit
> offsets and will be use to reference PMC irqs.
>
> Signed-off-by: Boris BREZILLON <b.brezillon@overkiz.com>
> ---
>   include/dt-bindings/clk/at91/common/pmc.h |   20 ++++++++++++++++++++
>   1 file changed, 20 insertions(+)
>   create mode 100644 include/dt-bindings/clk/at91/common/pmc.h
>
> diff --git a/include/dt-bindings/clk/at91/common/pmc.h b/include/dt-bindings/clk/at91/common/pmc.h
> new file mode 100644
> index 0000000..edc51d6
> --- /dev/null
> +++ b/include/dt-bindings/clk/at91/common/pmc.h
> @@ -0,0 +1,20 @@
> +/*
> + * This header provides constants for AT91 pmc status.
> + *
> + * The constants defined in this header are being used in dts.

It is better to add one line about license: for example:

  * Licensed under GPLv2 or later.


> + */
> +
> +#ifndef _DT_BINDINGS_CLK_AT91_PMC_H
> +#define _DT_BINDINGS_CLK_AT91_PMC_H
> +
> +#define AT91_PMC_MOSCS		0		/* MOSCS Flag */
> +#define AT91_PMC_LOCKA		1		/* PLLA Lock */
> +#define AT91_PMC_LOCKB		2		/* PLLB Lock */
> +#define AT91_PMC_MCKRDY		3		/* Master Clock */
> +#define AT91_PMC_LOCKU		6		/* UPLL Lock */
> +#define AT91_PMC_PCKRDY(id)	(8 + id)	/* Programmable Clock */

I prefer with parenthesis around "id" (8 + (id))

> +#define AT91_PMC_MOSCSELS	16		/* Main Oscillator Selection */
> +#define AT91_PMC_MOSCRCS	17		/* Main On-Chip RC */
> +#define AT91_PMC_CFDEV		18		/* Clock Failure Detector Event */
> +
> +#endif
>


-- 
Nicolas Ferre

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

* Re: [PATCH v3 03/19] clk: at91: add PMC base support
  2013-10-07 15:07   ` Nicolas Ferre
@ 2013-10-07 15:57     ` boris brezillon
  0 siblings, 0 replies; 54+ messages in thread
From: boris brezillon @ 2013-10-07 15:57 UTC (permalink / raw)
  To: Nicolas Ferre, Grant Likely, Rob Herring, Rob Landley,
	Andrew Victor, Jean-Christophe Plagniol-Villard, Russell King,
	Mike Turquette, Felipe Balbi, Greg Kroah-Hartman,
	Ludovic Desroches, Josh Wu, Richard Genoud
  Cc: devicetree, linux-kernel, linux-arm-kernel

Hello Nicolas,

On 07/10/2013 17:07, Nicolas Ferre wrote:
> On 08/08/2013 07:01, Boris BREZILLON :
>> This patch adds at91 PMC (Power Management Controller) base support.
>>
>> All at91 clocks managed by the PMC unit will use this framework.
>>
>> This framework provides the following fonctionalities:
>> - define a new struct at91_pmc to hide PMC internals (lock, PMC memory
>>    mapping, irq domain, ...)
>> - read/write helper functions (pmc_read/write) to access PMC registers
>> - lock/unlock helper functions (pmc_lock/unlock) to lock/unlock 
>> access to
>>    pmc registers
>> - a new irq domain and its associated irq chip to request PMC specific
>>    interrupts (useful for clk prepare callbacks)
>>
>> The PMC unit is declared as a dt clk provider (CLK_OF_DECLARE), and 
>> every
>> clk using this framework will declare a table of of_at91_clk_init_cb_t
>> and add it to the pmc_clk_ids table.
>>
>> When the pmc dt clock setup function is called (by of_clk_init 
>> function),
>> it triggers the registration of every supported child clk (those 
>> matching
>> the definitions in pmc_clk_ids).
>>
>> This patch copies at91_pmc_base (memory mapping) and at91sam9_idle
>> (function) from arch/arm/mach-at91/clock.c (which is not compiled if
>> COMMON_CLK_AT91 is enabled).
>>
>> Signed-off-by: Boris BREZILLON <b.brezillon@overkiz.com>
>> ---
>>   drivers/clk/Makefile      |    1 +
>>   drivers/clk/at91/Makefile |    5 +
>>   drivers/clk/at91/pmc.c    |  298 
>> +++++++++++++++++++++++++++++++++++++++++++++
>>   drivers/clk/at91/pmc.h    |   58 +++++++++
>>   4 files changed, 362 insertions(+)
>>   create mode 100644 drivers/clk/at91/Makefile
>>   create mode 100644 drivers/clk/at91/pmc.c
>>   create mode 100644 drivers/clk/at91/pmc.h
>>
>> diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile
>> index 4038c2b..c256a20 100644
>> --- a/drivers/clk/Makefile
>> +++ b/drivers/clk/Makefile
>> @@ -32,6 +32,7 @@ obj-$(CONFIG_ARCH_VT8500)    += clk-vt8500.o
>>   obj-$(CONFIG_ARCH_ZYNQ)        += zynq/
>>   obj-$(CONFIG_ARCH_TEGRA)    += tegra/
>>   obj-$(CONFIG_PLAT_SAMSUNG)    += samsung/
>> +obj-$(CONFIG_COMMON_CLK_AT91)    += at91/
>>
>>   obj-$(CONFIG_X86)        += x86/
>>
>> diff --git a/drivers/clk/at91/Makefile b/drivers/clk/at91/Makefile
>> new file mode 100644
>> index 0000000..1d4fb21
>> --- /dev/null
>> +++ b/drivers/clk/at91/Makefile
>> @@ -0,0 +1,5 @@
>> +#
>> +# Makefile for at91 specific clk
>> +#
>> +
>> +obj-y += pmc.o
>> diff --git a/drivers/clk/at91/pmc.c b/drivers/clk/at91/pmc.c
>> new file mode 100644
>> index 0000000..f6bd03d
>> --- /dev/null
>> +++ b/drivers/clk/at91/pmc.c
>> @@ -0,0 +1,298 @@
>> +/*
>> + * drivers/clk/at91/pmc.c
>> + *
>> + *  Copyright (C) 2013 Boris BREZILLON <b.brezillon@overkiz.com>
>> + *
>> + * This program is free software; you can redistribute it and/or modify
>> + * it under the terms of the GNU General Public License as published by
>> + * the Free Software Foundation; either version 2 of the License, or
>> + * (at your option) any later version.
>> + *
>> + */
>> +
>> +#include <linux/clk-provider.h>
>> +#include <linux/clkdev.h>
>> +#include <linux/clk/at91_pmc.h>
>> +#include <linux/of.h>
>> +#include <linux/of_address.h>
>> +#include <linux/io.h>
>> +#include <linux/interrupt.h>
>> +#include <linux/irq.h>
>> +#include <linux/irqchip/chained_irq.h>
>> +#include <linux/irqdomain.h>
>> +#include <linux/of_irq.h>
>> +
>> +#include <asm/proc-fns.h>
>> +
>> +#include "pmc.h"
>> +
>> +void __iomem *at91_pmc_base;
>> +EXPORT_SYMBOL_GPL(at91_pmc_base);
>> +
>> +void at91sam9_idle(void)
>> +{
>> +    at91_pmc_write(AT91_PMC_SCDR, AT91_PMC_PCK);
>> +    cpu_do_idle();
>> +}
>> +
>> +static void pmc_irq_mask(struct irq_data *d)
>> +{
>> +    struct at91_pmc *pmc = irq_data_get_irq_chip_data(d);
>> +
>> +    pmc_write(pmc, AT91_PMC_IDR, 1 << d->hwirq);
>> +}
>> +
>> +static void pmc_irq_unmask(struct irq_data *d)
>> +{
>> +    struct at91_pmc *pmc = irq_data_get_irq_chip_data(d);
>> +
>> +    pmc_write(pmc, AT91_PMC_IER, 1 << d->hwirq);
>> +}
>> +
>> +static int pmc_irq_set_type(struct irq_data *d, unsigned type)
>> +{
>> +    if (type != IRQ_TYPE_LEVEL_HIGH) {
>> +        pr_warn("PMC: type not supported (support only 
>> IRQ_TYPE_LEVEL_HIGH type)\n");
>> +        return -EINVAL;
>> +    }
>> +
>> +    return 0;
>> +}
>> +
>> +static struct irq_chip pmc_irq = {
>> +    .name = "PMC",
>> +    .irq_disable = pmc_irq_mask,
>> +    .irq_mask = pmc_irq_mask,
>> +    .irq_unmask = pmc_irq_unmask,
>> +    .irq_set_type = pmc_irq_set_type,
>> +};
>> +
>> +static struct lock_class_key pmc_lock_class;
>> +
>> +static int pmc_irq_map(struct irq_domain *h, unsigned int virq,
>> +               irq_hw_number_t hw)
>> +{
>> +    struct at91_pmc    *pmc = h->host_data;
>> +
>> +    irq_set_lockdep_class(virq, &pmc_lock_class);
>> +
>> +    irq_set_chip_and_handler(virq, &pmc_irq,
>> +                 handle_level_irq);
>> +    set_irq_flags(virq, IRQF_VALID);
>> +    irq_set_chip_data(virq, pmc);
>> +
>> +    return 0;
>> +}
>> +
>> +static int pmc_irq_domain_xlate(struct irq_domain *d,
>> +                struct device_node *ctrlr,
>> +                const u32 *intspec, unsigned int intsize,
>> +                irq_hw_number_t *out_hwirq,
>> +                unsigned int *out_type)
>> +{
>> +    struct at91_pmc *pmc = d->host_data;
>> +    const struct at91_pmc_caps *caps = pmc->caps;
>> +
>> +    if (WARN_ON(intsize < 2))
>> +        return -EINVAL;
>> +    *out_hwirq = intspec[0];
>> +    *out_type = intspec[1] & IRQ_TYPE_SENSE_MASK;
>> +
>> +    if (!(caps->available_irqs & (1 << *out_hwirq)))
>> +        return -EINVAL;
>> +
>> +    if (*out_type != IRQ_TYPE_LEVEL_HIGH)
>> +        return -EINVAL;
>> +
>> +    return 0;
>> +}
>> +
>> +static struct irq_domain_ops pmc_irq_ops = {
>> +    .map    = pmc_irq_map,
>> +    .xlate    = pmc_irq_domain_xlate,
>> +};
>> +
>> +static irqreturn_t pmc_irq_handler(int irq, void *data)
>> +{
>> +    struct at91_pmc *pmc = (struct at91_pmc *)data;
>> +    unsigned long sr;
>> +    int n;
>> +
>> +    sr = pmc_read(pmc, AT91_PMC_SR) & pmc_read(pmc, AT91_PMC_IMR);
>> +    if (!sr)
>> +        return IRQ_NONE;
>> +
>> +    for_each_set_bit(n, &sr, BITS_PER_LONG)
>> +        generic_handle_irq(irq_find_mapping(pmc->irqdomain, n));
>> +
>> +    return IRQ_HANDLED;
>> +}
>> +
>> +static const struct at91_pmc_caps at91rm9200_caps = {
>> +    .available_irqs = AT91_PMC_MOSCS | AT91_PMC_LOCKA | 
>> AT91_PMC_LOCKB |
>> +              AT91_PMC_MCKRDY | AT91_PMC_PCK0RDY |
>> +              AT91_PMC_PCK1RDY | AT91_PMC_PCK2RDY |
>> +              AT91_PMC_PCK3RDY,
>> +};
>> +
>> +static const struct at91_pmc_caps at91sam9260_caps = {
>> +    .available_irqs = AT91_PMC_MOSCS | AT91_PMC_LOCKA | 
>> AT91_PMC_LOCKB |
>> +              AT91_PMC_MCKRDY | AT91_PMC_PCK0RDY |
>> +              AT91_PMC_PCK1RDY,
>> +};
>> +
>> +static const struct at91_pmc_caps at91sam9g45_caps = {
>> +    .available_irqs = AT91_PMC_MOSCS | AT91_PMC_LOCKA | 
>> AT91_PMC_MCKRDY |
>> +              AT91_PMC_LOCKU | AT91_PMC_PCK0RDY |
>> +              AT91_PMC_PCK1RDY,
>> +};
>> +
>> +static const struct at91_pmc_caps at91sam9n12_caps = {
>> +    .available_irqs = AT91_PMC_MOSCS | AT91_PMC_LOCKA | 
>> AT91_PMC_LOCKB |
>> +              AT91_PMC_MCKRDY | AT91_PMC_PCK0RDY |
>> +              AT91_PMC_PCK1RDY | AT91_PMC_MOSCSELS |
>> +              AT91_PMC_MOSCRCS | AT91_PMC_CFDEV,
>> +};
>> +
>> +static const struct at91_pmc_caps at91sam9x5_caps = {
>> +    .available_irqs = AT91_PMC_MOSCS | AT91_PMC_LOCKA | 
>> AT91_PMC_MCKRDY |
>> +              AT91_PMC_LOCKU | AT91_PMC_PCK0RDY |
>> +              AT91_PMC_PCK1RDY | AT91_PMC_MOSCSELS |
>> +              AT91_PMC_MOSCRCS | AT91_PMC_CFDEV,
>> +};
>> +
>> +static const struct at91_pmc_caps at91sam9g35_caps = {
>> +    .available_irqs = AT91_PMC_MOSCS | AT91_PMC_LOCKA | 
>> AT91_PMC_MCKRDY |
>> +              AT91_PMC_PCK0RDY | AT91_PMC_PCK1RDY |
>> +              AT91_PMC_MOSCSELS | AT91_PMC_MOSCRCS |
>> +              AT91_PMC_CFDEV,
>
> 9g35 is part of 9x5 series. It is not different from its other fellow 
> SoCs.
> (but it is true that the datasheet has changed recently in relation 
> with this missing LOCKU bit ;-) ).
>
> So I suspect that we can remove all definitions of at91sam9g35 and 
> merge them with 9x5 ones (including compatibility string).
>
Sure, I will remove 9g35 specific definitions

>> +};
>> +
>> +static const struct at91_pmc_caps sama5d3_caps = {
>> +    .available_irqs = AT91_PMC_MOSCS | AT91_PMC_LOCKA | 
>> AT91_PMC_MCKRDY |
>> +              AT91_PMC_LOCKU | AT91_PMC_PCK0RDY |
>> +              AT91_PMC_PCK1RDY | AT91_PMC_PCK2RDY |
>> +              AT91_PMC_MOSCSELS | AT91_PMC_MOSCRCS |
>> +              AT91_PMC_CFDEV,
>> +};
>> +
>> +static struct at91_pmc *__init at91_pmc_init(struct device_node *np,
>> +                         void __iomem *regbase, int virq,
>> +                         const struct at91_pmc_caps *caps)
>> +{
>> +    struct at91_pmc *pmc;
>> +
>> +    if (!regbase || !virq ||  !caps)
>> +        return NULL;
>> +
>> +    at91_pmc_base = regbase;
>> +
>> +    pmc = kzalloc(sizeof(*pmc), GFP_KERNEL);
>> +    if (!pmc)
>> +        return NULL;
>> +
>> +    spin_lock_init(&pmc->lock);
>> +    pmc->regbase = regbase;
>> +    pmc->virq = virq;
>> +    pmc->caps = caps;
>> +
>> +    pmc->irqdomain = irq_domain_add_linear(np, 32, &pmc_irq_ops, pmc);
>> +
>> +    if (!pmc->irqdomain)
>> +        goto out_free_pmc;
>> +
>> +    pmc_write(pmc, AT91_PMC_IDR, 0xffffffff);
>> +    if (request_irq(pmc->virq, pmc_irq_handler, IRQF_SHARED, "pmc", 
>> pmc))
>> +        goto out_remove_irqdomain;
>> +
>> +    return pmc;
>> +
>> +out_remove_irqdomain:
>> +    irq_domain_remove(pmc->irqdomain);
>> +out_free_pmc:
>> +    kfree(pmc);
>> +
>> +    return NULL;
>> +}
>> +
>> +static const struct of_device_id pmc_clk_ids[] __initdata = {
>> +    { /*sentinel*/ }
>> +};
>> +
>> +static void __init of_at91_pmc_setup(struct device_node *np,
>> +                     const struct at91_pmc_caps *caps)
>> +{
>> +    struct at91_pmc *pmc;
>> +    struct device_node *childnp;
>> +    void (*clk_setup)(struct device_node *, struct at91_pmc *);
>> +    const struct of_device_id *clk_id;
>> +    void __iomem *regbase = of_iomap(np, 0);
>> +    int virq;
>> +
>> +    if (!regbase)
>> +        return;
>> +
>> +    virq = irq_of_parse_and_map(np, 0);
>> +    if (!virq)
>> +        return;
>> +
>> +    pmc = at91_pmc_init(np, regbase, virq, caps);
>> +    if (!pmc)
>> +        return;
>> +    for_each_child_of_node(np, childnp) {
>> +        clk_id = of_match_node(pmc_clk_ids, childnp);
>> +        if (!clk_id)
>> +            continue;
>> +        clk_setup = clk_id->data;
>> +        clk_setup(childnp, pmc);
>> +    }
>> +}
>> +
>> +static void __init of_at91rm9200_pmc_setup(struct device_node *np)
>> +{
>> +    of_at91_pmc_setup(np, &at91rm9200_caps);
>> +}
>> +CLK_OF_DECLARE(at91rm9200_clk_main, "atmel,at91rm9200-pmc",
>> +           of_at91rm9200_pmc_setup);
>> +
>> +static void __init of_at91sam9260_pmc_setup(struct device_node *np)
>> +{
>> +    of_at91_pmc_setup(np, &at91sam9260_caps);
>> +}
>> +CLK_OF_DECLARE(at91sam9260_clk_main, "atmel,at91sam9260-pmc",
>> +           of_at91sam9260_pmc_setup);
>> +
>> +static void __init of_at91sam9g45_pmc_setup(struct device_node *np)
>> +{
>> +    of_at91_pmc_setup(np, &at91sam9g45_caps);
>> +}
>> +CLK_OF_DECLARE(at91sam9g45_clk_main, "atmel,at91sam9g45-pmc",
>> +           of_at91sam9g45_pmc_setup);
>> +
>> +static void __init of_at91sam9n12_pmc_setup(struct device_node *np)
>> +{
>> +    of_at91_pmc_setup(np, &at91sam9n12_caps);
>> +}
>> +CLK_OF_DECLARE(at91sam9n12_clk_main, "atmel,at91sam9n12-pmc",
>> +           of_at91sam9n12_pmc_setup);
>> +
>> +static void __init of_at91sam9x5_pmc_setup(struct device_node *np)
>> +{
>> +    of_at91_pmc_setup(np, &at91sam9x5_caps);
>> +}
>> +CLK_OF_DECLARE(at91sam9x5_clk_main, "atmel,at91sam9x5-pmc",
>> +           of_at91sam9x5_pmc_setup);
>> +
>> +static void __init of_at91sam9g35_pmc_setup(struct device_node *np)
>> +{
>> +    of_at91_pmc_setup(np, &at91sam9g35_caps);
>> +}
>> +CLK_OF_DECLARE(at91sam9g35_clk_main, "atmel,at91sam9g35-pmc",
>> +           of_at91sam9g35_pmc_setup);
>
> Ditto.
>
>> +
>> +static void __init of_sama5d3_pmc_setup(struct device_node *np)
>> +{
>> +    of_at91_pmc_setup(np, &sama5d3_caps);
>> +}
>> +CLK_OF_DECLARE(sama5d3_clk_main, "atmel,sama5d3-pmc",
>> +           of_sama5d3_pmc_setup);
>> diff --git a/drivers/clk/at91/pmc.h b/drivers/clk/at91/pmc.h
>> new file mode 100644
>> index 0000000..b7e8397
>> --- /dev/null
>> +++ b/drivers/clk/at91/pmc.h
>> @@ -0,0 +1,58 @@
>> +/*
>> + * drivers/clk/at91/pmc.h
>> + *
>> + *  Copyright (C) 2013 Boris BREZILLON <b.brezillon@overkiz.com>
>> + *
>> + * This program is free software; you can redistribute it and/or modify
>> + * it under the terms of the GNU General Public License as published by
>> + * the Free Software Foundation; either version 2 of the License, or
>> + * (at your option) any later version.
>> + */
>> +
>> +#ifndef __PMC_H_
>> +#define __PMC_H_
>> +
>> +#include <linux/io.h>
>> +#include <linux/irqdomain.h>
>> +#include <linux/spinlock.h>
>> +
>> +struct clk_range {
>> +    unsigned long min;
>> +    unsigned long max;
>> +};
>> +
>> +#define CLK_RANGE(MIN, MAX) {.min = MIN, .max = MAX,}
>> +
>> +struct at91_pmc_caps {
>> +    u32 available_irqs;
>> +};
>> +
>> +struct at91_pmc {
>> +    void __iomem *regbase;
>> +    int virq;
>> +    spinlock_t lock;
>> +    const struct at91_pmc_caps *caps;
>> +    struct irq_domain *irqdomain;
>> +};
>> +
>> +static inline void pmc_lock(struct at91_pmc *pmc)
>> +{
>> +    spin_lock(&pmc->lock);
>> +}
>> +
>> +static inline void pmc_unlock(struct at91_pmc *pmc)
>> +{
>> +    spin_unlock(&pmc->lock);
>> +}
>> +
>> +static inline u32 pmc_read(struct at91_pmc *pmc, int offset)
>> +{
>> +    return readl_relaxed(pmc->regbase + offset);
>> +}
>> +
>> +static inline void pmc_write(struct at91_pmc *pmc, int offset, u32 
>> value)
>> +{
>> +    return writel_relaxed(value, pmc->regbase + offset);
>> +}
>> +
>> +#endif /* __PMC_H_ */
>>
>
>


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

* Re: [PATCH v3 02/19] ARM: at91: add Kconfig options for common clk support
  2013-10-07 15:12   ` Nicolas Ferre
@ 2013-10-07 16:05     ` boris brezillon
  2013-10-09  9:56     ` boris brezillon
  1 sibling, 0 replies; 54+ messages in thread
From: boris brezillon @ 2013-10-07 16:05 UTC (permalink / raw)
  To: Nicolas Ferre, Grant Likely, Rob Herring, Rob Landley,
	Andrew Victor, Jean-Christophe Plagniol-Villard, Russell King,
	Mike Turquette, Felipe Balbi, Greg Kroah-Hartman,
	Ludovic Desroches, Josh Wu, Richard Genoud
  Cc: devicetree, linux-kernel, linux-arm-kernel

On 07/10/2013 17:12, Nicolas Ferre wrote:
> On 08/08/2013 07:02, Boris BREZILLON :
>> This patch adds the following Kconfig options to prepare the 
>> transition to
>> common clk framework:
>>
>> - AT91_USE_OLD_CLK: this option is selected by every SoC which does not
>>    support new at91 clks based on common clk framework (SoC which 
>> does not
>>    define the clock tree in its device tree).
>>    This options is also selected when the user choose non dt boards 
>> support
>>    (new at91 clks can only be registered from a device tree definition).
>>
>> - COMMON_CLK_AT91: this option cannot be selected directly. Instead 
>> it is
>
> I would have prefered to keep "AT91" as a prefix => "AT91_COMMON_CLK"
> But it is not so important.
>
>>    enabled if these 3 conditions are met:
>>     * at least one of the selected SoCs have a PMC (Power Management
>>       Controller) Unit
>>     * device tree support is enabled
>>     * the old at91 clk implementation is disabled (every selected SoC 
>> define
>>       its clks in its device tree and non dt boards support is disabled)
>>
>> - OLD_CLK_AT91: this option cannot be selected directly. Instead it is
>
> Here also.

I'll change the names of these options.

>
>>    enabled if these 2 conditions are met:
>>     * at least one of the selected SoCs have a PMC (Power Management
>>       Controller) Unit
>>     * at least one of the selected SoCs does not define its clks in its
>>       device tree or non dt-boards support is enabled
>>
>> This patch selects AT91_USE_OLD_CLK in all currently supported SoCs. 
>> These
>> selects will be removed after clk definitions are properly added in each
>> soc's device tree.
>> It also selects AT91_USE_OLD_CLK in all non-dt boards support.
>>
>> AT91_PMC_UNIT references are replaced by OLD_CLK_AT91, because PMC 
>> Unit is
>> enabled for both old and common clk implementations, and old clk
>> implementation should not be compiled if COMMON_CLK is enabled.
>>
>> To avoid future link errors, a new stub is created for 
>> at91_dt_clock_init
>> function if OLD_CLK_AT91 is disabled.
>>
>> A new check is added in dt init functions (setup.c) to prepare for SoCs
>> supporting new clk implementation. These SoCs won't setup the
>> register_clocks callback (clk registration is done using of_clk_init).
>>
>> Signed-off-by: Boris BREZILLON <b.brezillon@overkiz.com>
>> ---
>>   arch/arm/mach-at91/Kconfig        |   21 +++++++++++++++++++++
>>   arch/arm/mach-at91/Kconfig.non_dt |    6 ++++++
>>   arch/arm/mach-at91/Makefile       |    2 +-
>>   arch/arm/mach-at91/generic.h      |    3 ++-
>>   arch/arm/mach-at91/setup.c        |    6 ++++--
>>   5 files changed, 34 insertions(+), 4 deletions(-)
>>
>> diff --git a/arch/arm/mach-at91/Kconfig b/arch/arm/mach-at91/Kconfig
>> index 699b71e..85b53a4 100644
>> --- a/arch/arm/mach-at91/Kconfig
>> +++ b/arch/arm/mach-at91/Kconfig
>> @@ -6,10 +6,22 @@ config HAVE_AT91_DBGU0
>>   config HAVE_AT91_DBGU1
>>       bool
>>
>> +config AT91_USE_OLD_CLK
>> +    bool
>> +
>>   config AT91_PMC_UNIT
>>       bool
>>       default !ARCH_AT91X40
>>
>> +config COMMON_CLK_AT91
>> +    bool
>> +    default AT91_PMC_UNIT && USE_OF && !AT91_USE_OLD_CLK
>> +    select COMMON_CLK
>> +
>> +config OLD_CLK_AT91
>> +    bool
>> +    default AT91_PMC_UNIT && AT91_USE_OLD_CLK
>> +
>>   config AT91_SAM9_ALT_RESET
>>       bool
>>       default !ARCH_AT91X40
>> @@ -65,6 +77,7 @@ config SOC_SAMA5D3
>>       select SOC_SAMA5
>>       select HAVE_FB_ATMEL
>>       select HAVE_AT91_DBGU1
>> +    select AT91_USE_OLD_CLK
>>       help
>>         Select this if you are using one of Atmel's SAMA5D3 family SoC.
>>         This support covers SAMA5D31, SAMA5D33, SAMA5D34, SAMA5D35.
>> @@ -78,11 +91,13 @@ config SOC_AT91RM9200
>>       select HAVE_AT91_DBGU0
>>       select MULTI_IRQ_HANDLER
>>       select SPARSE_IRQ
>> +    select AT91_USE_OLD_CLK
>>
>>   config SOC_AT91SAM9260
>>       bool "AT91SAM9260, AT91SAM9XE or AT91SAM9G20"
>>       select HAVE_AT91_DBGU0
>>       select SOC_AT91SAM9
>> +    select AT91_USE_OLD_CLK
>>       help
>>         Select this if you are using one of Atmel's AT91SAM9260, 
>> AT91SAM9XE
>>         or AT91SAM9G20 SoC.
>> @@ -92,6 +107,7 @@ config SOC_AT91SAM9261
>>       select HAVE_AT91_DBGU0
>>       select HAVE_FB_ATMEL
>>       select SOC_AT91SAM9
>> +    select AT91_USE_OLD_CLK
>>       help
>>         Select this if you are using one of Atmel's AT91SAM9261 or 
>> AT91SAM9G10 SoC.
>>
>> @@ -100,18 +116,21 @@ config SOC_AT91SAM9263
>>       select HAVE_AT91_DBGU1
>>       select HAVE_FB_ATMEL
>>       select SOC_AT91SAM9
>> +    select AT91_USE_OLD_CLK
>>
>>   config SOC_AT91SAM9RL
>>       bool "AT91SAM9RL"
>>       select HAVE_AT91_DBGU0
>>       select HAVE_FB_ATMEL
>>       select SOC_AT91SAM9
>> +    select AT91_USE_OLD_CLK
>>
>>   config SOC_AT91SAM9G45
>>       bool "AT91SAM9G45 or AT91SAM9M10 families"
>>       select HAVE_AT91_DBGU1
>>       select HAVE_FB_ATMEL
>>       select SOC_AT91SAM9
>> +    select AT91_USE_OLD_CLK
>>       help
>>         Select this if you are using one of Atmel's AT91SAM9G45 
>> family SoC.
>>         This support covers AT91SAM9G45, AT91SAM9G46, AT91SAM9M10 and 
>> AT91SAM9M11.
>> @@ -121,6 +140,7 @@ config SOC_AT91SAM9X5
>>       select HAVE_AT91_DBGU0
>>       select HAVE_FB_ATMEL
>>       select SOC_AT91SAM9
>> +    select AT91_USE_OLD_CLK
>>       help
>>         Select this if you are using one of Atmel's AT91SAM9x5 family 
>> SoC.
>>         This means that your SAM9 name finishes with a '5' (except if 
>> it is
>> @@ -133,6 +153,7 @@ config SOC_AT91SAM9N12
>>       select HAVE_AT91_DBGU0
>>       select HAVE_FB_ATMEL
>>       select SOC_AT91SAM9
>> +    select AT91_USE_OLD_CLK
>>       help
>>         Select this if you are using Atmel's AT91SAM9N12 SoC.
>>
>> diff --git a/arch/arm/mach-at91/Kconfig.non_dt 
>> b/arch/arm/mach-at91/Kconfig.non_dt
>> index ca900be..b736b57 100644
>> --- a/arch/arm/mach-at91/Kconfig.non_dt
>> +++ b/arch/arm/mach-at91/Kconfig.non_dt
>> @@ -12,26 +12,32 @@ config ARCH_AT91_NONE
>>   config ARCH_AT91RM9200
>>       bool "AT91RM9200"
>>       select SOC_AT91RM9200
>> +    select AT91_USE_OLD_CLK
>>
>>   config ARCH_AT91SAM9260
>>       bool "AT91SAM9260 or AT91SAM9XE or AT91SAM9G20"
>>       select SOC_AT91SAM9260
>> +    select AT91_USE_OLD_CLK
>>
>>   config ARCH_AT91SAM9261
>>       bool "AT91SAM9261 or AT91SAM9G10"
>>       select SOC_AT91SAM9261
>> +    select AT91_USE_OLD_CLK
>>
>>   config ARCH_AT91SAM9263
>>       bool "AT91SAM9263"
>>       select SOC_AT91SAM9263
>> +    select AT91_USE_OLD_CLK
>>
>>   config ARCH_AT91SAM9RL
>>       bool "AT91SAM9RL"
>>       select SOC_AT91SAM9RL
>> +    select AT91_USE_OLD_CLK
>>
>>   config ARCH_AT91SAM9G45
>>       bool "AT91SAM9G45"
>>       select SOC_AT91SAM9G45
>> +    select AT91_USE_OLD_CLK
>>
>>   config ARCH_AT91X40
>>       bool "AT91x40"
>> diff --git a/arch/arm/mach-at91/Makefile b/arch/arm/mach-at91/Makefile
>> index 3b0a953..8539411 100644
>> --- a/arch/arm/mach-at91/Makefile
>> +++ b/arch/arm/mach-at91/Makefile
>> @@ -7,7 +7,7 @@ obj-m        :=
>>   obj-n        :=
>>   obj-        :=
>>
>> -obj-$(CONFIG_AT91_PMC_UNIT)    += clock.o
>> +obj-$(CONFIG_OLD_CLK_AT91)    += clock.o
>>   obj-$(CONFIG_AT91_SAM9_ALT_RESET) += at91sam9_alt_reset.o
>>   obj-$(CONFIG_AT91_SAM9G45_RESET) += at91sam9g45_reset.o
>>   obj-$(CONFIG_AT91_SAM9_TIME)    += at91sam926x_time.o
>> diff --git a/arch/arm/mach-at91/generic.h b/arch/arm/mach-at91/generic.h
>> index dc6e2f5..375c42e 100644
>> --- a/arch/arm/mach-at91/generic.h
>> +++ b/arch/arm/mach-at91/generic.h
>> @@ -44,11 +44,12 @@ extern void at91sam926x_pit_init(void);
>>   extern void at91x40_timer_init(void);
>>
>>    /* Clocks */
>> -#ifdef CONFIG_AT91_PMC_UNIT
>> +#ifdef CONFIG_OLD_CLK_AT91
>>   extern int __init at91_clock_init(unsigned long main_clock);
>>   extern int __init at91_dt_clock_init(void);
>>   #else
>>   static int inline at91_clock_init(unsigned long main_clock) { 
>> return 0; }
>> +static int inline at91_dt_clock_init(void) { return 0; }
>>   #endif
>>   struct device;
>>
>> diff --git a/arch/arm/mach-at91/setup.c b/arch/arm/mach-at91/setup.c
>> index 41aa68b..06052fc 100644
>> --- a/arch/arm/mach-at91/setup.c
>> +++ b/arch/arm/mach-at91/setup.c
>> @@ -483,7 +483,8 @@ void __init at91rm9200_dt_initialize(void)
>>       at91_dt_clock_init();
>>
>>       /* Register the processor-specific clocks */
>> -    at91_boot_soc.register_clocks();
>> +    if (at91_boot_soc.register_clocks)
>> +        at91_boot_soc.register_clocks();
>>
>>       at91_boot_soc.init();
>>   }
>> @@ -498,7 +499,8 @@ void __init at91_dt_initialize(void)
>>       at91_dt_clock_init();
>>
>>       /* Register the processor-specific clocks */
>> -    at91_boot_soc.register_clocks();
>> +    if (at91_boot_soc.register_clocks)
>> +        at91_boot_soc.register_clocks();
>>
>>       if (at91_boot_soc.init)
>>           at91_boot_soc.init();
>>
>
>


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

* Re: [PATCH v3 04/19] clk: at91: add PMC macro file for dt definitions
  2013-10-07 15:17   ` Nicolas Ferre
@ 2013-10-07 16:06     ` boris brezillon
  0 siblings, 0 replies; 54+ messages in thread
From: boris brezillon @ 2013-10-07 16:06 UTC (permalink / raw)
  To: Nicolas Ferre, Grant Likely, Rob Herring, Rob Landley,
	Andrew Victor, Jean-Christophe Plagniol-Villard, Russell King,
	Mike Turquette, Felipe Balbi, Greg Kroah-Hartman,
	Ludovic Desroches, Josh Wu, Richard Genoud
  Cc: devicetree, linux-kernel, linux-arm-kernel

On 07/10/2013 17:17, Nicolas Ferre wrote:
> On 08/08/2013 07:04, Boris BREZILLON :
>> This patch adds a new macro file for PMC macros.
>>
>> This macro file includes the definitions of SR (status register) bit
>> offsets and will be use to reference PMC irqs.
>>
>> Signed-off-by: Boris BREZILLON <b.brezillon@overkiz.com>
>> ---
>>   include/dt-bindings/clk/at91/common/pmc.h |   20 ++++++++++++++++++++
>>   1 file changed, 20 insertions(+)
>>   create mode 100644 include/dt-bindings/clk/at91/common/pmc.h
>>
>> diff --git a/include/dt-bindings/clk/at91/common/pmc.h 
>> b/include/dt-bindings/clk/at91/common/pmc.h
>> new file mode 100644
>> index 0000000..edc51d6
>> --- /dev/null
>> +++ b/include/dt-bindings/clk/at91/common/pmc.h
>> @@ -0,0 +1,20 @@
>> +/*
>> + * This header provides constants for AT91 pmc status.
>> + *
>> + * The constants defined in this header are being used in dts.
>
> It is better to add one line about license: for example:
>
>  * Licensed under GPLv2 or later.
>
>
>> + */
>> +
>> +#ifndef _DT_BINDINGS_CLK_AT91_PMC_H
>> +#define _DT_BINDINGS_CLK_AT91_PMC_H
>> +
>> +#define AT91_PMC_MOSCS        0        /* MOSCS Flag */
>> +#define AT91_PMC_LOCKA        1        /* PLLA Lock */
>> +#define AT91_PMC_LOCKB        2        /* PLLB Lock */
>> +#define AT91_PMC_MCKRDY        3        /* Master Clock */
>> +#define AT91_PMC_LOCKU        6        /* UPLL Lock */
>> +#define AT91_PMC_PCKRDY(id)    (8 + id)    /* Programmable Clock */
>
> I prefer with parenthesis around "id" (8 + (id))

Absolutely, I'll fix it.
>
>> +#define AT91_PMC_MOSCSELS    16        /* Main Oscillator Selection */
>> +#define AT91_PMC_MOSCRCS    17        /* Main On-Chip RC */
>> +#define AT91_PMC_CFDEV        18        /* Clock Failure Detector 
>> Event */
>> +
>> +#endif
>>
>
>


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

* Re: [PATCH v3 05/19] clk: at91: add PMC main clock
  2013-08-08  5:06 ` [PATCH v3 05/19] clk: at91: add PMC main clock Boris BREZILLON
@ 2013-10-07 16:51   ` Nicolas Ferre
  2013-10-07 19:11     ` boris brezillon
  0 siblings, 1 reply; 54+ messages in thread
From: Nicolas Ferre @ 2013-10-07 16:51 UTC (permalink / raw)
  To: Boris BREZILLON, Grant Likely, Rob Herring, Rob Landley,
	Andrew Victor, Jean-Christophe Plagniol-Villard, Russell King,
	Mike Turquette, Felipe Balbi, Greg Kroah-Hartman,
	Ludovic Desroches, Josh Wu, Richard Genoud
  Cc: devicetree, linux-kernel, linux-arm-kernel

On 08/08/2013 07:06, Boris BREZILLON :
> This patch adds new at91 main oscillator clock implementation using common
> clk framework.
>
> If rate is not provided during clock registration it is calculated using
> the slow clock (main clk parent in this case) rate and MCFR register.
>
> Signed-off-by: Boris BREZILLON <b.brezillon@overkiz.com>
> ---
>   drivers/clk/at91/Makefile   |    1 +
>   drivers/clk/at91/clk-main.c |  171 +++++++++++++++++++++++++++++++++++++++++++
>   drivers/clk/at91/pmc.c      |    5 ++
>   drivers/clk/at91/pmc.h      |    3 +
>   4 files changed, 180 insertions(+)
>   create mode 100644 drivers/clk/at91/clk-main.c
>
> diff --git a/drivers/clk/at91/Makefile b/drivers/clk/at91/Makefile
> index 1d4fb21..44105bd 100644
> --- a/drivers/clk/at91/Makefile
> +++ b/drivers/clk/at91/Makefile
> @@ -3,3 +3,4 @@
>   #
>
>   obj-y += pmc.o
> +obj-y += clk-main.o
> diff --git a/drivers/clk/at91/clk-main.c b/drivers/clk/at91/clk-main.c
> new file mode 100644
> index 0000000..68738dd
> --- /dev/null
> +++ b/drivers/clk/at91/clk-main.c
> @@ -0,0 +1,171 @@
> +/*
> + * drivers/clk/at91/clk-main.c
> + *
> + *  Copyright (C) 2013 Boris BREZILLON <b.brezillon@overkiz.com>
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License as published by
> + * the Free Software Foundation; either version 2 of the License, or
> + * (at your option) any later version.
> + *
> + */
> +
> +#include <linux/clk-provider.h>
> +#include <linux/clkdev.h>
> +#include <linux/clk/at91_pmc.h>
> +#include <linux/of.h>
> +#include <linux/of_address.h>
> +#include <linux/of_irq.h>
> +#include <linux/io.h>
> +#include <linux/interrupt.h>
> +#include <linux/irq.h>
> +#include <linux/sched.h>
> +#include <linux/wait.h>
> +
> +#include "pmc.h"
> +
> +#define to_clk_main(hw) container_of(hw, struct clk_main, hw)
> +struct clk_main {
> +	struct clk_hw hw;
> +	struct at91_pmc *pmc;
> +	unsigned long rate;
> +	unsigned int irq;
> +	wait_queue_head_t wait;
> +};
> +
> +static irqreturn_t clk_main_irq_handler(int irq, void *dev_id)
> +{
> +	struct clk_main *clkmain = (struct clk_main *)dev_id;
> +
> +	wake_up(&clkmain->wait);
> +	disable_irq_nosync(clkmain->irq);
> +
> +	return IRQ_HANDLED;
> +}
> +
> +static int clk_main_prepare(struct clk_hw *hw)
> +{
> +	struct clk_main *clkmain = to_clk_main(hw);
> +	struct at91_pmc *pmc = clkmain->pmc;
> +
> +	while (!(pmc_read(pmc, AT91_PMC_SR) & AT91_PMC_MOSCS)) {
> +		enable_irq(clkmain->irq);
> +		wait_event(clkmain->wait,
> +			   pmc_read(pmc, AT91_PMC_SR) & AT91_PMC_MOSCS);
> +	}
> +
> +	return 0;
> +}
> +
> +static int clk_main_is_prepared(struct clk_hw *hw)
> +{
> +	struct clk_main *clkmain = to_clk_main(hw);
> +
> +	return !!(pmc_read(clkmain->pmc, AT91_PMC_SR) & AT91_PMC_MOSCS);
> +}
> +
> +static unsigned long clk_main_recalc_rate(struct clk_hw *hw,
> +					  unsigned long parent_rate)
> +{
> +	u32 tmp;
> +	struct clk_main *clkmain = to_clk_main(hw);
> +	struct at91_pmc *pmc = clkmain->pmc;
> +
> +	if (clkmain->rate)
> +		return clkmain->rate;
> +
> +	while (!((tmp = pmc_read(pmc, AT91_CKGR_MCFR)) & AT91_PMC_MAINRDY))
> +		;

I must say that I do not like this while() loop. Please implement a way 
out and a mean to release CPU when waiting...

Maybe taking a timeout example like this one:
http://lxr.free-electrons.com/source/drivers/net/ethernet/cadence/macb.c#L391

Which is actually what I leart from Wolfram during his interesting 
session @ ELC-E:
http://elinux.org/images/5/54/Elce11_sang.pdf

It is true though that we should keep this very quick to not alter boot 
time too much.

I also wonder if really checking that main clock is read makes sense. If 
we are running Linux it probably mean that at least main clock is 
already well configured by the bootloader.

And this lead to a more general remark: couldn't we simply state that 
this clock is fixed and only available for reading its status?


> +
> +	tmp &= AT91_PMC_MAINF;
> +	clkmain->rate = (tmp * parent_rate) / 16;
> +
> +	return clkmain->rate;
> +}
> +
> +static const struct clk_ops main_ops = {
> +	.prepare = clk_main_prepare,
> +	.is_prepared = clk_main_is_prepared,
> +	.recalc_rate = clk_main_recalc_rate,
> +};
> +
> +static struct clk * __init
> +at91_clk_register_main(struct at91_pmc *pmc,
> +		       unsigned int irq,
> +		       const char *name,
> +		       const char *parent_name,
> +		       unsigned long rate)
> +{
> +	int ret;
> +	struct clk_main *clkmain;
> +	struct clk *clk = NULL;
> +	struct clk_init_data init;
> +
> +	if (!pmc || !irq || !name)
> +		return ERR_PTR(-EINVAL);
> +
> +	if (!rate && !parent_name)
> +		return ERR_PTR(-EINVAL);
> +
> +	clkmain = kzalloc(sizeof(*clkmain), GFP_KERNEL);
> +	if (!clkmain)
> +		return ERR_PTR(-ENOMEM);
> +
> +	init.name = name;
> +	init.ops = &main_ops;
> +	init.parent_names = parent_name ? &parent_name : NULL;
> +	init.num_parents = parent_name ? 1 : 0;
> +	init.flags = parent_name ? 0 : CLK_IS_ROOT;
> +
> +	clkmain->hw.init = &init;
> +	clkmain->rate = rate;
> +	clkmain->pmc = pmc;
> +	clkmain->irq = irq;
> +	init_waitqueue_head(&clkmain->wait);
> +	irq_set_status_flags(clkmain->irq, IRQ_NOAUTOEN);
> +	ret = request_irq(clkmain->irq, clk_main_irq_handler,
> +			  IRQF_TRIGGER_HIGH, "clk-main", clkmain);
> +	if (ret)
> +		return ERR_PTR(ret);
> +
> +	clk = clk_register(NULL, &clkmain->hw);
> +
> +	if (IS_ERR(clk)) {
> +		free_irq(clkmain->irq, clkmain);
> +		kfree(clkmain);
> +	}
> +
> +	return clk;
> +}
> +
> +
> +
> +static void __init
> +of_at91_clk_main_setup(struct device_node *np, struct at91_pmc *pmc)
> +{
> +	struct clk *clk;
> +	unsigned int irq;
> +	const char *parent_name;
> +	const char *name = np->name;
> +	u32 rate = 0;
> +
> +	parent_name = of_clk_get_parent_name(np, 0);
> +	of_property_read_string(np, "clock-output-names", &name);
> +	of_property_read_u32(np, "clock-frequency", &rate);
> +	irq = irq_of_parse_and_map(np, 0);
> +	if (!irq)
> +		return;
> +
> +	clk = at91_clk_register_main(pmc, irq, name, parent_name, rate);
> +
> +	if (!IS_ERR(clk))
> +		return;
> +
> +	of_clk_add_provider(np, of_clk_src_simple_get, clk);

I do not understand this part: we add the provider if we have not 
registered the clock correctly?

> +}
> +
> +void __init of_at91rm9200_clk_main_setup(struct device_node *np,
> +					 struct at91_pmc *pmc)
> +{
> +	of_at91_clk_main_setup(np, pmc);
> +}
> diff --git a/drivers/clk/at91/pmc.c b/drivers/clk/at91/pmc.c
> index f6bd03d..42f0c19 100644
> --- a/drivers/clk/at91/pmc.c
> +++ b/drivers/clk/at91/pmc.c
> @@ -216,6 +216,11 @@ out_free_pmc:
>   }
>
>   static const struct of_device_id pmc_clk_ids[] __initdata = {
> +	/* Main clock */
> +	{
> +		.compatible = "atmel,at91rm9200-clk-main",
> +		.data = of_at91rm9200_clk_main_setup
> +	},
>   	{ /*sentinel*/ }
>   };
>
> diff --git a/drivers/clk/at91/pmc.h b/drivers/clk/at91/pmc.h
> index b7e8397..294e230 100644
> --- a/drivers/clk/at91/pmc.h
> +++ b/drivers/clk/at91/pmc.h
> @@ -55,4 +55,7 @@ static inline void pmc_write(struct at91_pmc *pmc, int offset, u32 value)
>   	return writel_relaxed(value, pmc->regbase + offset);
>   }
>
> +extern void __init of_at91rm9200_clk_main_setup(struct device_node *np,
> +						struct at91_pmc *pmc);
> +
>   #endif /* __PMC_H_ */
>


-- 
Nicolas Ferre

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

* Re: [PATCH v3 05/19] clk: at91: add PMC main clock
  2013-10-07 16:51   ` Nicolas Ferre
@ 2013-10-07 19:11     ` boris brezillon
  2013-10-08  8:24       ` Nicolas Ferre
  0 siblings, 1 reply; 54+ messages in thread
From: boris brezillon @ 2013-10-07 19:11 UTC (permalink / raw)
  To: Nicolas Ferre, Grant Likely, Rob Herring, Rob Landley,
	Andrew Victor, Jean-Christophe Plagniol-Villard, Russell King,
	Mike Turquette, Felipe Balbi, Greg Kroah-Hartman,
	Ludovic Desroches, Josh Wu, Richard Genoud
  Cc: devicetree, linux-kernel, linux-arm-kernel

On 07/10/2013 18:51, Nicolas Ferre wrote:
> On 08/08/2013 07:06, Boris BREZILLON :
>> This patch adds new at91 main oscillator clock implementation using 
>> common
>> clk framework.
>>
>> If rate is not provided during clock registration it is calculated using
>> the slow clock (main clk parent in this case) rate and MCFR register.
>>
>> Signed-off-by: Boris BREZILLON <b.brezillon@overkiz.com>
>> ---
>>   drivers/clk/at91/Makefile   |    1 +
>>   drivers/clk/at91/clk-main.c |  171 
>> +++++++++++++++++++++++++++++++++++++++++++
>>   drivers/clk/at91/pmc.c      |    5 ++
>>   drivers/clk/at91/pmc.h      |    3 +
>>   4 files changed, 180 insertions(+)
>>   create mode 100644 drivers/clk/at91/clk-main.c
>>
>> diff --git a/drivers/clk/at91/Makefile b/drivers/clk/at91/Makefile
>> index 1d4fb21..44105bd 100644
>> --- a/drivers/clk/at91/Makefile
>> +++ b/drivers/clk/at91/Makefile
>> @@ -3,3 +3,4 @@
>>   #
>>
>>   obj-y += pmc.o
>> +obj-y += clk-main.o
>> diff --git a/drivers/clk/at91/clk-main.c b/drivers/clk/at91/clk-main.c
>> new file mode 100644
>> index 0000000..68738dd
>> --- /dev/null
>> +++ b/drivers/clk/at91/clk-main.c
>> @@ -0,0 +1,171 @@
>> +/*
>> + * drivers/clk/at91/clk-main.c
>> + *
>> + *  Copyright (C) 2013 Boris BREZILLON <b.brezillon@overkiz.com>
>> + *
>> + * This program is free software; you can redistribute it and/or modify
>> + * it under the terms of the GNU General Public License as published by
>> + * the Free Software Foundation; either version 2 of the License, or
>> + * (at your option) any later version.
>> + *
>> + */
>> +
>> +#include <linux/clk-provider.h>
>> +#include <linux/clkdev.h>
>> +#include <linux/clk/at91_pmc.h>
>> +#include <linux/of.h>
>> +#include <linux/of_address.h>
>> +#include <linux/of_irq.h>
>> +#include <linux/io.h>
>> +#include <linux/interrupt.h>
>> +#include <linux/irq.h>
>> +#include <linux/sched.h>
>> +#include <linux/wait.h>
>> +
>> +#include "pmc.h"
>> +
>> +#define to_clk_main(hw) container_of(hw, struct clk_main, hw)
>> +struct clk_main {
>> +    struct clk_hw hw;
>> +    struct at91_pmc *pmc;
>> +    unsigned long rate;
>> +    unsigned int irq;
>> +    wait_queue_head_t wait;
>> +};
>> +
>> +static irqreturn_t clk_main_irq_handler(int irq, void *dev_id)
>> +{
>> +    struct clk_main *clkmain = (struct clk_main *)dev_id;
>> +
>> +    wake_up(&clkmain->wait);
>> +    disable_irq_nosync(clkmain->irq);
>> +
>> +    return IRQ_HANDLED;
>> +}
>> +
>> +static int clk_main_prepare(struct clk_hw *hw)
>> +{
>> +    struct clk_main *clkmain = to_clk_main(hw);
>> +    struct at91_pmc *pmc = clkmain->pmc;
>> +
>> +    while (!(pmc_read(pmc, AT91_PMC_SR) & AT91_PMC_MOSCS)) {
>> +        enable_irq(clkmain->irq);
>> +        wait_event(clkmain->wait,
>> +               pmc_read(pmc, AT91_PMC_SR) & AT91_PMC_MOSCS);
>> +    }
>> +
>> +    return 0;
>> +}
>> +
>> +static int clk_main_is_prepared(struct clk_hw *hw)
>> +{
>> +    struct clk_main *clkmain = to_clk_main(hw);
>> +
>> +    return !!(pmc_read(clkmain->pmc, AT91_PMC_SR) & AT91_PMC_MOSCS);
>> +}
>> +
>> +static unsigned long clk_main_recalc_rate(struct clk_hw *hw,
>> +                      unsigned long parent_rate)
>> +{
>> +    u32 tmp;
>> +    struct clk_main *clkmain = to_clk_main(hw);
>> +    struct at91_pmc *pmc = clkmain->pmc;
>> +
>> +    if (clkmain->rate)
>> +        return clkmain->rate;
>> +
>> +    while (!((tmp = pmc_read(pmc, AT91_CKGR_MCFR)) & AT91_PMC_MAINRDY))
>> +        ;
>
> I must say that I do not like this while() loop. Please implement a 
> way out and a mean to release CPU when waiting...
>
> Maybe taking a timeout example like this one:
> http://lxr.free-electrons.com/source/drivers/net/ethernet/cadence/macb.c#L391 
>
>
> Which is actually what I leart from Wolfram during his interesting 
> session @ ELC-E:
> http://elinux.org/images/5/54/Elce11_sang.pdf
>

I'll take a closer look at these references.
As I understand, this is about sleeping between each test/iteration of 
the while loop.

> It is true though that we should keep this very quick to not alter 
> boot time too much.
>
> I also wonder if really checking that main clock is read makes sense. 
> If we are running Linux it probably mean that at least main clock is 
> already well configured by the bootloader.

This is not exactly the status of the main clk (the main clk status is 
reflected by the MOSCXTS bit in the PMC_SR register).
This field reflects the MAINF value reliability (MAINF value is used in 
case the main XTAL frequency was not provided in the dt definition,
to calculate the main XTAL frequency).
Anyway, MAINFRDY will probably be set at the time this code is executed.

>
> And this lead to a more general remark: couldn't we simply state that 
> this clock is fixed and only available for reading its status?
>
This is up to you, but IMHO the code to support this (unlikely) case is 
not so big (even with the sleeping version you suggested).

>
>> +
>> +    tmp &= AT91_PMC_MAINF;
>> +    clkmain->rate = (tmp * parent_rate) / 16;
>> +
>> +    return clkmain->rate;
>> +}
>> +
>> +static const struct clk_ops main_ops = {
>> +    .prepare = clk_main_prepare,
>> +    .is_prepared = clk_main_is_prepared,
>> +    .recalc_rate = clk_main_recalc_rate,
>> +};
>> +
>> +static struct clk * __init
>> +at91_clk_register_main(struct at91_pmc *pmc,
>> +               unsigned int irq,
>> +               const char *name,
>> +               const char *parent_name,
>> +               unsigned long rate)
>> +{
>> +    int ret;
>> +    struct clk_main *clkmain;
>> +    struct clk *clk = NULL;
>> +    struct clk_init_data init;
>> +
>> +    if (!pmc || !irq || !name)
>> +        return ERR_PTR(-EINVAL);
>> +
>> +    if (!rate && !parent_name)
>> +        return ERR_PTR(-EINVAL);
>> +
>> +    clkmain = kzalloc(sizeof(*clkmain), GFP_KERNEL);
>> +    if (!clkmain)
>> +        return ERR_PTR(-ENOMEM);
>> +
>> +    init.name = name;
>> +    init.ops = &main_ops;
>> +    init.parent_names = parent_name ? &parent_name : NULL;
>> +    init.num_parents = parent_name ? 1 : 0;
>> +    init.flags = parent_name ? 0 : CLK_IS_ROOT;
>> +
>> +    clkmain->hw.init = &init;
>> +    clkmain->rate = rate;
>> +    clkmain->pmc = pmc;
>> +    clkmain->irq = irq;
>> +    init_waitqueue_head(&clkmain->wait);
>> +    irq_set_status_flags(clkmain->irq, IRQ_NOAUTOEN);
>> +    ret = request_irq(clkmain->irq, clk_main_irq_handler,
>> +              IRQF_TRIGGER_HIGH, "clk-main", clkmain);
>> +    if (ret)
>> +        return ERR_PTR(ret);
>> +
>> +    clk = clk_register(NULL, &clkmain->hw);
>> +
>> +    if (IS_ERR(clk)) {
>> +        free_irq(clkmain->irq, clkmain);
>> +        kfree(clkmain);
>> +    }
>> +
>> +    return clk;
>> +}
>> +
>> +
>> +
>> +static void __init
>> +of_at91_clk_main_setup(struct device_node *np, struct at91_pmc *pmc)
>> +{
>> +    struct clk *clk;
>> +    unsigned int irq;
>> +    const char *parent_name;
>> +    const char *name = np->name;
>> +    u32 rate = 0;
>> +
>> +    parent_name = of_clk_get_parent_name(np, 0);
>> +    of_property_read_string(np, "clock-output-names", &name);
>> +    of_property_read_u32(np, "clock-frequency", &rate);
>> +    irq = irq_of_parse_and_map(np, 0);
>> +    if (!irq)
>> +        return;
>> +
>> +    clk = at91_clk_register_main(pmc, irq, name, parent_name, rate);
>> +
>> +    if (!IS_ERR(clk))
>> +        return;
>> +
>> +    of_clk_add_provider(np, of_clk_src_simple_get, clk);
>
> I do not understand this part: we add the provider if we have not 
> registered the clock correctly?
This is a bug. :)

I haven't noticed it, because we do not directly request this clk using 
of_clk_get or clk_get function.
Instead this clk is used as a parent for several clks (plls, master, 
...) and in this case the common clk framework only
use parent clk names, not of clk provider to retrieve the appropriate clk.

Anyway, thanks for catching this bug, I'll fix it.

>
>
>> +}
>> +
>> +void __init of_at91rm9200_clk_main_setup(struct device_node *np,
>> +                     struct at91_pmc *pmc)
>> +{
>> +    of_at91_clk_main_setup(np, pmc);
>> +}
>> diff --git a/drivers/clk/at91/pmc.c b/drivers/clk/at91/pmc.c
>> index f6bd03d..42f0c19 100644
>> --- a/drivers/clk/at91/pmc.c
>> +++ b/drivers/clk/at91/pmc.c
>> @@ -216,6 +216,11 @@ out_free_pmc:
>>   }
>>
>>   static const struct of_device_id pmc_clk_ids[] __initdata = {
>> +    /* Main clock */
>> +    {
>> +        .compatible = "atmel,at91rm9200-clk-main",
>> +        .data = of_at91rm9200_clk_main_setup
>> +    },
>>       { /*sentinel*/ }
>>   };
>>
>> diff --git a/drivers/clk/at91/pmc.h b/drivers/clk/at91/pmc.h
>> index b7e8397..294e230 100644
>> --- a/drivers/clk/at91/pmc.h
>> +++ b/drivers/clk/at91/pmc.h
>> @@ -55,4 +55,7 @@ static inline void pmc_write(struct at91_pmc *pmc, 
>> int offset, u32 value)
>>       return writel_relaxed(value, pmc->regbase + offset);
>>   }
>>
>> +extern void __init of_at91rm9200_clk_main_setup(struct device_node *np,
>> +                        struct at91_pmc *pmc);
>> +
>>   #endif /* __PMC_H_ */
>>
>
>


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

* Re: [PATCH v3 05/19] clk: at91: add PMC main clock
  2013-10-07 19:11     ` boris brezillon
@ 2013-10-08  8:24       ` Nicolas Ferre
  2013-10-08  9:00         ` boris brezillon
  0 siblings, 1 reply; 54+ messages in thread
From: Nicolas Ferre @ 2013-10-08  8:24 UTC (permalink / raw)
  To: boris brezillon, Grant Likely, Rob Herring, Rob Landley,
	Andrew Victor, Jean-Christophe Plagniol-Villard, Russell King,
	Mike Turquette, Felipe Balbi, Greg Kroah-Hartman,
	Ludovic Desroches, Josh Wu, Richard Genoud
  Cc: devicetree, linux-kernel, linux-arm-kernel

On 07/10/2013 21:11, boris brezillon :
> On 07/10/2013 18:51, Nicolas Ferre wrote:
>> On 08/08/2013 07:06, Boris BREZILLON :
>>> This patch adds new at91 main oscillator clock implementation using
>>> common
>>> clk framework.
>>>
>>> If rate is not provided during clock registration it is calculated using
>>> the slow clock (main clk parent in this case) rate and MCFR register.
>>>
>>> Signed-off-by: Boris BREZILLON <b.brezillon@overkiz.com>
>>> ---
>>>    drivers/clk/at91/Makefile   |    1 +
>>>    drivers/clk/at91/clk-main.c |  171
>>> +++++++++++++++++++++++++++++++++++++++++++
>>>    drivers/clk/at91/pmc.c      |    5 ++
>>>    drivers/clk/at91/pmc.h      |    3 +
>>>    4 files changed, 180 insertions(+)
>>>    create mode 100644 drivers/clk/at91/clk-main.c
>>>
>>> diff --git a/drivers/clk/at91/Makefile b/drivers/clk/at91/Makefile
>>> index 1d4fb21..44105bd 100644
>>> --- a/drivers/clk/at91/Makefile
>>> +++ b/drivers/clk/at91/Makefile
>>> @@ -3,3 +3,4 @@
>>>    #
>>>
>>>    obj-y += pmc.o
>>> +obj-y += clk-main.o
>>> diff --git a/drivers/clk/at91/clk-main.c b/drivers/clk/at91/clk-main.c
>>> new file mode 100644
>>> index 0000000..68738dd
>>> --- /dev/null
>>> +++ b/drivers/clk/at91/clk-main.c
>>> @@ -0,0 +1,171 @@
>>> +/*
>>> + * drivers/clk/at91/clk-main.c
>>> + *
>>> + *  Copyright (C) 2013 Boris BREZILLON <b.brezillon@overkiz.com>
>>> + *
>>> + * This program is free software; you can redistribute it and/or modify
>>> + * it under the terms of the GNU General Public License as published by
>>> + * the Free Software Foundation; either version 2 of the License, or
>>> + * (at your option) any later version.
>>> + *
>>> + */
>>> +
>>> +#include <linux/clk-provider.h>
>>> +#include <linux/clkdev.h>
>>> +#include <linux/clk/at91_pmc.h>
>>> +#include <linux/of.h>
>>> +#include <linux/of_address.h>
>>> +#include <linux/of_irq.h>
>>> +#include <linux/io.h>
>>> +#include <linux/interrupt.h>
>>> +#include <linux/irq.h>
>>> +#include <linux/sched.h>
>>> +#include <linux/wait.h>
>>> +
>>> +#include "pmc.h"
>>> +
>>> +#define to_clk_main(hw) container_of(hw, struct clk_main, hw)
>>> +struct clk_main {
>>> +    struct clk_hw hw;
>>> +    struct at91_pmc *pmc;
>>> +    unsigned long rate;
>>> +    unsigned int irq;
>>> +    wait_queue_head_t wait;
>>> +};
>>> +
>>> +static irqreturn_t clk_main_irq_handler(int irq, void *dev_id)
>>> +{
>>> +    struct clk_main *clkmain = (struct clk_main *)dev_id;
>>> +
>>> +    wake_up(&clkmain->wait);
>>> +    disable_irq_nosync(clkmain->irq);
>>> +
>>> +    return IRQ_HANDLED;
>>> +}
>>> +
>>> +static int clk_main_prepare(struct clk_hw *hw)
>>> +{
>>> +    struct clk_main *clkmain = to_clk_main(hw);
>>> +    struct at91_pmc *pmc = clkmain->pmc;
>>> +
>>> +    while (!(pmc_read(pmc, AT91_PMC_SR) & AT91_PMC_MOSCS)) {
>>> +        enable_irq(clkmain->irq);
>>> +        wait_event(clkmain->wait,
>>> +               pmc_read(pmc, AT91_PMC_SR) & AT91_PMC_MOSCS);
>>> +    }
>>> +
>>> +    return 0;
>>> +}
>>> +
>>> +static int clk_main_is_prepared(struct clk_hw *hw)
>>> +{
>>> +    struct clk_main *clkmain = to_clk_main(hw);
>>> +
>>> +    return !!(pmc_read(clkmain->pmc, AT91_PMC_SR) & AT91_PMC_MOSCS);
>>> +}
>>> +
>>> +static unsigned long clk_main_recalc_rate(struct clk_hw *hw,
>>> +                      unsigned long parent_rate)
>>> +{
>>> +    u32 tmp;
>>> +    struct clk_main *clkmain = to_clk_main(hw);
>>> +    struct at91_pmc *pmc = clkmain->pmc;
>>> +
>>> +    if (clkmain->rate)
>>> +        return clkmain->rate;
>>> +
>>> +    while (!((tmp = pmc_read(pmc, AT91_CKGR_MCFR)) & AT91_PMC_MAINRDY))
>>> +        ;
>>
>> I must say that I do not like this while() loop. Please implement a
>> way out and a mean to release CPU when waiting...
>>
>> Maybe taking a timeout example like this one:
>> http://lxr.free-electrons.com/source/drivers/net/ethernet/cadence/macb.c#L391
>>
>>
>> Which is actually what I leart from Wolfram during his interesting
>> session @ ELC-E:
>> http://elinux.org/images/5/54/Elce11_sang.pdf
>>
>
> I'll take a closer look at these references.
> As I understand, this is about sleeping between each test/iteration of
> the while loop.
>
>> It is true though that we should keep this very quick to not alter
>> boot time too much.
>>
>> I also wonder if really checking that main clock is read makes sense.
>> If we are running Linux it probably mean that at least main clock is
>> already well configured by the bootloader.
>
> This is not exactly the status of the main clk (the main clk status is
> reflected by the MOSCXTS bit in the PMC_SR register).
> This field reflects the MAINF value reliability (MAINF value is used in
> case the main XTAL frequency was not provided in the dt definition,
> to calculate the main XTAL frequency).
> Anyway, MAINFRDY will probably be set at the time this code is executed.
>
>>
>> And this lead to a more general remark: couldn't we simply state that
>> this clock is fixed and only available for reading its status?
>>
> This is up to you, but IMHO the code to support this (unlikely) case is
> not so big (even with the sleeping version you suggested).

Fair enough, let's go for this version.

>>> +
>>> +    tmp &= AT91_PMC_MAINF;
>>> +    clkmain->rate = (tmp * parent_rate) / 16;
>>> +
>>> +    return clkmain->rate;
>>> +}
>>> +
>>> +static const struct clk_ops main_ops = {
>>> +    .prepare = clk_main_prepare,
>>> +    .is_prepared = clk_main_is_prepared,
>>> +    .recalc_rate = clk_main_recalc_rate,
>>> +};
>>> +
>>> +static struct clk * __init
>>> +at91_clk_register_main(struct at91_pmc *pmc,
>>> +               unsigned int irq,
>>> +               const char *name,
>>> +               const char *parent_name,
>>> +               unsigned long rate)
>>> +{
>>> +    int ret;
>>> +    struct clk_main *clkmain;
>>> +    struct clk *clk = NULL;
>>> +    struct clk_init_data init;
>>> +
>>> +    if (!pmc || !irq || !name)
>>> +        return ERR_PTR(-EINVAL);
>>> +
>>> +    if (!rate && !parent_name)
>>> +        return ERR_PTR(-EINVAL);
>>> +
>>> +    clkmain = kzalloc(sizeof(*clkmain), GFP_KERNEL);
>>> +    if (!clkmain)
>>> +        return ERR_PTR(-ENOMEM);
>>> +
>>> +    init.name = name;
>>> +    init.ops = &main_ops;
>>> +    init.parent_names = parent_name ? &parent_name : NULL;
>>> +    init.num_parents = parent_name ? 1 : 0;
>>> +    init.flags = parent_name ? 0 : CLK_IS_ROOT;
>>> +
>>> +    clkmain->hw.init = &init;
>>> +    clkmain->rate = rate;
>>> +    clkmain->pmc = pmc;
>>> +    clkmain->irq = irq;
>>> +    init_waitqueue_head(&clkmain->wait);
>>> +    irq_set_status_flags(clkmain->irq, IRQ_NOAUTOEN);
>>> +    ret = request_irq(clkmain->irq, clk_main_irq_handler,
>>> +              IRQF_TRIGGER_HIGH, "clk-main", clkmain);
>>> +    if (ret)
>>> +        return ERR_PTR(ret);
>>> +
>>> +    clk = clk_register(NULL, &clkmain->hw);
>>> +
>>> +    if (IS_ERR(clk)) {
>>> +        free_irq(clkmain->irq, clkmain);
>>> +        kfree(clkmain);
>>> +    }
>>> +
>>> +    return clk;
>>> +}
>>> +
>>> +
>>> +
>>> +static void __init
>>> +of_at91_clk_main_setup(struct device_node *np, struct at91_pmc *pmc)
>>> +{
>>> +    struct clk *clk;
>>> +    unsigned int irq;
>>> +    const char *parent_name;
>>> +    const char *name = np->name;
>>> +    u32 rate = 0;
>>> +
>>> +    parent_name = of_clk_get_parent_name(np, 0);
>>> +    of_property_read_string(np, "clock-output-names", &name);
>>> +    of_property_read_u32(np, "clock-frequency", &rate);
>>> +    irq = irq_of_parse_and_map(np, 0);
>>> +    if (!irq)
>>> +        return;
>>> +
>>> +    clk = at91_clk_register_main(pmc, irq, name, parent_name, rate);
>>> +
>>> +    if (!IS_ERR(clk))
>>> +        return;
>>> +
>>> +    of_clk_add_provider(np, of_clk_src_simple_get, clk);
>>
>> I do not understand this part: we add the provider if we have not
>> registered the clock correctly?
> This is a bug. :)
>
> I haven't noticed it, because we do not directly request this clk using
> of_clk_get or clk_get function.
> Instead this clk is used as a parent for several clks (plls, master,
> ...) and in this case the common clk framework only
> use parent clk names, not of clk provider to retrieve the appropriate clk.
>
> Anyway, thanks for catching this bug, I'll fix it.
>
>>
>>
>>> +}
>>> +
>>> +void __init of_at91rm9200_clk_main_setup(struct device_node *np,
>>> +                     struct at91_pmc *pmc)
>>> +{
>>> +    of_at91_clk_main_setup(np, pmc);
>>> +}
>>> diff --git a/drivers/clk/at91/pmc.c b/drivers/clk/at91/pmc.c
>>> index f6bd03d..42f0c19 100644
>>> --- a/drivers/clk/at91/pmc.c
>>> +++ b/drivers/clk/at91/pmc.c
>>> @@ -216,6 +216,11 @@ out_free_pmc:
>>>    }
>>>
>>>    static const struct of_device_id pmc_clk_ids[] __initdata = {
>>> +    /* Main clock */
>>> +    {
>>> +        .compatible = "atmel,at91rm9200-clk-main",
>>> +        .data = of_at91rm9200_clk_main_setup
>>> +    },
>>>        { /*sentinel*/ }
>>>    };
>>>
>>> diff --git a/drivers/clk/at91/pmc.h b/drivers/clk/at91/pmc.h
>>> index b7e8397..294e230 100644
>>> --- a/drivers/clk/at91/pmc.h
>>> +++ b/drivers/clk/at91/pmc.h
>>> @@ -55,4 +55,7 @@ static inline void pmc_write(struct at91_pmc *pmc,
>>> int offset, u32 value)
>>>        return writel_relaxed(value, pmc->regbase + offset);
>>>    }
>>>
>>> +extern void __init of_at91rm9200_clk_main_setup(struct device_node *np,
>>> +                        struct at91_pmc *pmc);
>>> +
>>>    #endif /* __PMC_H_ */
>>>
>>
>>
>
>


-- 
Nicolas Ferre

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

* Re: [PATCH v3 05/19] clk: at91: add PMC main clock
  2013-10-08  8:24       ` Nicolas Ferre
@ 2013-10-08  9:00         ` boris brezillon
  0 siblings, 0 replies; 54+ messages in thread
From: boris brezillon @ 2013-10-08  9:00 UTC (permalink / raw)
  To: Nicolas Ferre, Grant Likely, Rob Herring, Rob Landley,
	Andrew Victor, Jean-Christophe Plagniol-Villard, Russell King,
	Mike Turquette, Felipe Balbi, Greg Kroah-Hartman,
	Ludovic Desroches, Josh Wu, Richard Genoud
  Cc: devicetree, linux-kernel, linux-arm-kernel

On 08/10/2013 10:24, Nicolas Ferre wrote:
> On 07/10/2013 21:11, boris brezillon :
>> On 07/10/2013 18:51, Nicolas Ferre wrote:
>>> On 08/08/2013 07:06, Boris BREZILLON :
>>>> This patch adds new at91 main oscillator clock implementation using
>>>> common
>>>> clk framework.
>>>>
>>>> If rate is not provided during clock registration it is calculated 
>>>> using
>>>> the slow clock (main clk parent in this case) rate and MCFR register.
>>>>
>>>> Signed-off-by: Boris BREZILLON <b.brezillon@overkiz.com>
>>>> ---
>>>>    drivers/clk/at91/Makefile   |    1 +
>>>>    drivers/clk/at91/clk-main.c |  171
>>>> +++++++++++++++++++++++++++++++++++++++++++
>>>>    drivers/clk/at91/pmc.c      |    5 ++
>>>>    drivers/clk/at91/pmc.h      |    3 +
>>>>    4 files changed, 180 insertions(+)
>>>>    create mode 100644 drivers/clk/at91/clk-main.c
>>>>
>>>> diff --git a/drivers/clk/at91/Makefile b/drivers/clk/at91/Makefile
>>>> index 1d4fb21..44105bd 100644
>>>> --- a/drivers/clk/at91/Makefile
>>>> +++ b/drivers/clk/at91/Makefile
>>>> @@ -3,3 +3,4 @@
>>>>    #
>>>>
>>>>    obj-y += pmc.o
>>>> +obj-y += clk-main.o
>>>> diff --git a/drivers/clk/at91/clk-main.c b/drivers/clk/at91/clk-main.c
>>>> new file mode 100644
>>>> index 0000000..68738dd
>>>> --- /dev/null
>>>> +++ b/drivers/clk/at91/clk-main.c
>>>> @@ -0,0 +1,171 @@
>>>> +/*
>>>> + * drivers/clk/at91/clk-main.c
>>>> + *
>>>> + *  Copyright (C) 2013 Boris BREZILLON <b.brezillon@overkiz.com>
>>>> + *
>>>> + * This program is free software; you can redistribute it and/or 
>>>> modify
>>>> + * it under the terms of the GNU General Public License as 
>>>> published by
>>>> + * the Free Software Foundation; either version 2 of the License, or
>>>> + * (at your option) any later version.
>>>> + *
>>>> + */
>>>> +
>>>> +#include <linux/clk-provider.h>
>>>> +#include <linux/clkdev.h>
>>>> +#include <linux/clk/at91_pmc.h>
>>>> +#include <linux/of.h>
>>>> +#include <linux/of_address.h>
>>>> +#include <linux/of_irq.h>
>>>> +#include <linux/io.h>
>>>> +#include <linux/interrupt.h>
>>>> +#include <linux/irq.h>
>>>> +#include <linux/sched.h>
>>>> +#include <linux/wait.h>
>>>> +
>>>> +#include "pmc.h"
>>>> +
>>>> +#define to_clk_main(hw) container_of(hw, struct clk_main, hw)
>>>> +struct clk_main {
>>>> +    struct clk_hw hw;
>>>> +    struct at91_pmc *pmc;
>>>> +    unsigned long rate;
>>>> +    unsigned int irq;
>>>> +    wait_queue_head_t wait;
>>>> +};
>>>> +
>>>> +static irqreturn_t clk_main_irq_handler(int irq, void *dev_id)
>>>> +{
>>>> +    struct clk_main *clkmain = (struct clk_main *)dev_id;
>>>> +
>>>> +    wake_up(&clkmain->wait);
>>>> +    disable_irq_nosync(clkmain->irq);
>>>> +
>>>> +    return IRQ_HANDLED;
>>>> +}
>>>> +
>>>> +static int clk_main_prepare(struct clk_hw *hw)
>>>> +{
>>>> +    struct clk_main *clkmain = to_clk_main(hw);
>>>> +    struct at91_pmc *pmc = clkmain->pmc;
>>>> +
>>>> +    while (!(pmc_read(pmc, AT91_PMC_SR) & AT91_PMC_MOSCS)) {
>>>> +        enable_irq(clkmain->irq);
>>>> +        wait_event(clkmain->wait,
>>>> +               pmc_read(pmc, AT91_PMC_SR) & AT91_PMC_MOSCS);
>>>> +    }
>>>> +
>>>> +    return 0;
>>>> +}
>>>> +
>>>> +static int clk_main_is_prepared(struct clk_hw *hw)
>>>> +{
>>>> +    struct clk_main *clkmain = to_clk_main(hw);
>>>> +
>>>> +    return !!(pmc_read(clkmain->pmc, AT91_PMC_SR) & AT91_PMC_MOSCS);
>>>> +}
>>>> +
>>>> +static unsigned long clk_main_recalc_rate(struct clk_hw *hw,
>>>> +                      unsigned long parent_rate)
>>>> +{
>>>> +    u32 tmp;
>>>> +    struct clk_main *clkmain = to_clk_main(hw);
>>>> +    struct at91_pmc *pmc = clkmain->pmc;
>>>> +
>>>> +    if (clkmain->rate)
>>>> +        return clkmain->rate;
>>>> +
>>>> +    while (!((tmp = pmc_read(pmc, AT91_CKGR_MCFR)) & 
>>>> AT91_PMC_MAINRDY))
>>>> +        ;
>>>
>>> I must say that I do not like this while() loop. Please implement a
>>> way out and a mean to release CPU when waiting...
>>>
>>> Maybe taking a timeout example like this one:
>>> http://lxr.free-electrons.com/source/drivers/net/ethernet/cadence/macb.c#L391 
>>>
>>>
>>>
>>> Which is actually what I leart from Wolfram during his interesting
>>> session @ ELC-E:
>>> http://elinux.org/images/5/54/Elce11_sang.pdf
>>>
>>
>> I'll take a closer look at these references.
>> As I understand, this is about sleeping between each test/iteration of
>> the while loop.
>>

Mike, I'm not sure if the recalc_rate callback can actually sleep.
If this is not the case, we should move this waiting loop in clk_prepare.

What do you think ?

>>> It is true though that we should keep this very quick to not alter
>>> boot time too much.
>>>
>>> I also wonder if really checking that main clock is read makes sense.
>>> If we are running Linux it probably mean that at least main clock is
>>> already well configured by the bootloader.
>>
>> This is not exactly the status of the main clk (the main clk status is
>> reflected by the MOSCXTS bit in the PMC_SR register).
>> This field reflects the MAINF value reliability (MAINF value is used in
>> case the main XTAL frequency was not provided in the dt definition,
>> to calculate the main XTAL frequency).
>> Anyway, MAINFRDY will probably be set at the time this code is executed.
>>
>>>
>>> And this lead to a more general remark: couldn't we simply state that
>>> this clock is fixed and only available for reading its status?
>>>
>> This is up to you, but IMHO the code to support this (unlikely) case is
>> not so big (even with the sleeping version you suggested).
>
> Fair enough, let's go for this version.
>
>>>> +
>>>> +    tmp &= AT91_PMC_MAINF;
>>>> +    clkmain->rate = (tmp * parent_rate) / 16;
>>>> +
>>>> +    return clkmain->rate;
>>>> +}
>>>> +
>>>> +static const struct clk_ops main_ops = {
>>>> +    .prepare = clk_main_prepare,
>>>> +    .is_prepared = clk_main_is_prepared,
>>>> +    .recalc_rate = clk_main_recalc_rate,
>>>> +};
>>>> +
>>>> +static struct clk * __init
>>>> +at91_clk_register_main(struct at91_pmc *pmc,
>>>> +               unsigned int irq,
>>>> +               const char *name,
>>>> +               const char *parent_name,
>>>> +               unsigned long rate)
>>>> +{
>>>> +    int ret;
>>>> +    struct clk_main *clkmain;
>>>> +    struct clk *clk = NULL;
>>>> +    struct clk_init_data init;
>>>> +
>>>> +    if (!pmc || !irq || !name)
>>>> +        return ERR_PTR(-EINVAL);
>>>> +
>>>> +    if (!rate && !parent_name)
>>>> +        return ERR_PTR(-EINVAL);
>>>> +
>>>> +    clkmain = kzalloc(sizeof(*clkmain), GFP_KERNEL);
>>>> +    if (!clkmain)
>>>> +        return ERR_PTR(-ENOMEM);
>>>> +
>>>> +    init.name = name;
>>>> +    init.ops = &main_ops;
>>>> +    init.parent_names = parent_name ? &parent_name : NULL;
>>>> +    init.num_parents = parent_name ? 1 : 0;
>>>> +    init.flags = parent_name ? 0 : CLK_IS_ROOT;
>>>> +
>>>> +    clkmain->hw.init = &init;
>>>> +    clkmain->rate = rate;
>>>> +    clkmain->pmc = pmc;
>>>> +    clkmain->irq = irq;
>>>> +    init_waitqueue_head(&clkmain->wait);
>>>> +    irq_set_status_flags(clkmain->irq, IRQ_NOAUTOEN);
>>>> +    ret = request_irq(clkmain->irq, clk_main_irq_handler,
>>>> +              IRQF_TRIGGER_HIGH, "clk-main", clkmain);
>>>> +    if (ret)
>>>> +        return ERR_PTR(ret);
>>>> +
>>>> +    clk = clk_register(NULL, &clkmain->hw);
>>>> +
>>>> +    if (IS_ERR(clk)) {
>>>> +        free_irq(clkmain->irq, clkmain);
>>>> +        kfree(clkmain);
>>>> +    }
>>>> +
>>>> +    return clk;
>>>> +}
>>>> +
>>>> +
>>>> +
>>>> +static void __init
>>>> +of_at91_clk_main_setup(struct device_node *np, struct at91_pmc *pmc)
>>>> +{
>>>> +    struct clk *clk;
>>>> +    unsigned int irq;
>>>> +    const char *parent_name;
>>>> +    const char *name = np->name;
>>>> +    u32 rate = 0;
>>>> +
>>>> +    parent_name = of_clk_get_parent_name(np, 0);
>>>> +    of_property_read_string(np, "clock-output-names", &name);
>>>> +    of_property_read_u32(np, "clock-frequency", &rate);
>>>> +    irq = irq_of_parse_and_map(np, 0);
>>>> +    if (!irq)
>>>> +        return;
>>>> +
>>>> +    clk = at91_clk_register_main(pmc, irq, name, parent_name, rate);
>>>> +
>>>> +    if (!IS_ERR(clk))
>>>> +        return;
>>>> +
>>>> +    of_clk_add_provider(np, of_clk_src_simple_get, clk);
>>>
>>> I do not understand this part: we add the provider if we have not
>>> registered the clock correctly?
>> This is a bug. :)
>>
>> I haven't noticed it, because we do not directly request this clk using
>> of_clk_get or clk_get function.
>> Instead this clk is used as a parent for several clks (plls, master,
>> ...) and in this case the common clk framework only
>> use parent clk names, not of clk provider to retrieve the appropriate 
>> clk.
>>
>> Anyway, thanks for catching this bug, I'll fix it.
>>
>>>
>>>
>>>> +}
>>>> +
>>>> +void __init of_at91rm9200_clk_main_setup(struct device_node *np,
>>>> +                     struct at91_pmc *pmc)
>>>> +{
>>>> +    of_at91_clk_main_setup(np, pmc);
>>>> +}
>>>> diff --git a/drivers/clk/at91/pmc.c b/drivers/clk/at91/pmc.c
>>>> index f6bd03d..42f0c19 100644
>>>> --- a/drivers/clk/at91/pmc.c
>>>> +++ b/drivers/clk/at91/pmc.c
>>>> @@ -216,6 +216,11 @@ out_free_pmc:
>>>>    }
>>>>
>>>>    static const struct of_device_id pmc_clk_ids[] __initdata = {
>>>> +    /* Main clock */
>>>> +    {
>>>> +        .compatible = "atmel,at91rm9200-clk-main",
>>>> +        .data = of_at91rm9200_clk_main_setup
>>>> +    },
>>>>        { /*sentinel*/ }
>>>>    };
>>>>
>>>> diff --git a/drivers/clk/at91/pmc.h b/drivers/clk/at91/pmc.h
>>>> index b7e8397..294e230 100644
>>>> --- a/drivers/clk/at91/pmc.h
>>>> +++ b/drivers/clk/at91/pmc.h
>>>> @@ -55,4 +55,7 @@ static inline void pmc_write(struct at91_pmc *pmc,
>>>> int offset, u32 value)
>>>>        return writel_relaxed(value, pmc->regbase + offset);
>>>>    }
>>>>
>>>> +extern void __init of_at91rm9200_clk_main_setup(struct device_node 
>>>> *np,
>>>> +                        struct at91_pmc *pmc);
>>>> +
>>>>    #endif /* __PMC_H_ */
>>>>
>>>
>>>
>>
>>
>
>


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

* Re: [PATCH v3 17/19] clk: at91: add PMC clk device tree binding doc.
  2013-08-08  7:19 ` [PATCH v3 17/19] clk: at91: add PMC clk device tree binding doc Boris BREZILLON
@ 2013-10-08  9:44   ` Nicolas Ferre
  2013-10-08 12:37     ` boris brezillon
  0 siblings, 1 reply; 54+ messages in thread
From: Nicolas Ferre @ 2013-10-08  9:44 UTC (permalink / raw)
  To: Boris BREZILLON, Grant Likely, Rob Herring, Rob Landley,
	Andrew Victor, Jean-Christophe Plagniol-Villard, Russell King,
	Mike Turquette, Felipe Balbi, Greg Kroah-Hartman,
	Ludovic Desroches, Josh Wu, Richard Genoud
  Cc: devicetree, linux-kernel, linux-arm-kernel

On 08/08/2013 09:19, Boris BREZILLON :
> This patch adds new at91 clks dt bindings documentation.
>
> Signed-off-by: Boris BREZILLON <b.brezillon@overkiz.com>
> ---
>   .../devicetree/bindings/clock/at91-clock.txt       |  312 ++++++++++++++++++++
>   1 file changed, 312 insertions(+)
>   create mode 100644 Documentation/devicetree/bindings/clock/at91-clock.txt
>
> diff --git a/Documentation/devicetree/bindings/clock/at91-clock.txt b/Documentation/devicetree/bindings/clock/at91-clock.txt
> new file mode 100644
> index 0000000..04739da
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/clock/at91-clock.txt
> @@ -0,0 +1,312 @@
> +Device Tree Clock bindings for arch-at91
> +
> +This binding uses the common clock binding[1].
> +
> +[1] Documentation/devicetree/bindings/clock/clock-bindings.txt
> +
> +Required properties:
> +- compatible : shall be one of the following:
> +	"atmel,at91rm9200-pmc" or
> +	"atmel,at91sam9g45-pmc" or
> +	"atmel,at91sam9n12-pmc" or
> +	"atmel,at91sam9x5-pmc" or
> +	"atmel,at91sam9g35-pmc" or

Already said in previous patches: 9g35 is not different from the 9x5: it 
was a bug in the older datasheet.

> +	"atmel,sama5d3-pmc":
> +		at91 PMC (Power Management Controller)
> +		All at91 specific clocks (clocks defined below) must be child
> +		node of the PMC node.
> +
> +	"atmel,at91rm9200-clk-main":
> +		at91 main oscillator
> +
> +	"atmel,at91rm9200-clk-master" or
> +	"atmel,at91sam9x5-clk-master":
> +		at91 master clock
> +
> +	"atmel,at91sam9x5-clk-peripheral" or
> +	"atmel,at91rm9200-clk-peripheral":
> +		at91 peripheral clocks
> +
> +	"atmel,at91rm9200-clk-pll" or
> +	"atmel,at91sam9g45-clk-pll" or
> +	"atmel,at91sam9g20-clk-pllb" or
> +	"atmel,sama5d3-clk-pll":
> +		at91 pll clocks
> +
> +	"atmel,at91sam9x5-clk-plldiv":
> +		at91 plla divisor
> +
> +	"atmel,at91rm9200-clk-programmable" or
> +	"atmel,at91sam9g45-clk-programmable" or
> +	"atmel,at91sam9x5-clk-programmable":
> +		at91 programmable clocks
> +
> +	"atmel,at91sam9x5-clk-smd":
> +		at91 SMD (Soft Modem) clock
> +
> +	"atmel,at91rm9200-clk-system":
> +		at91 system clocks
> +
> +	"atmel,at91rm9200-clk-usb" or
> +	"atmel,at91sam9x5-clk-usb":
> +		at91 usb clock
> +
> +	"atmel,at91sam9x5-clk-utmi":
> +		at91 utmi clock
> +
> +Required properties for PMC node:
> +- reg : defines the IO memory reserved for the PMC.
> +- interrupts : shall be set to PMC interrupt line.
> +- interrupt-controller : tell that the PMC is an interrupt controller
> +- #interrupt-cells : must be set to 2. The first cell encodes the interrupt id

Please add more information about these values.


> +		     the second cell encodes the interrupt type.

Here also: is it always the same type that shall be given? Following 
which rule? What are the allowed values?


> +For example:
> + 	pmc: pmc@fffffc00 {
> +		compatible = "atmel,sama5d3-pmc";
> +		interrupts = <AT91_ID_SYS IRQ_TYPE_LEVEL_HIGH 7>;

It is an habit not to use macro names in device tree examples (even if 
it is true that it is more readable).

> +		interrupt-controller;
> +		#interrupt-cells = <2>;
> +
> +		/* put at91 clocks here */
> +	};
> +
> +Required properties for main clock:
> +- interrupt-parent : must reference the PMC node.
> +- interrupts : shall be set to "<AT91_PMC_MOSCS IRQ_TYPE_LEVEL_HIGH>".

Ditto. Here you can use the numerical value and also specify the macro 
name. But the numerical value should prevail.

> +- #clock-cells : from common clock binding; shall be set to 0.
> +- clocks (optional if clock-frequency is provided) : shall be the slow clock
> +	phandle. This clock is used to compute the main clock rate if
> +	"clock-frequency" is not provided.
> +- clock-frequency: the main oscillator frequency.Prefer the use of

Nit. one white space missing

> +	"clock-frequency" over automatic clock rate computation.


> +
> +For example:
> +	main: mainck {
> +		compatible = "atmel,at91rm9200-clk-main";
> +		interrupt-parent = <&pmc>;
> +		interrupts = <AT91_PMC_MOSCS IRQ_TYPE_LEVEL_HIGH>;

Ditto

> +		#clock-cells = <0>;
> +		clocks = <&ck32k>;
> +		clock-frequency = <18432000>;
> +	};
> +
> +Required properties for master clock:
> +- interrupt-parent : must reference the PMC node.
> +- interrupts : shall be set to "<AT91_PMC_MCKRDY IRQ_TYPE_LEVEL_HIGH>".

Ditto

> +- #clock-cells : from common clock binding; shall be set to 0.
> +- clocks : shall be the master clock sources (see atmel datasheet) phandles.
> +	e.g. "<&ck32k>, <&main>, <&plla>, <&pllb>".
> +- atmel,clk-output-range : minimum and maximum clock frequency (two u32
> +			   fields).
> +	   e.g. output = <0 133000000>; <=> 0 to 133MHz.
> +- atmel,clk-divisors : master clock divisors table (four u32 fields).
> +		0 <=> reserved value.
> +		e.g. divisors = <1 2 4 6>;
> +- atmel,master-clk-have-div3-pres : some SoC use the reserved value 7 in the
> +				    PRES field as CLOCK_DIV3 (e.g sam9x5).

I will check with care the master clock driver as this one is pretty 
picky about changes that could affect it! Note that in previous clock 
implementation we did not touched the MCK configuration, we were only 
reading it...

Anyway, let's keep this binding but make sure that driver is written 
with extreme care ;-)

> +
> +For example:
> +	mck: mck {
> +		compatible = "atmel,at91rm9200-clk-master";
> +		interrupt-parent = <&pmc>;
> +		interrupts = <AT91_PMC_MCKRDY IRQ_TYPE_LEVEL_HIGH>;
> +		#clock-cells = <0>;
> +		atmel,clk-output-range = <0 133000000>;
> +		atmel,clk-divisors = <1 2 4 0>;
> +	};
> +
> +Required properties for peripheral clocks:
> +- #clock-cells : from common clock binding; shall be set to 1. The second cell
> +	is used to encode the peripheral id. Peripheral ids are defined in
> +	atmel's SoC datasheets.
> +- clocks : shall be the master clock phandle.
> +	e.g. clocks = <&mck>;
> +- name: device tree node describing a specific system clock.
> +	* atmel,clk-id: peripheral id. Peripheral id macros should be used.

No. Please use raw numbers. We will not switch to macros for these 
peripheral IDs.

> +	* atmel,clk-default-divisor (optional, only available for
> +	  "atmel,at91sam9x5-clk-peripheral"): sam9x5 and sama5d3 SoC provides
> +	  configurable peripheral clock divisor. If you define this property
> +	  (u32), the default divisor will be applied when enabling
> +	  peripheral clock. If not provided the peripheral clock is not
> +	  divided.
> +
> +For example:
> +	periph: periphck {
> +		compatible = "atmel,at91sam9x5-clk-peripheral";
> +		#clock-cells = <1>;
> +		clocks = <&mck>;
> +
> +		pioA_clk {
> +			atmel,clk-id = <AT91SAM9X5_ID_PIOA>;

Ditto.

> +			atmel,clk-default-divisor = <1>;
> +		};
> +
> +		pioB_clk {
> +			atmel,clk-id = <AT91SAM9X5_ID_PIOB>;
> +			atmel,clk-default-divisor = <2>;
> +		};
> +	};
> +
> +
> +Required properties for pll clocks:
> +- interrupt-parent : must reference the PMC node.
> +- interrupts : shall be set to "<AT91_PMC_LOCKA IRQ_TYPE_LEVEL_HIGH>".

Ditto

> +- #clock-cells : from common clock binding; shall be set to 0.
> +- clocks : shall be the main clock phandle.
> +- atmel,clk-id : pll id. PLL id macros should be used.

No macros here, simply raw numbers. So this mean that we must have some 
documentation of these numbers.

> +- atmel,clk-input-range : minimum and maximum source clock frequency (two u32
> +			  fields).
> +	  e.g. input = <1 32000000>; <=> 1 to 32MHz.
> +- #atmel,pll-clk-output-range-cells : number of cells reserved for pll output
> +				      range description. Sould be set to 2, 3
> +				      or 4.
> +	* 1st and 2nd cells represent the frequency range (min-max).
> +	* 3rd cell is optional and represents the OUT field value for the given
> +	  range.
> +	* 4th cell is optional and represents the ICPLL field (PLLICPR
> +	  register)
> +- atmel,pll-clk-output-ranges : pll output frequency ranges + optional parameter
> +				depending on #atmel,pll-output-range-cells
> +				property value.
> +
> +For example:
> +	plla: pllack {
> +		compatible = "atmel,at91sam9g45-clk-pll";
> +		interrupt-parent = <&pmc>;
> +		interrupts = <AT91_PMC_LOCKA IRQ_TYPE_LEVEL_HIGH>;
> +		#clock-cells = <0>;
> +		clocks = <&main>;
> +		atmel,clk-id = <AT91_PLLA_CLK>;
> +		atmel,clk-input-range = <2000000 32000000>;
> +		#atmel,pll-clk-output-range-cells = <4>;
> +		atmel,pll-clk-output-ranges = <74500000 800000000 0 0
> +					       69500000 750000000 1 0
> +					       64500000 700000000 2 0
> +					       59500000 650000000 3 0
> +					       54500000 600000000 0 1
> +					       49500000 550000000 1 1
> +					       44500000 500000000 2 1
> +					       40000000 450000000 3 1>;
> +	};
> +
> +Required properties for plldiv clocks:
> +- #clock-cells : from common clock binding; shall be set to 0.
> +- clocks : shall be the plla clock phandle.
> +
> +For example:
> +	plladiv: plladivck {
> +		compatible = "atmel,at91sam9x5-clk-plldiv";
> +		#clock-cells = <0>;
> +		clocks = <&plla>;
> +	};

Maybe a little explanation about this clock. It is a fixed divided (how 
many times?) clock issued from the specified clock.

> +
> +Required properties for programmable clocks:
> +- interrupt-parent : must reference the PMC node.
> +- #clock-cells : from common clock binding; shall be set to 1. The second cell
> +	is used to encode the programmable clock id.
> +	Peripheral ids are in atmel's SoC
> +	datasheets.
> +- clocks : shall be the programmable clock source phandles.
> +	e.g. clocks = <&clk32k>, <&main>, <&plla>, <&pllb>;
> +- name: device tree node describing a specific prog clock.
> +	* atmel,clk-id : programmable clock id (register offset from  PCKx
> +			 register).
> +	* interrupts : shall be set to
> +		       "<AT91_PMC_PCKRDY(id) IRQ_TYPE_LEVEL_HIGH>".

Ditto

> +
> +For example:
> +	prog: progck {
> +		compatible = "atmel,at91sam9g45-clk-programmable";
> +		interrupt-parent = <&pmc>;
> +		#clock-cells = <1>;
> +		clocks = <&clk32k>, <&main>, <&plladiv>, <&utmi>, <&mck>;
> +
> +		prog0 {
> +			atmel,clk-id = <0>;
> +			interrupts = <AT91_PMC_PCKRDY(0) IRQ_TYPE_LEVEL_HIGH>;

Ditto

> +		};
> +
> +		prog1 {
> +			atmel,clk-id = <1>;
> +			interrupts = <AT91_PMC_PCKRDY(1) IRQ_TYPE_LEVEL_HIGH>;
> +		};
> +	};
> +
> +
> +Required properties for smd clock:
> +- #clock-cells : from common clock binding; shall be set to 0.
> +- clocks : shall be the smd clock source phandles.
> +	e.g. clocks = <&plladiv>, <&utmi>;
> +
> +For example:
> +	smd: smdck {
> +		compatible = "atmel,at91sam9x5-clk-smd";
> +		#clock-cells = <0>;
> +		clocks = <&plladiv>, <&utmi>;
> +	};
> +
> +Required properties for system clocks:
> +- #clock-cells : from common clock binding; shall be set to 1. The second cell
> +	is used to encode the system clock id (bit used in SCER/SCDR register).
> +- name: device tree node describing a specific system clock.
> +	* id: system clock id (bit position in SCER/SCDR/SCSR registers).
> +	      System clock id macros should be used.

Ditto

> +
> +For example:
> +	system: systemck {
> +		compatible = "atmel,at91rm9200-clk-system";
> +		#clock-cells = <1>;
> +
> +		ddrck {
> +			atmel,clk-id = <AT91_DDRCK_SYS_CLK>;
> +		};
> +
> +		uhpck {
> +			atmel,clk-id = <AT91_UHP_SYS_CLK>;
> +		};
> +
> +		udpck {
> +			atmel,clk-id = <AT91_UDP_SYS_CLK>;
> +		};
> +	};
> +
> +
> +Required properties for usb clock:
> +- #clock-cells : from common clock binding; shall be set to 0.
> +- clocks : shall be the smd clock source phandles.
> +	e.g. clocks = <&pllb>;
> +- atmel,clk-divisors (only available for "atmel,at91rm9200-clk-usb"):
> +	usb clock divisor table.
> +	e.g. divisors = <1 2 4 0>;
> +- atmel,usb-clk-src0-unused (only available for "atmel,at91sam9x5-clk-usb"):
> +	Some SoC (sam9n12) use usb source 0 to disable the usb clock.

I am not sure that we should use a special case for this device.
The enable/disable is still done by system clock register set.

It is true that this bit is defined differently but just because the 
only source for this clock is pllb.

> +
> +For example:
> +	usb: usbck {
> +		compatible = "atmel,at91sam9x5-clk-usb";
> +		#clock-cells = <0>;
> +		clocks = <&plladiv>, <&utmi>;
> +	};
> +
> +	usb: usbck {
> +		compatible = "atmel,at91rm9200-clk-usb";
> +		#clock-cells = <0>;
> +		clocks = <&pllb>;
> +		atmel,clk-divisors = <1 2 4 0>;
> +	};
> +
> +
> +Required properties for utmi clock:
> +- interrupt-parent : must reference the PMC node.
> +- interrupts : shall be set to "<AT91_PMC_LOCKU IRQ_TYPE_LEVEL_HIGH>".
> +- #clock-cells : from common clock binding; shall be set to 0.
> +- clocks : shall be the main clock source phandle.
> +
> +For example:
> +	utmi: utmick {
> +		compatible = "atmel,at91sam9x5-clk-utmi";
> +		interrupt-parent = <&pmc>;
> +		interrupts = <AT91_PMC_LOCKU IRQ_TYPE_LEVEL_HIGH>;
> +		#clock-cells = <0>;
> +		clocks = <&main>;
> +	};
>

Many things in this patch that will have incident in driver code. I will 
try to be coherent when I review the driver patches ;-)

Anyway, all this seem good!

Bye,
-- 
Nicolas Ferre

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

* Re: [PATCH v3 06/19] clk: at91: add PMC pll clocks
  2013-08-08  6:07 ` [PATCH v3 06/19] clk: at91: add PMC pll clocks Boris BREZILLON
@ 2013-10-08 10:28   ` Nicolas Ferre
  2013-10-08 11:45     ` boris brezillon
  0 siblings, 1 reply; 54+ messages in thread
From: Nicolas Ferre @ 2013-10-08 10:28 UTC (permalink / raw)
  To: Boris BREZILLON, Grant Likely, Rob Herring, Rob Landley,
	Andrew Victor, Jean-Christophe Plagniol-Villard, Russell King,
	Mike Turquette, Felipe Balbi, Greg Kroah-Hartman,
	Ludovic Desroches, Josh Wu, Richard Genoud
  Cc: devicetree, linux-kernel, linux-arm-kernel

On 08/08/2013 08:07, Boris BREZILLON :
> This patch adds new at91 pll clock implementation using common clk framework.
>
> The pll clock layout describe the PLLX register layout.
> There are four pll clock layouts:
> - at91rm9200
> - at91sam9g20
> - at91sam9g45
> - sama5d3
>
> PLL clocks are given characteristics:
> - min/max clock source rate
> - ranges of valid clock output rates
> - values to set in out and icpll fields for each supported output range
>
> These characteristics are checked during rate change to avoid
> over/underclocking.
>
> These characteristics are described in atmel's SoC datasheet in
> "Electrical Characteristics" paragraph.
>
> Signed-off-by: Boris BREZILLON <b.brezillon@overkiz.com>
> ---
>   drivers/clk/at91/Makefile     |    2 +-
>   drivers/clk/at91/clk-pll.c    |  506 +++++++++++++++++++++++++++++++++++++++++
>   drivers/clk/at91/clk-plldiv.c |  137 +++++++++++
>   drivers/clk/at91/pmc.c        |   21 ++
>   drivers/clk/at91/pmc.h        |   11 +
>   include/linux/clk/at91_pmc.h  |    2 +
>   6 files changed, 678 insertions(+), 1 deletion(-)
>   create mode 100644 drivers/clk/at91/clk-pll.c
>   create mode 100644 drivers/clk/at91/clk-plldiv.c
>
> diff --git a/drivers/clk/at91/Makefile b/drivers/clk/at91/Makefile
> index 44105bd..902bbf1 100644
> --- a/drivers/clk/at91/Makefile
> +++ b/drivers/clk/at91/Makefile
> @@ -3,4 +3,4 @@
>   #
>
>   obj-y += pmc.o
> -obj-y += clk-main.o
> +obj-y += clk-main.o clk-pll.o clk-plldiv.o
> diff --git a/drivers/clk/at91/clk-pll.c b/drivers/clk/at91/clk-pll.c
> new file mode 100644
> index 0000000..ce519f2
> --- /dev/null
> +++ b/drivers/clk/at91/clk-pll.c
> @@ -0,0 +1,506 @@
> +/*
> + * drivers/clk/at91/clk-pll.c
> + *
> + *  Copyright (C) 2013 Boris BREZILLON <b.brezillon@overkiz.com>
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License as published by
> + * the Free Software Foundation; either version 2 of the License, or
> + * (at your option) any later version.
> + *
> + */
> +
> +#include <linux/clk-provider.h>
> +#include <linux/clkdev.h>
> +#include <linux/clk/at91_pmc.h>
> +#include <linux/of.h>
> +#include <linux/of_address.h>
> +#include <linux/of_irq.h>
> +#include <linux/io.h>
> +#include <linux/wait.h>
> +#include <linux/sched.h>
> +#include <linux/interrupt.h>
> +#include <linux/irq.h>
> +
> +#include "pmc.h"
> +
> +struct clk_pll_characteristics {
> +	struct clk_range input;
> +	int num_output;
> +	struct clk_range *output;
> +	u16 *icpll;
> +	u8 *out;
> +};
> +
> +struct clk_pll_layout {
> +	u32 pllr_mask;
> +	u16 mul_mask;
> +	u8 mul_shift;
> +};
> +
> +#define to_clk_pll(hw) container_of(hw, struct clk_pll, hw)
> +
> +struct clk_pll {
> +	struct clk_hw hw;
> +	struct at91_pmc *pmc;
> +	unsigned int irq;
> +	wait_queue_head_t wait;
> +	u8 id;
> +	u8 div;
> +	u8 range;
> +	u16 mul;
> +	const struct clk_pll_layout *layout;
> +	const struct clk_pll_characteristics *characteristics;
> +};
> +
> +static irqreturn_t clk_pll_irq_handler(int irq, void *dev_id)
> +{
> +	struct clk_pll *pll = (struct clk_pll *)dev_id;
> +
> +	wake_up(&pll->wait);
> +	disable_irq_nosync(pll->irq);
> +
> +	return IRQ_HANDLED;
> +}
> +
> +static int clk_pll_prepare(struct clk_hw *hw)
> +{
> +	struct clk_pll *pll = to_clk_pll(hw);
> +	struct at91_pmc *pmc = pll->pmc;
> +
> +	while (!(pmc_read(pmc, AT91_PMC_SR) & (1 << (1 + pll->id)))) {

Here, we can define a macro for this driver that can take pll->id and 
give back the mask: it seems to be used frequently in the driver).

> +		enable_irq(pll->irq);
> +		wait_event(pll->wait,
> +			   pmc_read(pmc, AT91_PMC_SR) & (1 << (1 + pll->id)));
> +	}
> +
> +	return 0;
> +}
> +
> +static int clk_pll_is_ready(struct clk_hw *hw)
> +{
> +	struct clk_pll *pll = to_clk_pll(hw);
> +	struct at91_pmc *pmc = pll->pmc;
> +
> +	return !!(pmc_read(pmc, AT91_PMC_SR) &
> +		  (1 << (1 + pll->id)));
> +}
> +
> +static void clk_pll_disable(struct clk_hw *hw)
> +{
> +	struct clk_pll *pll = to_clk_pll(hw);
> +	struct at91_pmc *pmc = pll->pmc;
> +	const struct clk_pll_layout *layout = pll->layout;
> +	int offset = AT91_CKGR_PLLAR + (pll->id * 4);

Here also, a macro can be interesting to retrieve the PLL register address.

> +	u32 tmp = pmc_read(pmc, offset) & ~(layout->pllr_mask);

Well why not just setting MULA/B to 0? I know it is nearly the same but 
on sama5d3, there is a field that must always be set to 1 (bit 29).


> +
> +	pmc_write(pmc, offset, tmp);
> +}
> +
> +static unsigned long clk_pll_recalc_rate(struct clk_hw *hw,
> +					 unsigned long parent_rate)
> +{
> +	struct clk_pll *pll = to_clk_pll(hw);
> +	const struct clk_pll_layout *layout = pll->layout;
> +	struct at91_pmc *pmc = pll->pmc;
> +	int offset = AT91_CKGR_PLLAR + (pll->id * 4);

Ditto

> +	u32 tmp = pmc_read(pmc, offset) & layout->pllr_mask;
> +	u8 div = tmp & 0xFF;

A #defined value, please

> +	u16 mul = (tmp >> layout->mul_shift) & layout->mul_mask;
> +	if (!div || !mul)
> +		return 0;
> +
> +	return (parent_rate * (mul + 1)) / div;
> +}
> +
> +static long clk_pll_get_best_div_mul(struct clk_pll *pll, unsigned long rate,
> +				     unsigned long parent_rate,
> +				     u32 *div, u32 *mul,
> +				     u32 *index) {
> +	unsigned long maxrate;
> +	unsigned long minrate;
> +	unsigned long divrate;
> +	unsigned long bestdiv = 1;
> +	unsigned long bestmul;
> +	unsigned long tmpdiv;
> +	unsigned long roundup;
> +	unsigned long rounddown;
> +	unsigned long remainder;
> +	unsigned long bestremainder;
> +	unsigned long maxmul;
> +	unsigned long maxdiv;
> +	unsigned long mindiv;
> +	int i = 0;
> +	const struct clk_pll_layout *layout = pll->layout;
> +	const struct clk_pll_characteristics *characteristics =
> +							pll->characteristics;
> +
> +	/* Minimum divider = 1 */
> +	/* Maximum multiplier = max_mul */
> +	maxmul = layout->mul_mask + 1;
> +	maxrate = (parent_rate * maxmul) / 1;
> +
> +	/* Maximum divider = max_div */
> +	/* Minimum multiplier = 2 */
> +	maxdiv = 0xFF;

Same defined value as above

> +	minrate = (parent_rate * 2) / maxdiv;
> +
> +	if (parent_rate < characteristics->input.min ||
> +	    parent_rate < characteristics->input.max)
> +		return -ERANGE;
> +
> +	if (parent_rate < minrate || parent_rate > maxrate)
> +		return -ERANGE;
> +
> +	for (i = 0; i < characteristics->num_output; ++i) {
> +		if (parent_rate >= characteristics->output[i].min &&
> +		    parent_rate <= characteristics->output[i].max)
> +			break;
> +		++i;

another iteration of "i" in the loop? If it is required, consider using 
the for() loop with i += 2...

> +	}
> +
> +	if (i >= characteristics->num_output)
> +		return -ERANGE;
> +
> +	bestmul = rate / parent_rate;
> +	rounddown = parent_rate % rate;
> +	roundup = rate - rounddown;
> +	bestremainder = roundup < rounddown ? roundup : rounddown;
> +
> +	if (!bestremainder) {
> +		if (div)
> +			*div = bestdiv;
> +		if (mul)
> +			*mul = bestmul;
> +		if (index)
> +			*index = i;
> +		return rate;
> +	}
> +
> +	maxdiv = 255 / (bestmul + 1);
> +	if (parent_rate / maxdiv < characteristics->input.min)
> +		maxdiv = parent_rate / characteristics->input.min;
> +	mindiv = parent_rate / characteristics->input.max;
> +	if (parent_rate % characteristics->input.max)
> +		mindiv++;
> +
> +	for (tmpdiv = mindiv; tmpdiv < maxdiv; tmpdiv++) {
> +		divrate = parent_rate / tmpdiv;
> +
> +		rounddown = rate % divrate;
> +		roundup = divrate - rounddown;
> +		remainder = roundup < rounddown ? roundup : rounddown;
> +
> +		if (remainder < bestremainder) {
> +			bestremainder = remainder;
> +			bestmul = rate / divrate;
> +			bestdiv = tmpdiv;
> +		}
> +
> +		if (!remainder)
> +			break;
> +	}
> +
> +	rate = (parent_rate / bestdiv) * bestmul;
> +
> +	if (div)
> +		*div = bestdiv;
> +	if (mul)
> +		*mul = bestmul;
> +	if (index)
> +		*index = i;
> +
> +	return rate;
> +}
> +
> +static long clk_pll_round_rate(struct clk_hw *hw, unsigned long rate,
> +					unsigned long *parent_rate)
> +{
> +	struct clk_pll *pll = to_clk_pll(hw);
> +
> +	return clk_pll_get_best_div_mul(pll, rate, *parent_rate,
> +					NULL, NULL, NULL);
> +
> +}
> +
> +static int clk_pll_set_rate(struct clk_hw *hw, unsigned long rate,
> +			    unsigned long parent_rate)
> +{
> +	struct clk_pll *pll = to_clk_pll(hw);
> +	struct at91_pmc *pmc = pll->pmc;
> +	const struct clk_pll_layout *layout = pll->layout;
> +	const struct clk_pll_characteristics *characteristics =
> +						pll->characteristics;
> +	int offset = AT91_CKGR_PLLAR + (pll->id * 4);

Ditto

> +	long ret;
> +	u32 div;
> +	u32 mul;
> +	u32 index;
> +	u32 tmp;
> +	u8 out = 0;
> +
> +	ret = clk_pll_get_best_div_mul(pll, rate, parent_rate,
> +				       &div, &mul, &index);
> +	if (ret < 0)
> +		return ret;
> +
> +	if (characteristics->out)
> +		out = characteristics->out[pll->range];
> +	if (characteristics->icpll) {
> +		tmp = pmc_read(pmc, AT91_PMC_PLLICPR) &
> +		      ~(0xFFFF << (16 * pll->id));

Macros and defined values, please

> +		tmp |= characteristics->icpll[pll->range] << (16 * pll->id);

Here also

> +		pmc_write(pmc, AT91_PMC_PLLICPR, tmp);
> +	}
> +	tmp = pmc_read(pmc, offset) & ~(layout->pllr_mask);
> +	tmp |= layout->pllr_mask & (div | 0x3F << 8 | out << 14 |
> +				    (mul & layout->mul_mask) <<
> +				    layout->mul_shift);

Here also

> +	pmc_write(pmc, offset, tmp);
> +
> +	return 0;
> +}
> +
> +static const struct clk_ops pll_ops = {
> +	.prepare = clk_pll_prepare,
> +	.is_prepared = clk_pll_is_ready,
> +	.disable = clk_pll_disable,
> +	.is_enabled = clk_pll_is_ready,
> +	.recalc_rate = clk_pll_recalc_rate,
> +	.round_rate = clk_pll_round_rate,
> +	.set_rate = clk_pll_set_rate,
> +};
> +
> +static struct clk * __init
> +at91_clk_register_pll(struct at91_pmc *pmc, unsigned int irq, const char *name,
> +		      const char *parent_name, u8 id,
> +		      const struct clk_pll_layout *layout,
> +		      const struct clk_pll_characteristics *characteristics)
> +{
> +	struct clk_pll *pll;
> +	struct clk *clk = NULL;
> +	struct clk_init_data init;
> +	int ret;
> +
> +	id &= 3;

defined value please

> +
> +	pll = kzalloc(sizeof(*pll), GFP_KERNEL);
> +	if (!pll)
> +		return ERR_PTR(-ENOMEM);
> +
> +	init.name = name;
> +	init.ops = &pll_ops;
> +	init.parent_names = &parent_name;
> +	init.num_parents = 1;
> +	init.flags = CLK_SET_RATE_GATE;
> +
> +	pll->id = id;
> +	pll->hw.init = &init;
> +	pll->layout = layout;
> +	pll->characteristics = characteristics;
> +	pll->pmc = pmc;
> +	pll->irq = irq;
> +	init_waitqueue_head(&pll->wait);
> +	irq_set_status_flags(pll->irq, IRQ_NOAUTOEN);
> +	ret = request_irq(pll->irq, clk_pll_irq_handler, IRQF_TRIGGER_HIGH,
> +			  id ? "clk-pllb" : "clk-plla", pll);
> +	if (ret)
> +		return ERR_PTR(ret);
> +
> +	clk = clk_register(NULL, &pll->hw);
> +

No extra space

> +	if (IS_ERR(clk))
> +		kfree(pll);
> +
> +	return clk;
> +}
> +
> +
> +static const struct clk_pll_layout at91rm9200_pll_layout = {
> +	.pllr_mask = 0x7FFFFFF,
> +	.mul_shift = 16,
> +	.mul_mask = 0x7FF,
> +};
> +
> +static const struct clk_pll_layout at91sam9g45_pll_layout = {
> +	.pllr_mask = 0xFFFFFF,
> +	.mul_shift = 16,
> +	.mul_mask = 0xFF,
> +};
> +
> +static const struct clk_pll_layout at91sam9g20_pllb_layout = {
> +	.pllr_mask = 0x3FFFFF,
> +	.mul_shift = 16,
> +	.mul_mask = 0x3F,
> +};
> +
> +static const struct clk_pll_layout sama5d3_pll_layout = {
> +	.pllr_mask = 0x1FFFFFF,
> +	.mul_shift = 18,
> +	.mul_mask = 0x7F,
> +};
> +
> +
> +static struct clk_pll_characteristics * __init
> +of_at91_clk_pll_get_characteristics(struct device_node *np)
> +{
> +	int i;
> +	int offset;
> +	u32 tmp;
> +	int num_output;
> +	u32 num_cells;
> +	struct clk_range input;
> +	struct clk_range *output;
> +	u8 *out = NULL;
> +	u16 *icpll = NULL;
> +	struct clk_pll_characteristics *characteristics;
> +
> +	if (of_property_read_u32_index(np, "atmel,clk-input-range", 0, &tmp))
> +		return NULL;
> +	input.min = tmp;
> +
> +	if (of_property_read_u32_index(np, "atmel,clk-input-range", 1, &tmp))
> +		return NULL;
> +	input.max = tmp;
> +
> +	if (of_property_read_u32(np, "#atmel,pll-clk-output-range-cells",
> +				 &num_cells))
> +		return NULL;
> +
> +	if (num_cells < 2 || num_cells > 4)
> +		return NULL;
> +
> +	if (!of_get_property(np, "atmel,pll-clk-output-ranges", &tmp))
> +		return NULL;
> +	num_output = tmp / (sizeof(u32) * num_cells);
> +
> +	characteristics = kzalloc(sizeof(*characteristics), GFP_KERNEL);
> +	if (!characteristics)
> +		return NULL;
> +
> +	output = kzalloc(sizeof(*output) * num_output, GFP_KERNEL);
> +	if (!output)
> +		goto out_free_characteristics;
> +
> +	if (num_cells > 2) {
> +		out = kzalloc(sizeof(*out) * num_output, GFP_KERNEL);
> +		if (!out)
> +			goto out_free_output;
> +	}
> +
> +	if (num_cells > 3) {
> +		icpll = kzalloc(sizeof(*icpll) * num_output, GFP_KERNEL);
> +		if (!icpll)
> +			goto out_free_output;
> +	}
> +
> +	for (i = 0; i < num_output; i++) {
> +		offset = i * num_cells;
> +		if (of_property_read_u32_index(np,
> +					       "atmel,pll-clk-output-ranges",
> +					       offset, &tmp))
> +			goto out_free_output;
> +		output[i].min = tmp;
> +		if (of_property_read_u32_index(np,
> +					       "atmel,pll-clk-output-ranges",
> +					       offset + 1, &tmp))
> +			goto out_free_output;
> +		output[i].max = tmp;
> +
> +		if (num_cells == 2)
> +			continue;
> +
> +		if (of_property_read_u32_index(np,
> +					       "atmel,pll-clk-output-ranges",
> +					       offset + 2, &tmp))
> +			goto out_free_output;
> +		out[i] = tmp;
> +
> +		if (num_cells == 3)
> +			continue;
> +
> +		if (of_property_read_u32_index(np,
> +					       "atmel,pll-clk-output-ranges",
> +					       offset + 3, &tmp))
> +			goto out_free_output;
> +		icpll[i] = tmp;
> +	}
> +
> +	characteristics->input = input;
> +	characteristics->num_output = num_output;
> +	characteristics->output = output;
> +	characteristics->out = out;
> +	characteristics->icpll = icpll;
> +	return characteristics;
> +
> +out_free_output:
> +	kfree(icpll);
> +	kfree(out);
> +	kfree(output);
> +out_free_characteristics:
> +	kfree(characteristics);
> +	return NULL;
> +}
> +
> +static void __init
> +of_at91_clk_pll_setup(struct device_node *np, struct at91_pmc *pmc,
> +		      const struct clk_pll_layout *layout)
> +{
> +	u32 id;
> +	unsigned int irq;
> +	struct clk *clk;
> +	const char *parent_name;
> +	const char *name = np->name;
> +	struct clk_pll_characteristics *characteristics;
> +
> +	if (of_property_read_u32(np, "atmel,clk-id", &id))
> +		return;
> +
> +	parent_name = of_clk_get_parent_name(np, 0);
> +
> +	of_property_read_string(np, "clock-output-names", &name);
> +
> +	characteristics = of_at91_clk_pll_get_characteristics(np);
> +	if (!characteristics)
> +		return;
> +
> +	irq = irq_of_parse_and_map(np, 0);
> +	if (!irq)
> +		return;
> +
> +	clk = at91_clk_register_pll(pmc, irq, name, parent_name, id, layout,
> +				    characteristics);
> +

No extra white line

> +	if (IS_ERR(clk))
> +		goto out_free_characteristics;
> +
> +	of_clk_add_provider(np, of_clk_src_simple_get, clk);
> +	return;
> +
> +out_free_characteristics:
> +	kfree(characteristics);
> +}
> +
> +void __init of_at91rm9200_clk_pll_setup(struct device_node *np,
> +					       struct at91_pmc *pmc)
> +{
> +	of_at91_clk_pll_setup(np, pmc, &at91rm9200_pll_layout);
> +}
> +
> +void __init of_at91sam9g45_clk_pll_setup(struct device_node *np,
> +						struct at91_pmc *pmc)
> +{
> +	of_at91_clk_pll_setup(np, pmc, &at91sam9g45_pll_layout);
> +}
> +
> +void __init of_at91sam9g20_clk_pllb_setup(struct device_node *np,
> +						 struct at91_pmc *pmc)
> +{
> +	of_at91_clk_pll_setup(np, pmc, &at91sam9g20_pllb_layout);
> +}
> +
> +void __init of_sama5d3_clk_pll_setup(struct device_node *np,
> +					    struct at91_pmc *pmc)
> +{
> +	of_at91_clk_pll_setup(np, pmc, &sama5d3_pll_layout);
> +}
> diff --git a/drivers/clk/at91/clk-plldiv.c b/drivers/clk/at91/clk-plldiv.c
> new file mode 100644
> index 0000000..2bbb22b
> --- /dev/null
> +++ b/drivers/clk/at91/clk-plldiv.c
> @@ -0,0 +1,137 @@
> +/*
> + * drivers/clk/at91/clk-plldiv.c
> + *
> + *  Copyright (C) 2013 Boris BREZILLON <b.brezillon@overkiz.com>
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License as published by
> + * the Free Software Foundation; either version 2 of the License, or
> + * (at your option) any later version.
> + *
> + */
> +
> +#include <linux/clk-provider.h>
> +#include <linux/clkdev.h>
> +#include <linux/clk/at91_pmc.h>
> +#include <linux/of.h>
> +#include <linux/of_address.h>
> +#include <linux/io.h>
> +
> +#include "pmc.h"
> +
> +#define to_clk_plldiv(hw) container_of(hw, struct clk_plldiv, hw)
> +
> +struct clk_plldiv {
> +	struct clk_hw hw;
> +	struct at91_pmc *pmc;
> +};
> +
> +static unsigned long clk_plldiv_recalc_rate(struct clk_hw *hw,
> +					    unsigned long parent_rate)
> +{
> +	struct clk_plldiv *plldiv = to_clk_plldiv(hw);
> +	struct at91_pmc *pmc = plldiv->pmc;
> +
> +	if (pmc_read(pmc, AT91_PMC_MCKR) & AT91_PMC_PLLADIV2)
> +		return parent_rate / 2;
> +
> +	return parent_rate;
> +}
> +
> +static long clk_plldiv_round_rate(struct clk_hw *hw, unsigned long rate,
> +					unsigned long *parent_rate)
> +{
> +	unsigned long div;
> +
> +	if (rate > *parent_rate)
> +		return *parent_rate;
> +	div = *parent_rate / 2;
> +	if (rate < div)
> +		return div;
> +
> +	if (rate - div < *parent_rate - rate)
> +		return div;
> +
> +	return *parent_rate;
> +}
> +
> +static int clk_plldiv_set_rate(struct clk_hw *hw, unsigned long rate,
> +			       unsigned long parent_rate)
> +{
> +	struct clk_plldiv *plldiv = to_clk_plldiv(hw);
> +	struct at91_pmc *pmc = plldiv->pmc;
> +	u32 tmp;
> +
> +	if (parent_rate != rate && (parent_rate / 2) != rate)
> +		return -EINVAL;
> +
> +	pmc_lock(pmc);
> +	tmp = pmc_read(pmc, AT91_PMC_MCKR) & ~AT91_PMC_PLLADIV2;
> +	if ((parent_rate / 2) == rate)
> +		tmp |= AT91_PMC_PLLADIV2;
> +	pmc_write(pmc, AT91_PMC_MCKR, tmp);
> +	pmc_unlock(pmc);
> +
> +	return 0;
> +}
> +
> +static const struct clk_ops plldiv_ops = {
> +	.recalc_rate = clk_plldiv_recalc_rate,
> +	.round_rate = clk_plldiv_round_rate,
> +	.set_rate = clk_plldiv_set_rate,
> +};
> +
> +static struct clk * __init
> +at91_clk_register_plldiv(struct at91_pmc *pmc, const char *name,
> +			 const char *parent_name)
> +{
> +	struct clk_plldiv *plldiv;
> +	struct clk *clk = NULL;
> +	struct clk_init_data init;
> +
> +	plldiv = kzalloc(sizeof(*plldiv), GFP_KERNEL);
> +	if (!plldiv)
> +		return ERR_PTR(-ENOMEM);
> +
> +	init.name = name;
> +	init.ops = &plldiv_ops;
> +	init.parent_names = parent_name ? &parent_name : NULL;
> +	init.num_parents = parent_name ? 1 : 0;
> +	init.flags = CLK_SET_RATE_GATE;
> +
> +	plldiv->hw.init = &init;
> +	plldiv->pmc = pmc;
> +
> +	clk = clk_register(NULL, &plldiv->hw);
> +
> +	if (IS_ERR(clk))
> +		kfree(plldiv);
> +
> +	return clk;
> +}
> +
> +static void __init
> +of_at91_clk_plldiv_setup(struct device_node *np, struct at91_pmc *pmc)
> +{
> +	struct clk *clk;
> +	const char *parent_name;
> +	const char *name = np->name;
> +
> +	parent_name = of_clk_get_parent_name(np, 0);
> +
> +	of_property_read_string(np, "clock-output-names", &name);
> +
> +	clk = at91_clk_register_plldiv(pmc, name, parent_name);
> +
> +	if (IS_ERR(clk))
> +		return;
> +
> +	of_clk_add_provider(np, of_clk_src_simple_get, clk);
> +	return;
> +}
> +
> +void __init of_at91sam9x5_clk_plldiv_setup(struct device_node *np,
> +					   struct at91_pmc *pmc)
> +{
> +	of_at91_clk_plldiv_setup(np, pmc);
> +}
> diff --git a/drivers/clk/at91/pmc.c b/drivers/clk/at91/pmc.c
> index 42f0c19..47aff40 100644
> --- a/drivers/clk/at91/pmc.c
> +++ b/drivers/clk/at91/pmc.c
> @@ -221,6 +221,27 @@ static const struct of_device_id pmc_clk_ids[] __initdata = {
>   		.compatible = "atmel,at91rm9200-clk-main",
>   		.data = of_at91rm9200_clk_main_setup
>   	},
> +	/* PLL clocks */
> +	{
> +		.compatible = "atmel,at91rm9200-clk-pll",
> +		.data = of_at91rm9200_clk_pll_setup,
> +	},
> +	{
> +		.compatible = "atmel,at91sam9g45-clk-pll",
> +		.data = of_at91sam9g45_clk_pll_setup,
> +	},
> +	{
> +		.compatible = "atmel,at91sam9g20-clk-pllb",
> +		.data = of_at91sam9g20_clk_pllb_setup,
> +	},
> +	{
> +		.compatible = "atmel,sama5d3-clk-pll",
> +		.data = of_sama5d3_clk_pll_setup,
> +	},
> +	{
> +		.compatible = "atmel,at91sam9x5-clk-plldiv",
> +		.data = of_at91sam9x5_clk_plldiv_setup,
> +	},
>   	{ /*sentinel*/ }
>   };
>
> diff --git a/drivers/clk/at91/pmc.h b/drivers/clk/at91/pmc.h
> index 294e230..35ccbbc 100644
> --- a/drivers/clk/at91/pmc.h
> +++ b/drivers/clk/at91/pmc.h
> @@ -58,4 +58,15 @@ static inline void pmc_write(struct at91_pmc *pmc, int offset, u32 value)
>   extern void __init of_at91rm9200_clk_main_setup(struct device_node *np,
>   						struct at91_pmc *pmc);
>
> +extern void __init of_at91rm9200_clk_pll_setup(struct device_node *np,
> +					       struct at91_pmc *pmc);
> +extern void __init of_at91sam9g45_clk_pll_setup(struct device_node *np,
> +						struct at91_pmc *pmc);
> +extern void __init of_at91sam9g20_clk_pllb_setup(struct device_node *np,
> +						 struct at91_pmc *pmc);
> +extern void __init of_sama5d3_clk_pll_setup(struct device_node *np,
> +					    struct at91_pmc *pmc);
> +extern void __init of_at91sam9x5_clk_plldiv_setup(struct device_node *np,
> +						  struct at91_pmc *pmc);
> +
>   #endif /* __PMC_H_ */
> diff --git a/include/linux/clk/at91_pmc.h b/include/linux/clk/at91_pmc.h
> index 00c45b3..a6911eb 100644
> --- a/include/linux/clk/at91_pmc.h
> +++ b/include/linux/clk/at91_pmc.h
> @@ -164,6 +164,8 @@ extern void __iomem *at91_pmc_base;
>   #define		AT91_PMC_CFDEV		(1 << 18)		/* Clock Failure Detector Event [some SAM9] */
>   #define	AT91_PMC_IMR		0x6c			/* Interrupt Mask Register */
>
> +#define AT91_PMC_PLLICPR	0x80			/* PLL Charge Pump Current Register */
> +
>   #define AT91_PMC_PROT		0xe4			/* Write Protect Mode Register [some SAM9] */
>   #define		AT91_PMC_WPEN		(0x1  <<  0)		/* Write Protect Enable */
>   #define		AT91_PMC_WPKEY		(0xffffff << 8)		/* Write Protect Key */
>


-- 
Nicolas Ferre

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

* Re: [PATCH v3 07/19] clk: at91: add pll id macros for pll dt bindings
  2013-08-08  6:09 ` [PATCH v3 07/19] clk: at91: add pll id macros for pll dt bindings Boris BREZILLON
@ 2013-10-08 10:30   ` Nicolas Ferre
  2013-10-08 12:03     ` boris brezillon
  0 siblings, 1 reply; 54+ messages in thread
From: Nicolas Ferre @ 2013-10-08 10:30 UTC (permalink / raw)
  To: Boris BREZILLON, Grant Likely, Rob Herring, Rob Landley,
	Andrew Victor, Jean-Christophe Plagniol-Villard, Russell King,
	Mike Turquette, Felipe Balbi, Greg Kroah-Hartman,
	Ludovic Desroches, Josh Wu, Richard Genoud
  Cc: devicetree, linux-kernel, linux-arm-kernel

On 08/08/2013 08:09, Boris BREZILLON :
> This patch adds the PLL id macros which will be used by pll dt definitions.

It is not needed, drop it. Just document the values in the DT biding and 
it will be fine.

>
> Signed-off-by: Boris BREZILLON <b.brezillon@overkiz.com>
> ---
>   include/dt-bindings/clk/at91/common/clk-pll.h |   13 +++++++++++++
>   1 file changed, 13 insertions(+)
>   create mode 100644 include/dt-bindings/clk/at91/common/clk-pll.h
>
> diff --git a/include/dt-bindings/clk/at91/common/clk-pll.h b/include/dt-bindings/clk/at91/common/clk-pll.h
> new file mode 100644
> index 0000000..93ec849
> --- /dev/null
> +++ b/include/dt-bindings/clk/at91/common/clk-pll.h
> @@ -0,0 +1,13 @@
> +/*
> + * This header provides constants for AT91 pll ids.
> + *
> + * The constants defined in this header are being used in dts.
> + */
> +
> +#ifndef _DT_BINDINGS_CLK_AT91_PLL_H
> +#define _DT_BINDINGS_CLK_AT91_PLL_H
> +
> +#define AT91_PLLA_CLK		0	/* PLLA clk id */
> +#define AT91_PLLB_CLK		1	/* PLLB clk id */
> +
> +#endif
>


-- 
Nicolas Ferre

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

* Re: [PATCH v3 06/19] clk: at91: add PMC pll clocks
  2013-10-08 10:28   ` Nicolas Ferre
@ 2013-10-08 11:45     ` boris brezillon
  0 siblings, 0 replies; 54+ messages in thread
From: boris brezillon @ 2013-10-08 11:45 UTC (permalink / raw)
  To: Nicolas Ferre, Grant Likely, Rob Herring, Rob Landley,
	Andrew Victor, Jean-Christophe Plagniol-Villard, Russell King,
	Mike Turquette, Felipe Balbi, Greg Kroah-Hartman,
	Ludovic Desroches, Josh Wu, Richard Genoud
  Cc: devicetree, linux-kernel, linux-arm-kernel

On 08/10/2013 12:28, Nicolas Ferre wrote:
> On 08/08/2013 08:07, Boris BREZILLON :
>> This patch adds new at91 pll clock implementation using common clk 
>> framework.
>>
>> The pll clock layout describe the PLLX register layout.
>> There are four pll clock layouts:
>> - at91rm9200
>> - at91sam9g20
>> - at91sam9g45
>> - sama5d3
>>
>> PLL clocks are given characteristics:
>> - min/max clock source rate
>> - ranges of valid clock output rates
>> - values to set in out and icpll fields for each supported output range
>>
>> These characteristics are checked during rate change to avoid
>> over/underclocking.
>>
>> These characteristics are described in atmel's SoC datasheet in
>> "Electrical Characteristics" paragraph.
>>
>> Signed-off-by: Boris BREZILLON <b.brezillon@overkiz.com>
>> ---
>>   drivers/clk/at91/Makefile     |    2 +-
>>   drivers/clk/at91/clk-pll.c    |  506 
>> +++++++++++++++++++++++++++++++++++++++++
>>   drivers/clk/at91/clk-plldiv.c |  137 +++++++++++
>>   drivers/clk/at91/pmc.c        |   21 ++
>>   drivers/clk/at91/pmc.h        |   11 +
>>   include/linux/clk/at91_pmc.h  |    2 +
>>   6 files changed, 678 insertions(+), 1 deletion(-)
>>   create mode 100644 drivers/clk/at91/clk-pll.c
>>   create mode 100644 drivers/clk/at91/clk-plldiv.c
>>
>> diff --git a/drivers/clk/at91/Makefile b/drivers/clk/at91/Makefile
>> index 44105bd..902bbf1 100644
>> --- a/drivers/clk/at91/Makefile
>> +++ b/drivers/clk/at91/Makefile
>> @@ -3,4 +3,4 @@
>>   #
>>
>>   obj-y += pmc.o
>> -obj-y += clk-main.o
>> +obj-y += clk-main.o clk-pll.o clk-plldiv.o
>> diff --git a/drivers/clk/at91/clk-pll.c b/drivers/clk/at91/clk-pll.c
>> new file mode 100644
>> index 0000000..ce519f2
>> --- /dev/null
>> +++ b/drivers/clk/at91/clk-pll.c
>> @@ -0,0 +1,506 @@
>> +/*
>> + * drivers/clk/at91/clk-pll.c
>> + *
>> + *  Copyright (C) 2013 Boris BREZILLON <b.brezillon@overkiz.com>
>> + *
>> + * This program is free software; you can redistribute it and/or modify
>> + * it under the terms of the GNU General Public License as published by
>> + * the Free Software Foundation; either version 2 of the License, or
>> + * (at your option) any later version.
>> + *
>> + */
>> +
>> +#include <linux/clk-provider.h>
>> +#include <linux/clkdev.h>
>> +#include <linux/clk/at91_pmc.h>
>> +#include <linux/of.h>
>> +#include <linux/of_address.h>
>> +#include <linux/of_irq.h>
>> +#include <linux/io.h>
>> +#include <linux/wait.h>
>> +#include <linux/sched.h>
>> +#include <linux/interrupt.h>
>> +#include <linux/irq.h>
>> +
>> +#include "pmc.h"
>> +
>> +struct clk_pll_characteristics {
>> +    struct clk_range input;
>> +    int num_output;
>> +    struct clk_range *output;
>> +    u16 *icpll;
>> +    u8 *out;
>> +};
>> +
>> +struct clk_pll_layout {
>> +    u32 pllr_mask;
>> +    u16 mul_mask;
>> +    u8 mul_shift;
>> +};
>> +
>> +#define to_clk_pll(hw) container_of(hw, struct clk_pll, hw)
>> +
>> +struct clk_pll {
>> +    struct clk_hw hw;
>> +    struct at91_pmc *pmc;
>> +    unsigned int irq;
>> +    wait_queue_head_t wait;
>> +    u8 id;
>> +    u8 div;
>> +    u8 range;
>> +    u16 mul;
>> +    const struct clk_pll_layout *layout;
>> +    const struct clk_pll_characteristics *characteristics;
>> +};
>> +
>> +static irqreturn_t clk_pll_irq_handler(int irq, void *dev_id)
>> +{
>> +    struct clk_pll *pll = (struct clk_pll *)dev_id;
>> +
>> +    wake_up(&pll->wait);
>> +    disable_irq_nosync(pll->irq);
>> +
>> +    return IRQ_HANDLED;
>> +}
>> +
>> +static int clk_pll_prepare(struct clk_hw *hw)
>> +{
>> +    struct clk_pll *pll = to_clk_pll(hw);
>> +    struct at91_pmc *pmc = pll->pmc;
>> +
>> +    while (!(pmc_read(pmc, AT91_PMC_SR) & (1 << (1 + pll->id)))) {
>
> Here, we can define a macro for this driver that can take pll->id and 
> give back the mask: it seems to be used frequently in the driver).

Sure, I will define macros and use them appropriately.

>
>> +        enable_irq(pll->irq);
>> +        wait_event(pll->wait,
>> +               pmc_read(pmc, AT91_PMC_SR) & (1 << (1 + pll->id)));
>> +    }
>> +
>> +    return 0;
>> +}
>> +
>> +static int clk_pll_is_ready(struct clk_hw *hw)
>> +{
>> +    struct clk_pll *pll = to_clk_pll(hw);
>> +    struct at91_pmc *pmc = pll->pmc;
>> +
>> +    return !!(pmc_read(pmc, AT91_PMC_SR) &
>> +          (1 << (1 + pll->id)));
>> +}
>> +
>> +static void clk_pll_disable(struct clk_hw *hw)
>> +{
>> +    struct clk_pll *pll = to_clk_pll(hw);
>> +    struct at91_pmc *pmc = pll->pmc;
>> +    const struct clk_pll_layout *layout = pll->layout;
>> +    int offset = AT91_CKGR_PLLAR + (pll->id * 4);
>
> Here also, a macro can be interesting to retrieve the PLL register 
> address.
>
>> +    u32 tmp = pmc_read(pmc, offset) & ~(layout->pllr_mask);
>
> Well why not just setting MULA/B to 0? I know it is nearly the same 
> but on sama5d3, there is a field that must always be set to 1 (bit 29).

This was here to handle sama5 (and maybe other SoCs I don't recall) 
specific case.
This way (by reading the PLLR register and masking it with ~pllr_mask) 
the bit that must be set 1 is always set correctly.

How would you do it (handle sama5 specific behaviour) ?

>
>
>> +
>> +    pmc_write(pmc, offset, tmp);
>> +}
>> +
>> +static unsigned long clk_pll_recalc_rate(struct clk_hw *hw,
>> +                     unsigned long parent_rate)
>> +{
>> +    struct clk_pll *pll = to_clk_pll(hw);
>> +    const struct clk_pll_layout *layout = pll->layout;
>> +    struct at91_pmc *pmc = pll->pmc;
>> +    int offset = AT91_CKGR_PLLAR + (pll->id * 4);
>
> Ditto
>
>> +    u32 tmp = pmc_read(pmc, offset) & layout->pllr_mask;
>> +    u8 div = tmp & 0xFF;
>
> A #defined value, please
>
>> +    u16 mul = (tmp >> layout->mul_shift) & layout->mul_mask;
>> +    if (!div || !mul)
>> +        return 0;
>> +
>> +    return (parent_rate * (mul + 1)) / div;
>> +}
>> +
>> +static long clk_pll_get_best_div_mul(struct clk_pll *pll, unsigned 
>> long rate,
>> +                     unsigned long parent_rate,
>> +                     u32 *div, u32 *mul,
>> +                     u32 *index) {
>> +    unsigned long maxrate;
>> +    unsigned long minrate;
>> +    unsigned long divrate;
>> +    unsigned long bestdiv = 1;
>> +    unsigned long bestmul;
>> +    unsigned long tmpdiv;
>> +    unsigned long roundup;
>> +    unsigned long rounddown;
>> +    unsigned long remainder;
>> +    unsigned long bestremainder;
>> +    unsigned long maxmul;
>> +    unsigned long maxdiv;
>> +    unsigned long mindiv;
>> +    int i = 0;
>> +    const struct clk_pll_layout *layout = pll->layout;
>> +    const struct clk_pll_characteristics *characteristics =
>> +                            pll->characteristics;
>> +
>> +    /* Minimum divider = 1 */
>> +    /* Maximum multiplier = max_mul */
>> +    maxmul = layout->mul_mask + 1;
>> +    maxrate = (parent_rate * maxmul) / 1;
>> +
>> +    /* Maximum divider = max_div */
>> +    /* Minimum multiplier = 2 */
>> +    maxdiv = 0xFF;
>
> Same defined value as above
>
>> +    minrate = (parent_rate * 2) / maxdiv;
>> +
>> +    if (parent_rate < characteristics->input.min ||
>> +        parent_rate < characteristics->input.max)
>> +        return -ERANGE;
>> +
>> +    if (parent_rate < minrate || parent_rate > maxrate)
>> +        return -ERANGE;
>> +
>> +    for (i = 0; i < characteristics->num_output; ++i) {
>> +        if (parent_rate >= characteristics->output[i].min &&
>> +            parent_rate <= characteristics->output[i].max)
>> +            break;
>> +        ++i;
>
> another iteration of "i" in the loop? If it is required, consider 
> using the for() loop with i += 2...

This is not required: this is a bug. I'll fix it.
>
>> +    }
>> +
>> +    if (i >= characteristics->num_output)
>> +        return -ERANGE;
>> +
>> +    bestmul = rate / parent_rate;
>> +    rounddown = parent_rate % rate;
>> +    roundup = rate - rounddown;
>> +    bestremainder = roundup < rounddown ? roundup : rounddown;
>> +
>> +    if (!bestremainder) {
>> +        if (div)
>> +            *div = bestdiv;
>> +        if (mul)
>> +            *mul = bestmul;
>> +        if (index)
>> +            *index = i;
>> +        return rate;
>> +    }
>> +
>> +    maxdiv = 255 / (bestmul + 1);
>> +    if (parent_rate / maxdiv < characteristics->input.min)
>> +        maxdiv = parent_rate / characteristics->input.min;
>> +    mindiv = parent_rate / characteristics->input.max;
>> +    if (parent_rate % characteristics->input.max)
>> +        mindiv++;
>> +
>> +    for (tmpdiv = mindiv; tmpdiv < maxdiv; tmpdiv++) {
>> +        divrate = parent_rate / tmpdiv;
>> +
>> +        rounddown = rate % divrate;
>> +        roundup = divrate - rounddown;
>> +        remainder = roundup < rounddown ? roundup : rounddown;
>> +
>> +        if (remainder < bestremainder) {
>> +            bestremainder = remainder;
>> +            bestmul = rate / divrate;
>> +            bestdiv = tmpdiv;
>> +        }
>> +
>> +        if (!remainder)
>> +            break;
>> +    }
>> +
>> +    rate = (parent_rate / bestdiv) * bestmul;
>> +
>> +    if (div)
>> +        *div = bestdiv;
>> +    if (mul)
>> +        *mul = bestmul;
>> +    if (index)
>> +        *index = i;
>> +
>> +    return rate;
>> +}
>> +
>> +static long clk_pll_round_rate(struct clk_hw *hw, unsigned long rate,
>> +                    unsigned long *parent_rate)
>> +{
>> +    struct clk_pll *pll = to_clk_pll(hw);
>> +
>> +    return clk_pll_get_best_div_mul(pll, rate, *parent_rate,
>> +                    NULL, NULL, NULL);
>> +
>> +}
>> +
>> +static int clk_pll_set_rate(struct clk_hw *hw, unsigned long rate,
>> +                unsigned long parent_rate)
>> +{
>> +    struct clk_pll *pll = to_clk_pll(hw);
>> +    struct at91_pmc *pmc = pll->pmc;
>> +    const struct clk_pll_layout *layout = pll->layout;
>> +    const struct clk_pll_characteristics *characteristics =
>> +                        pll->characteristics;
>> +    int offset = AT91_CKGR_PLLAR + (pll->id * 4);
>
> Ditto
>
>> +    long ret;
>> +    u32 div;
>> +    u32 mul;
>> +    u32 index;
>> +    u32 tmp;
>> +    u8 out = 0;
>> +
>> +    ret = clk_pll_get_best_div_mul(pll, rate, parent_rate,
>> +                       &div, &mul, &index);
>> +    if (ret < 0)
>> +        return ret;
>> +
>> +    if (characteristics->out)
>> +        out = characteristics->out[pll->range];
>> +    if (characteristics->icpll) {
>> +        tmp = pmc_read(pmc, AT91_PMC_PLLICPR) &
>> +              ~(0xFFFF << (16 * pll->id));
>
> Macros and defined values, please
>
>> +        tmp |= characteristics->icpll[pll->range] << (16 * pll->id);
>
> Here also
>
>> +        pmc_write(pmc, AT91_PMC_PLLICPR, tmp);
>> +    }
>> +    tmp = pmc_read(pmc, offset) & ~(layout->pllr_mask);
>> +    tmp |= layout->pllr_mask & (div | 0x3F << 8 | out << 14 |
>> +                    (mul & layout->mul_mask) <<
>> +                    layout->mul_shift);
>
> Here also
>
>> +    pmc_write(pmc, offset, tmp);

I realize there is a bug here:
  - pll->div and ->mul are never set
  - we should not write the new conf to the PLLR/ICPPL registers (this 
should be done in clk_prepare)

I'll fix it.

>> +
>> +    return 0;
>> +}
>> +
>> +static const struct clk_ops pll_ops = {
>> +    .prepare = clk_pll_prepare,
>> +    .is_prepared = clk_pll_is_ready,
>> +    .disable = clk_pll_disable,
>> +    .is_enabled = clk_pll_is_ready,
>> +    .recalc_rate = clk_pll_recalc_rate,
>> +    .round_rate = clk_pll_round_rate,
>> +    .set_rate = clk_pll_set_rate,
>> +};
>> +
>> +static struct clk * __init
>> +at91_clk_register_pll(struct at91_pmc *pmc, unsigned int irq, const 
>> char *name,
>> +              const char *parent_name, u8 id,
>> +              const struct clk_pll_layout *layout,
>> +              const struct clk_pll_characteristics *characteristics)
>> +{
>> +    struct clk_pll *pll;
>> +    struct clk *clk = NULL;
>> +    struct clk_init_data init;
>> +    int ret;
>> +
>> +    id &= 3;
>
> defined value please
>
>> +
>> +    pll = kzalloc(sizeof(*pll), GFP_KERNEL);
>> +    if (!pll)
>> +        return ERR_PTR(-ENOMEM);
>> +
>> +    init.name = name;
>> +    init.ops = &pll_ops;
>> +    init.parent_names = &parent_name;
>> +    init.num_parents = 1;
>> +    init.flags = CLK_SET_RATE_GATE;
>> +
>> +    pll->id = id;
>> +    pll->hw.init = &init;
>> +    pll->layout = layout;
>> +    pll->characteristics = characteristics;
>> +    pll->pmc = pmc;
>> +    pll->irq = irq;
>> +    init_waitqueue_head(&pll->wait);
>> +    irq_set_status_flags(pll->irq, IRQ_NOAUTOEN);
>> +    ret = request_irq(pll->irq, clk_pll_irq_handler, IRQF_TRIGGER_HIGH,
>> +              id ? "clk-pllb" : "clk-plla", pll);
>> +    if (ret)
>> +        return ERR_PTR(ret);
>> +
>> +    clk = clk_register(NULL, &pll->hw);
>> +
>
> No extra space
I'll remove all unneeded spaces and/or blank lines.
>
>> +    if (IS_ERR(clk))
>> +        kfree(pll);
>> +
>> +    return clk;
>> +}
>> +
>> +
>> +static const struct clk_pll_layout at91rm9200_pll_layout = {
>> +    .pllr_mask = 0x7FFFFFF,
>> +    .mul_shift = 16,
>> +    .mul_mask = 0x7FF,
>> +};
>> +
>> +static const struct clk_pll_layout at91sam9g45_pll_layout = {
>> +    .pllr_mask = 0xFFFFFF,
>> +    .mul_shift = 16,
>> +    .mul_mask = 0xFF,
>> +};
>> +
>> +static const struct clk_pll_layout at91sam9g20_pllb_layout = {
>> +    .pllr_mask = 0x3FFFFF,
>> +    .mul_shift = 16,
>> +    .mul_mask = 0x3F,
>> +};
>> +
>> +static const struct clk_pll_layout sama5d3_pll_layout = {
>> +    .pllr_mask = 0x1FFFFFF,
>> +    .mul_shift = 18,
>> +    .mul_mask = 0x7F,
>> +};
>> +
>> +
>> +static struct clk_pll_characteristics * __init
>> +of_at91_clk_pll_get_characteristics(struct device_node *np)
>> +{
>> +    int i;
>> +    int offset;
>> +    u32 tmp;
>> +    int num_output;
>> +    u32 num_cells;
>> +    struct clk_range input;
>> +    struct clk_range *output;
>> +    u8 *out = NULL;
>> +    u16 *icpll = NULL;
>> +    struct clk_pll_characteristics *characteristics;
>> +
>> +    if (of_property_read_u32_index(np, "atmel,clk-input-range", 0, 
>> &tmp))
>> +        return NULL;
>> +    input.min = tmp;
>> +
>> +    if (of_property_read_u32_index(np, "atmel,clk-input-range", 1, 
>> &tmp))
>> +        return NULL;
>> +    input.max = tmp;
>> +
>> +    if (of_property_read_u32(np, "#atmel,pll-clk-output-range-cells",
>> +                 &num_cells))
>> +        return NULL;
>> +
>> +    if (num_cells < 2 || num_cells > 4)
>> +        return NULL;
>> +
>> +    if (!of_get_property(np, "atmel,pll-clk-output-ranges", &tmp))
>> +        return NULL;
>> +    num_output = tmp / (sizeof(u32) * num_cells);
>> +
>> +    characteristics = kzalloc(sizeof(*characteristics), GFP_KERNEL);
>> +    if (!characteristics)
>> +        return NULL;
>> +
>> +    output = kzalloc(sizeof(*output) * num_output, GFP_KERNEL);
>> +    if (!output)
>> +        goto out_free_characteristics;
>> +
>> +    if (num_cells > 2) {
>> +        out = kzalloc(sizeof(*out) * num_output, GFP_KERNEL);
>> +        if (!out)
>> +            goto out_free_output;
>> +    }
>> +
>> +    if (num_cells > 3) {
>> +        icpll = kzalloc(sizeof(*icpll) * num_output, GFP_KERNEL);
>> +        if (!icpll)
>> +            goto out_free_output;
>> +    }
>> +
>> +    for (i = 0; i < num_output; i++) {
>> +        offset = i * num_cells;
>> +        if (of_property_read_u32_index(np,
>> +                           "atmel,pll-clk-output-ranges",
>> +                           offset, &tmp))
>> +            goto out_free_output;
>> +        output[i].min = tmp;
>> +        if (of_property_read_u32_index(np,
>> +                           "atmel,pll-clk-output-ranges",
>> +                           offset + 1, &tmp))
>> +            goto out_free_output;
>> +        output[i].max = tmp;
>> +
>> +        if (num_cells == 2)
>> +            continue;
>> +
>> +        if (of_property_read_u32_index(np,
>> +                           "atmel,pll-clk-output-ranges",
>> +                           offset + 2, &tmp))
>> +            goto out_free_output;
>> +        out[i] = tmp;
>> +
>> +        if (num_cells == 3)
>> +            continue;
>> +
>> +        if (of_property_read_u32_index(np,
>> +                           "atmel,pll-clk-output-ranges",
>> +                           offset + 3, &tmp))
>> +            goto out_free_output;
>> +        icpll[i] = tmp;
>> +    }
>> +
>> +    characteristics->input = input;
>> +    characteristics->num_output = num_output;
>> +    characteristics->output = output;
>> +    characteristics->out = out;
>> +    characteristics->icpll = icpll;
>> +    return characteristics;
>> +
>> +out_free_output:
>> +    kfree(icpll);
>> +    kfree(out);
>> +    kfree(output);
>> +out_free_characteristics:
>> +    kfree(characteristics);
>> +    return NULL;
>> +}
>> +
>> +static void __init
>> +of_at91_clk_pll_setup(struct device_node *np, struct at91_pmc *pmc,
>> +              const struct clk_pll_layout *layout)
>> +{
>> +    u32 id;
>> +    unsigned int irq;
>> +    struct clk *clk;
>> +    const char *parent_name;
>> +    const char *name = np->name;
>> +    struct clk_pll_characteristics *characteristics;
>> +
>> +    if (of_property_read_u32(np, "atmel,clk-id", &id))
>> +        return;
>> +
>> +    parent_name = of_clk_get_parent_name(np, 0);
>> +
>> +    of_property_read_string(np, "clock-output-names", &name);
>> +
>> +    characteristics = of_at91_clk_pll_get_characteristics(np);
>> +    if (!characteristics)
>> +        return;
>> +
>> +    irq = irq_of_parse_and_map(np, 0);
>> +    if (!irq)
>> +        return;
>> +
>> +    clk = at91_clk_register_pll(pmc, irq, name, parent_name, id, 
>> layout,
>> +                    characteristics);
>> +
>
> No extra white line
>
>> +    if (IS_ERR(clk))
>> +        goto out_free_characteristics;
>> +
>> +    of_clk_add_provider(np, of_clk_src_simple_get, clk);
>> +    return;
>> +
>> +out_free_characteristics:
>> +    kfree(characteristics);
>> +}
>> +
>> +void __init of_at91rm9200_clk_pll_setup(struct device_node *np,
>> +                           struct at91_pmc *pmc)
>> +{
>> +    of_at91_clk_pll_setup(np, pmc, &at91rm9200_pll_layout);
>> +}
>> +
>> +void __init of_at91sam9g45_clk_pll_setup(struct device_node *np,
>> +                        struct at91_pmc *pmc)
>> +{
>> +    of_at91_clk_pll_setup(np, pmc, &at91sam9g45_pll_layout);
>> +}
>> +
>> +void __init of_at91sam9g20_clk_pllb_setup(struct device_node *np,
>> +                         struct at91_pmc *pmc)
>> +{
>> +    of_at91_clk_pll_setup(np, pmc, &at91sam9g20_pllb_layout);
>> +}
>> +
>> +void __init of_sama5d3_clk_pll_setup(struct device_node *np,
>> +                        struct at91_pmc *pmc)
>> +{
>> +    of_at91_clk_pll_setup(np, pmc, &sama5d3_pll_layout);
>> +}
>> diff --git a/drivers/clk/at91/clk-plldiv.c 
>> b/drivers/clk/at91/clk-plldiv.c
>> new file mode 100644
>> index 0000000..2bbb22b
>> --- /dev/null
>> +++ b/drivers/clk/at91/clk-plldiv.c
>> @@ -0,0 +1,137 @@
>> +/*
>> + * drivers/clk/at91/clk-plldiv.c
>> + *
>> + *  Copyright (C) 2013 Boris BREZILLON <b.brezillon@overkiz.com>
>> + *
>> + * This program is free software; you can redistribute it and/or modify
>> + * it under the terms of the GNU General Public License as published by
>> + * the Free Software Foundation; either version 2 of the License, or
>> + * (at your option) any later version.
>> + *
>> + */
>> +
>> +#include <linux/clk-provider.h>
>> +#include <linux/clkdev.h>
>> +#include <linux/clk/at91_pmc.h>
>> +#include <linux/of.h>
>> +#include <linux/of_address.h>
>> +#include <linux/io.h>
>> +
>> +#include "pmc.h"
>> +
>> +#define to_clk_plldiv(hw) container_of(hw, struct clk_plldiv, hw)
>> +
>> +struct clk_plldiv {
>> +    struct clk_hw hw;
>> +    struct at91_pmc *pmc;
>> +};
>> +
>> +static unsigned long clk_plldiv_recalc_rate(struct clk_hw *hw,
>> +                        unsigned long parent_rate)
>> +{
>> +    struct clk_plldiv *plldiv = to_clk_plldiv(hw);
>> +    struct at91_pmc *pmc = plldiv->pmc;
>> +
>> +    if (pmc_read(pmc, AT91_PMC_MCKR) & AT91_PMC_PLLADIV2)
>> +        return parent_rate / 2;
>> +
>> +    return parent_rate;
>> +}
>> +
>> +static long clk_plldiv_round_rate(struct clk_hw *hw, unsigned long 
>> rate,
>> +                    unsigned long *parent_rate)
>> +{
>> +    unsigned long div;
>> +
>> +    if (rate > *parent_rate)
>> +        return *parent_rate;
>> +    div = *parent_rate / 2;
>> +    if (rate < div)
>> +        return div;
>> +
>> +    if (rate - div < *parent_rate - rate)
>> +        return div;
>> +
>> +    return *parent_rate;
>> +}
>> +
>> +static int clk_plldiv_set_rate(struct clk_hw *hw, unsigned long rate,
>> +                   unsigned long parent_rate)
>> +{
>> +    struct clk_plldiv *plldiv = to_clk_plldiv(hw);
>> +    struct at91_pmc *pmc = plldiv->pmc;
>> +    u32 tmp;
>> +
>> +    if (parent_rate != rate && (parent_rate / 2) != rate)
>> +        return -EINVAL;
>> +
>> +    pmc_lock(pmc);
>> +    tmp = pmc_read(pmc, AT91_PMC_MCKR) & ~AT91_PMC_PLLADIV2;
>> +    if ((parent_rate / 2) == rate)
>> +        tmp |= AT91_PMC_PLLADIV2;
>> +    pmc_write(pmc, AT91_PMC_MCKR, tmp);
>> +    pmc_unlock(pmc);
>> +
>> +    return 0;
>> +}
>> +
>> +static const struct clk_ops plldiv_ops = {
>> +    .recalc_rate = clk_plldiv_recalc_rate,
>> +    .round_rate = clk_plldiv_round_rate,
>> +    .set_rate = clk_plldiv_set_rate,
>> +};
>> +
>> +static struct clk * __init
>> +at91_clk_register_plldiv(struct at91_pmc *pmc, const char *name,
>> +             const char *parent_name)
>> +{
>> +    struct clk_plldiv *plldiv;
>> +    struct clk *clk = NULL;
>> +    struct clk_init_data init;
>> +
>> +    plldiv = kzalloc(sizeof(*plldiv), GFP_KERNEL);
>> +    if (!plldiv)
>> +        return ERR_PTR(-ENOMEM);
>> +
>> +    init.name = name;
>> +    init.ops = &plldiv_ops;
>> +    init.parent_names = parent_name ? &parent_name : NULL;
>> +    init.num_parents = parent_name ? 1 : 0;
>> +    init.flags = CLK_SET_RATE_GATE;
>> +
>> +    plldiv->hw.init = &init;
>> +    plldiv->pmc = pmc;
>> +
>> +    clk = clk_register(NULL, &plldiv->hw);
>> +
>> +    if (IS_ERR(clk))
>> +        kfree(plldiv);
>> +
>> +    return clk;
>> +}
>> +
>> +static void __init
>> +of_at91_clk_plldiv_setup(struct device_node *np, struct at91_pmc *pmc)
>> +{
>> +    struct clk *clk;
>> +    const char *parent_name;
>> +    const char *name = np->name;
>> +
>> +    parent_name = of_clk_get_parent_name(np, 0);
>> +
>> +    of_property_read_string(np, "clock-output-names", &name);
>> +
>> +    clk = at91_clk_register_plldiv(pmc, name, parent_name);
>> +
>> +    if (IS_ERR(clk))
>> +        return;
>> +
>> +    of_clk_add_provider(np, of_clk_src_simple_get, clk);
>> +    return;
>> +}
>> +
>> +void __init of_at91sam9x5_clk_plldiv_setup(struct device_node *np,
>> +                       struct at91_pmc *pmc)
>> +{
>> +    of_at91_clk_plldiv_setup(np, pmc);
>> +}
>> diff --git a/drivers/clk/at91/pmc.c b/drivers/clk/at91/pmc.c
>> index 42f0c19..47aff40 100644
>> --- a/drivers/clk/at91/pmc.c
>> +++ b/drivers/clk/at91/pmc.c
>> @@ -221,6 +221,27 @@ static const struct of_device_id pmc_clk_ids[] 
>> __initdata = {
>>           .compatible = "atmel,at91rm9200-clk-main",
>>           .data = of_at91rm9200_clk_main_setup
>>       },
>> +    /* PLL clocks */
>> +    {
>> +        .compatible = "atmel,at91rm9200-clk-pll",
>> +        .data = of_at91rm9200_clk_pll_setup,
>> +    },
>> +    {
>> +        .compatible = "atmel,at91sam9g45-clk-pll",
>> +        .data = of_at91sam9g45_clk_pll_setup,
>> +    },
>> +    {
>> +        .compatible = "atmel,at91sam9g20-clk-pllb",
>> +        .data = of_at91sam9g20_clk_pllb_setup,
>> +    },
>> +    {
>> +        .compatible = "atmel,sama5d3-clk-pll",
>> +        .data = of_sama5d3_clk_pll_setup,
>> +    },
>> +    {
>> +        .compatible = "atmel,at91sam9x5-clk-plldiv",
>> +        .data = of_at91sam9x5_clk_plldiv_setup,
>> +    },
>>       { /*sentinel*/ }
>>   };
>>
>> diff --git a/drivers/clk/at91/pmc.h b/drivers/clk/at91/pmc.h
>> index 294e230..35ccbbc 100644
>> --- a/drivers/clk/at91/pmc.h
>> +++ b/drivers/clk/at91/pmc.h
>> @@ -58,4 +58,15 @@ static inline void pmc_write(struct at91_pmc *pmc, 
>> int offset, u32 value)
>>   extern void __init of_at91rm9200_clk_main_setup(struct device_node 
>> *np,
>>                           struct at91_pmc *pmc);
>>
>> +extern void __init of_at91rm9200_clk_pll_setup(struct device_node *np,
>> +                           struct at91_pmc *pmc);
>> +extern void __init of_at91sam9g45_clk_pll_setup(struct device_node *np,
>> +                        struct at91_pmc *pmc);
>> +extern void __init of_at91sam9g20_clk_pllb_setup(struct device_node 
>> *np,
>> +                         struct at91_pmc *pmc);
>> +extern void __init of_sama5d3_clk_pll_setup(struct device_node *np,
>> +                        struct at91_pmc *pmc);
>> +extern void __init of_at91sam9x5_clk_plldiv_setup(struct device_node 
>> *np,
>> +                          struct at91_pmc *pmc);
>> +
>>   #endif /* __PMC_H_ */
>> diff --git a/include/linux/clk/at91_pmc.h b/include/linux/clk/at91_pmc.h
>> index 00c45b3..a6911eb 100644
>> --- a/include/linux/clk/at91_pmc.h
>> +++ b/include/linux/clk/at91_pmc.h
>> @@ -164,6 +164,8 @@ extern void __iomem *at91_pmc_base;
>>   #define        AT91_PMC_CFDEV        (1 << 18)        /* Clock 
>> Failure Detector Event [some SAM9] */
>>   #define    AT91_PMC_IMR        0x6c            /* Interrupt Mask 
>> Register */
>>
>> +#define AT91_PMC_PLLICPR    0x80            /* PLL Charge Pump 
>> Current Register */
>> +
>>   #define AT91_PMC_PROT        0xe4            /* Write Protect Mode 
>> Register [some SAM9] */
>>   #define        AT91_PMC_WPEN        (0x1  <<  0) /* Write Protect 
>> Enable */
>>   #define        AT91_PMC_WPKEY        (0xffffff << 8)        /* 
>> Write Protect Key */
>>
>
>


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

* Re: [PATCH v3 07/19] clk: at91: add pll id macros for pll dt bindings
  2013-10-08 10:30   ` Nicolas Ferre
@ 2013-10-08 12:03     ` boris brezillon
  0 siblings, 0 replies; 54+ messages in thread
From: boris brezillon @ 2013-10-08 12:03 UTC (permalink / raw)
  To: Nicolas Ferre, Grant Likely, Rob Herring, Rob Landley,
	Andrew Victor, Jean-Christophe Plagniol-Villard, Russell King,
	Mike Turquette, Felipe Balbi, Greg Kroah-Hartman,
	Ludovic Desroches, Josh Wu, Richard Genoud
  Cc: devicetree, linux-kernel, linux-arm-kernel

On 08/10/2013 12:30, Nicolas Ferre wrote:
> On 08/08/2013 08:09, Boris BREZILLON :
>> This patch adds the PLL id macros which will be used by pll dt 
>> definitions.
>
> It is not needed, drop it. Just document the values in the DT biding 
> and it will be fine.

I'll drop (and document) it.

>
>>
>> Signed-off-by: Boris BREZILLON <b.brezillon@overkiz.com>
>> ---
>>   include/dt-bindings/clk/at91/common/clk-pll.h |   13 +++++++++++++
>>   1 file changed, 13 insertions(+)
>>   create mode 100644 include/dt-bindings/clk/at91/common/clk-pll.h
>>
>> diff --git a/include/dt-bindings/clk/at91/common/clk-pll.h 
>> b/include/dt-bindings/clk/at91/common/clk-pll.h
>> new file mode 100644
>> index 0000000..93ec849
>> --- /dev/null
>> +++ b/include/dt-bindings/clk/at91/common/clk-pll.h
>> @@ -0,0 +1,13 @@
>> +/*
>> + * This header provides constants for AT91 pll ids.
>> + *
>> + * The constants defined in this header are being used in dts.
>> + */
>> +
>> +#ifndef _DT_BINDINGS_CLK_AT91_PLL_H
>> +#define _DT_BINDINGS_CLK_AT91_PLL_H
>> +
>> +#define AT91_PLLA_CLK        0    /* PLLA clk id */
>> +#define AT91_PLLB_CLK        1    /* PLLB clk id */
>> +
>> +#endif
>>
>
>


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

* Re: [PATCH v3 17/19] clk: at91: add PMC clk device tree binding doc.
  2013-10-08  9:44   ` Nicolas Ferre
@ 2013-10-08 12:37     ` boris brezillon
  2013-10-08 12:42       ` Nicolas Ferre
  0 siblings, 1 reply; 54+ messages in thread
From: boris brezillon @ 2013-10-08 12:37 UTC (permalink / raw)
  To: Nicolas Ferre, Grant Likely, Rob Herring, Rob Landley,
	Andrew Victor, Jean-Christophe Plagniol-Villard, Russell King,
	Mike Turquette, Felipe Balbi, Greg Kroah-Hartman,
	Ludovic Desroches, Josh Wu, Richard Genoud
  Cc: devicetree, linux-kernel, linux-arm-kernel

On 08/10/2013 11:44, Nicolas Ferre wrote:
> On 08/08/2013 09:19, Boris BREZILLON :
>> This patch adds new at91 clks dt bindings documentation.
>>
>> Signed-off-by: Boris BREZILLON <b.brezillon@overkiz.com>
>> ---
>>   .../devicetree/bindings/clock/at91-clock.txt       |  312 
>> ++++++++++++++++++++
>>   1 file changed, 312 insertions(+)
>>   create mode 100644 
>> Documentation/devicetree/bindings/clock/at91-clock.txt
>>
>> diff --git a/Documentation/devicetree/bindings/clock/at91-clock.txt 
>> b/Documentation/devicetree/bindings/clock/at91-clock.txt
>> new file mode 100644
>> index 0000000..04739da
>> --- /dev/null
>> +++ b/Documentation/devicetree/bindings/clock/at91-clock.txt
>> @@ -0,0 +1,312 @@
>> +Device Tree Clock bindings for arch-at91
>> +
>> +This binding uses the common clock binding[1].
>> +
>> +[1] Documentation/devicetree/bindings/clock/clock-bindings.txt
>> +
>> +Required properties:
>> +- compatible : shall be one of the following:
>> +    "atmel,at91rm9200-pmc" or
>> +    "atmel,at91sam9g45-pmc" or
>> +    "atmel,at91sam9n12-pmc" or
>> +    "atmel,at91sam9x5-pmc" or
>> +    "atmel,at91sam9g35-pmc" or
>
> Already said in previous patches: 9g35 is not different from the 9x5: 
> it was a bug in the older datasheet.
I'll drop it.
>
>> +    "atmel,sama5d3-pmc":
>> +        at91 PMC (Power Management Controller)
>> +        All at91 specific clocks (clocks defined below) must be child
>> +        node of the PMC node.
>> +
>> +    "atmel,at91rm9200-clk-main":
>> +        at91 main oscillator
>> +
>> +    "atmel,at91rm9200-clk-master" or
>> +    "atmel,at91sam9x5-clk-master":
>> +        at91 master clock
>> +
>> +    "atmel,at91sam9x5-clk-peripheral" or
>> +    "atmel,at91rm9200-clk-peripheral":
>> +        at91 peripheral clocks
>> +
>> +    "atmel,at91rm9200-clk-pll" or
>> +    "atmel,at91sam9g45-clk-pll" or
>> +    "atmel,at91sam9g20-clk-pllb" or
>> +    "atmel,sama5d3-clk-pll":
>> +        at91 pll clocks
>> +
>> +    "atmel,at91sam9x5-clk-plldiv":
>> +        at91 plla divisor
>> +
>> +    "atmel,at91rm9200-clk-programmable" or
>> +    "atmel,at91sam9g45-clk-programmable" or
>> +    "atmel,at91sam9x5-clk-programmable":
>> +        at91 programmable clocks
>> +
>> +    "atmel,at91sam9x5-clk-smd":
>> +        at91 SMD (Soft Modem) clock
>> +
>> +    "atmel,at91rm9200-clk-system":
>> +        at91 system clocks
>> +
>> +    "atmel,at91rm9200-clk-usb" or
>> +    "atmel,at91sam9x5-clk-usb":
>> +        at91 usb clock
>> +
>> +    "atmel,at91sam9x5-clk-utmi":
>> +        at91 utmi clock
>> +
>> +Required properties for PMC node:
>> +- reg : defines the IO memory reserved for the PMC.
>> +- interrupts : shall be set to PMC interrupt line.
>> +- interrupt-controller : tell that the PMC is an interrupt controller
>> +- #interrupt-cells : must be set to 2. The first cell encodes the 
>> interrupt id
>
> Please add more information about these values.
>
The first cell encodes the clk/interrupt id, which is represented by the 
bit position in the PMC_SR register:
  - MAIN clk = 0
  - PLLA = 1
  - ...
>
>> +             the second cell encodes the interrupt type.
>
> Here also: is it always the same type that shall be given? Following 
> which rule? What are the allowed values?

Yes it's always IRQ_TYPE_LEVEL_HIGH, maybe I should just define one cell 
and drop the irq type cell.
>
>
>> +For example:
>> +     pmc: pmc@fffffc00 {
>> +        compatible = "atmel,sama5d3-pmc";
>> +        interrupts = <AT91_ID_SYS IRQ_TYPE_LEVEL_HIGH 7>;
>
> It is an habit not to use macro names in device tree examples (even if 
> it is true that it is more readable).

I'll use numerical values instead of macros (anyway, the AT91_ID_XX will 
be dropped).

>
>> +        interrupt-controller;
>> +        #interrupt-cells = <2>;
>> +
>> +        /* put at91 clocks here */
>> +    };
>> +
>> +Required properties for main clock:
>> +- interrupt-parent : must reference the PMC node.
>> +- interrupts : shall be set to "<AT91_PMC_MOSCS IRQ_TYPE_LEVEL_HIGH>".
>
> Ditto. Here you can use the numerical value and also specify the macro 
> name. But the numerical value should prevail.
Okay

>
>> +- #clock-cells : from common clock binding; shall be set to 0.
>> +- clocks (optional if clock-frequency is provided) : shall be the 
>> slow clock
>> +    phandle. This clock is used to compute the main clock rate if
>> +    "clock-frequency" is not provided.
>> +- clock-frequency: the main oscillator frequency.Prefer the use of
>
> Nit. one white space missing
>
>> +    "clock-frequency" over automatic clock rate computation.
>
>
>> +
>> +For example:
>> +    main: mainck {
>> +        compatible = "atmel,at91rm9200-clk-main";
>> +        interrupt-parent = <&pmc>;
>> +        interrupts = <AT91_PMC_MOSCS IRQ_TYPE_LEVEL_HIGH>;
>
> Ditto
>
>> +        #clock-cells = <0>;
>> +        clocks = <&ck32k>;
>> +        clock-frequency = <18432000>;
>> +    };
>> +
>> +Required properties for master clock:
>> +- interrupt-parent : must reference the PMC node.
>> +- interrupts : shall be set to "<AT91_PMC_MCKRDY IRQ_TYPE_LEVEL_HIGH>".
>
> Ditto
>
>> +- #clock-cells : from common clock binding; shall be set to 0.
>> +- clocks : shall be the master clock sources (see atmel datasheet) 
>> phandles.
>> +    e.g. "<&ck32k>, <&main>, <&plla>, <&pllb>".
>> +- atmel,clk-output-range : minimum and maximum clock frequency (two u32
>> +               fields).
>> +       e.g. output = <0 133000000>; <=> 0 to 133MHz.
>> +- atmel,clk-divisors : master clock divisors table (four u32 fields).
>> +        0 <=> reserved value.
>> +        e.g. divisors = <1 2 4 6>;
>> +- atmel,master-clk-have-div3-pres : some SoC use the reserved value 
>> 7 in the
>> +                    PRES field as CLOCK_DIV3 (e.g sam9x5).
>
> I will check with care the master clock driver as this one is pretty 
> picky about changes that could affect it! Note that in previous clock 
> implementation we did not touched the MCK configuration, we were only 
> reading it...
>
> Anyway, let's keep this binding but make sure that driver is written 
> with extreme care ;-)
>
>> +
>> +For example:
>> +    mck: mck {
>> +        compatible = "atmel,at91rm9200-clk-master";
>> +        interrupt-parent = <&pmc>;
>> +        interrupts = <AT91_PMC_MCKRDY IRQ_TYPE_LEVEL_HIGH>;
>> +        #clock-cells = <0>;
>> +        atmel,clk-output-range = <0 133000000>;
>> +        atmel,clk-divisors = <1 2 4 0>;
>> +    };
>> +
>> +Required properties for peripheral clocks:
>> +- #clock-cells : from common clock binding; shall be set to 1. The 
>> second cell
>> +    is used to encode the peripheral id. Peripheral ids are defined in
>> +    atmel's SoC datasheets.
>> +- clocks : shall be the master clock phandle.
>> +    e.g. clocks = <&mck>;
>> +- name: device tree node describing a specific system clock.
>> +    * atmel,clk-id: peripheral id. Peripheral id macros should be used.
>
> No. Please use raw numbers. We will not switch to macros for these 
> peripheral IDs.
Sure, I'll change this.
>
>> +    * atmel,clk-default-divisor (optional, only available for
>> +      "atmel,at91sam9x5-clk-peripheral"): sam9x5 and sama5d3 SoC 
>> provides
>> +      configurable peripheral clock divisor. If you define this 
>> property
>> +      (u32), the default divisor will be applied when enabling
>> +      peripheral clock. If not provided the peripheral clock is not
>> +      divided.
>> +
>> +For example:
>> +    periph: periphck {
>> +        compatible = "atmel,at91sam9x5-clk-peripheral";
>> +        #clock-cells = <1>;
>> +        clocks = <&mck>;
>> +
>> +        pioA_clk {
>> +            atmel,clk-id = <AT91SAM9X5_ID_PIOA>;
>
> Ditto.
>
>> +            atmel,clk-default-divisor = <1>;
>> +        };
>> +
>> +        pioB_clk {
>> +            atmel,clk-id = <AT91SAM9X5_ID_PIOB>;
>> +            atmel,clk-default-divisor = <2>;
>> +        };
>> +    };
>> +
>> +
>> +Required properties for pll clocks:
>> +- interrupt-parent : must reference the PMC node.
>> +- interrupts : shall be set to "<AT91_PMC_LOCKA IRQ_TYPE_LEVEL_HIGH>".
>
> Ditto
>
>> +- #clock-cells : from common clock binding; shall be set to 0.
>> +- clocks : shall be the main clock phandle.
>> +- atmel,clk-id : pll id. PLL id macros should be used.
>
> No macros here, simply raw numbers. So this mean that we must have 
> some documentation of these numbers.
>
>> +- atmel,clk-input-range : minimum and maximum source clock frequency 
>> (two u32
>> +              fields).
>> +      e.g. input = <1 32000000>; <=> 1 to 32MHz.
>> +- #atmel,pll-clk-output-range-cells : number of cells reserved for 
>> pll output
>> +                      range description. Sould be set to 2, 3
>> +                      or 4.
>> +    * 1st and 2nd cells represent the frequency range (min-max).
>> +    * 3rd cell is optional and represents the OUT field value for 
>> the given
>> +      range.
>> +    * 4th cell is optional and represents the ICPLL field (PLLICPR
>> +      register)
>> +- atmel,pll-clk-output-ranges : pll output frequency ranges + 
>> optional parameter
>> +                depending on #atmel,pll-output-range-cells
>> +                property value.
>> +
>> +For example:
>> +    plla: pllack {
>> +        compatible = "atmel,at91sam9g45-clk-pll";
>> +        interrupt-parent = <&pmc>;
>> +        interrupts = <AT91_PMC_LOCKA IRQ_TYPE_LEVEL_HIGH>;
>> +        #clock-cells = <0>;
>> +        clocks = <&main>;
>> +        atmel,clk-id = <AT91_PLLA_CLK>;
>> +        atmel,clk-input-range = <2000000 32000000>;
>> +        #atmel,pll-clk-output-range-cells = <4>;
>> +        atmel,pll-clk-output-ranges = <74500000 800000000 0 0
>> +                           69500000 750000000 1 0
>> +                           64500000 700000000 2 0
>> +                           59500000 650000000 3 0
>> +                           54500000 600000000 0 1
>> +                           49500000 550000000 1 1
>> +                           44500000 500000000 2 1
>> +                           40000000 450000000 3 1>;
>> +    };
>> +
>> +Required properties for plldiv clocks:
>> +- #clock-cells : from common clock binding; shall be set to 0.
>> +- clocks : shall be the plla clock phandle.
>> +
>> +For example:
>> +    plladiv: plladivck {
>> +        compatible = "atmel,at91sam9x5-clk-plldiv";
>> +        #clock-cells = <0>;
>> +        clocks = <&plla>;
>> +    };
>
> Maybe a little explanation about this clock. It is a fixed divided 
> (how many times?) clock issued from the specified clock.

It is a fixed clock divider (by 2) and AFAIK clk parent must be plla.
I'll add more precision about this clk.

>
>> +
>> +Required properties for programmable clocks:
>> +- interrupt-parent : must reference the PMC node.
>> +- #clock-cells : from common clock binding; shall be set to 1. The 
>> second cell
>> +    is used to encode the programmable clock id.
>> +    Peripheral ids are in atmel's SoC
>> +    datasheets.
>> +- clocks : shall be the programmable clock source phandles.
>> +    e.g. clocks = <&clk32k>, <&main>, <&plla>, <&pllb>;
>> +- name: device tree node describing a specific prog clock.
>> +    * atmel,clk-id : programmable clock id (register offset from  PCKx
>> +             register).
>> +    * interrupts : shall be set to
>> +               "<AT91_PMC_PCKRDY(id) IRQ_TYPE_LEVEL_HIGH>".
>
> Ditto
>
>> +
>> +For example:
>> +    prog: progck {
>> +        compatible = "atmel,at91sam9g45-clk-programmable";
>> +        interrupt-parent = <&pmc>;
>> +        #clock-cells = <1>;
>> +        clocks = <&clk32k>, <&main>, <&plladiv>, <&utmi>, <&mck>;
>> +
>> +        prog0 {
>> +            atmel,clk-id = <0>;
>> +            interrupts = <AT91_PMC_PCKRDY(0) IRQ_TYPE_LEVEL_HIGH>;
>
> Ditto
>
>> +        };
>> +
>> +        prog1 {
>> +            atmel,clk-id = <1>;
>> +            interrupts = <AT91_PMC_PCKRDY(1) IRQ_TYPE_LEVEL_HIGH>;
>> +        };
>> +    };
>> +
>> +
>> +Required properties for smd clock:
>> +- #clock-cells : from common clock binding; shall be set to 0.
>> +- clocks : shall be the smd clock source phandles.
>> +    e.g. clocks = <&plladiv>, <&utmi>;
>> +
>> +For example:
>> +    smd: smdck {
>> +        compatible = "atmel,at91sam9x5-clk-smd";
>> +        #clock-cells = <0>;
>> +        clocks = <&plladiv>, <&utmi>;
>> +    };
>> +
>> +Required properties for system clocks:
>> +- #clock-cells : from common clock binding; shall be set to 1. The 
>> second cell
>> +    is used to encode the system clock id (bit used in SCER/SCDR 
>> register).
>> +- name: device tree node describing a specific system clock.
>> +    * id: system clock id (bit position in SCER/SCDR/SCSR registers).
>> +          System clock id macros should be used.
>
> Ditto
>
>> +
>> +For example:
>> +    system: systemck {
>> +        compatible = "atmel,at91rm9200-clk-system";
>> +        #clock-cells = <1>;
>> +
>> +        ddrck {
>> +            atmel,clk-id = <AT91_DDRCK_SYS_CLK>;
>> +        };
>> +
>> +        uhpck {
>> +            atmel,clk-id = <AT91_UHP_SYS_CLK>;
>> +        };
>> +
>> +        udpck {
>> +            atmel,clk-id = <AT91_UDP_SYS_CLK>;
>> +        };
>> +    };
>> +
>> +
>> +Required properties for usb clock:
>> +- #clock-cells : from common clock binding; shall be set to 0.
>> +- clocks : shall be the smd clock source phandles.
>> +    e.g. clocks = <&pllb>;
>> +- atmel,clk-divisors (only available for "atmel,at91rm9200-clk-usb"):
>> +    usb clock divisor table.
>> +    e.g. divisors = <1 2 4 0>;
>> +- atmel,usb-clk-src0-unused (only available for 
>> "atmel,at91sam9x5-clk-usb"):
>> +    Some SoC (sam9n12) use usb source 0 to disable the usb clock.
>
> I am not sure that we should use a special case for this device.
> The enable/disable is still done by system clock register set.
>
> It is true that this bit is defined differently but just because the 
> only source for this clock is pllb.

Yes, but at least, I need to know that I must add one to the clock 
parent id when I set the USBS field in the PMC_USB register.
Or I can drop the atmel,usb-clk-src0-unused property and  just add a new 
"atmel,at91sam9n12-clk-usb" compatible string,
which might be a better solution here.

Tell me what you'd prefer.
>
>> +
>> +For example:
>> +    usb: usbck {
>> +        compatible = "atmel,at91sam9x5-clk-usb";
>> +        #clock-cells = <0>;
>> +        clocks = <&plladiv>, <&utmi>;
>> +    };
>> +
>> +    usb: usbck {
>> +        compatible = "atmel,at91rm9200-clk-usb";
>> +        #clock-cells = <0>;
>> +        clocks = <&pllb>;
>> +        atmel,clk-divisors = <1 2 4 0>;
>> +    };
>> +
>> +
>> +Required properties for utmi clock:
>> +- interrupt-parent : must reference the PMC node.
>> +- interrupts : shall be set to "<AT91_PMC_LOCKU IRQ_TYPE_LEVEL_HIGH>".
>> +- #clock-cells : from common clock binding; shall be set to 0.
>> +- clocks : shall be the main clock source phandle.
>> +
>> +For example:
>> +    utmi: utmick {
>> +        compatible = "atmel,at91sam9x5-clk-utmi";
>> +        interrupt-parent = <&pmc>;
>> +        interrupts = <AT91_PMC_LOCKU IRQ_TYPE_LEVEL_HIGH>;
>> +        #clock-cells = <0>;
>> +        clocks = <&main>;
>> +    };
>>
>
> Many things in this patch that will have incident in driver code. I 
> will try to be coherent when I review the driver patches ;-)
>
> Anyway, all this seem good!
>
> Bye,

Thanks for the detailed review.



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

* Re: [PATCH v3 17/19] clk: at91: add PMC clk device tree binding doc.
  2013-10-08 12:37     ` boris brezillon
@ 2013-10-08 12:42       ` Nicolas Ferre
  0 siblings, 0 replies; 54+ messages in thread
From: Nicolas Ferre @ 2013-10-08 12:42 UTC (permalink / raw)
  To: boris brezillon, Grant Likely, Rob Herring, Rob Landley,
	Andrew Victor, Jean-Christophe Plagniol-Villard, Russell King,
	Mike Turquette, Felipe Balbi, Greg Kroah-Hartman,
	Ludovic Desroches, Josh Wu, Richard Genoud
  Cc: devicetree, linux-kernel, linux-arm-kernel

On 08/10/2013 14:37, boris brezillon :
> On 08/10/2013 11:44, Nicolas Ferre wrote:
>> On 08/08/2013 09:19, Boris BREZILLON :
>>> This patch adds new at91 clks dt bindings documentation.
>>>
>>> Signed-off-by: Boris BREZILLON <b.brezillon@overkiz.com>
>>> ---
>>>    .../devicetree/bindings/clock/at91-clock.txt       |  312
>>> ++++++++++++++++++++
>>>    1 file changed, 312 insertions(+)
>>>    create mode 100644
>>> Documentation/devicetree/bindings/clock/at91-clock.txt
>>>
>>> diff --git a/Documentation/devicetree/bindings/clock/at91-clock.txt
>>> b/Documentation/devicetree/bindings/clock/at91-clock.txt
>>> new file mode 100644
>>> index 0000000..04739da
>>> --- /dev/null
>>> +++ b/Documentation/devicetree/bindings/clock/at91-clock.txt
>>> @@ -0,0 +1,312 @@
>>> +Device Tree Clock bindings for arch-at91
>>> +
>>> +This binding uses the common clock binding[1].
>>> +
>>> +[1] Documentation/devicetree/bindings/clock/clock-bindings.txt
>>> +
>>> +Required properties:
>>> +- compatible : shall be one of the following:
>>> +    "atmel,at91rm9200-pmc" or
>>> +    "atmel,at91sam9g45-pmc" or
>>> +    "atmel,at91sam9n12-pmc" or
>>> +    "atmel,at91sam9x5-pmc" or
>>> +    "atmel,at91sam9g35-pmc" or
>>
>> Already said in previous patches: 9g35 is not different from the 9x5:
>> it was a bug in the older datasheet.
> I'll drop it.
>>
>>> +    "atmel,sama5d3-pmc":
>>> +        at91 PMC (Power Management Controller)
>>> +        All at91 specific clocks (clocks defined below) must be child
>>> +        node of the PMC node.
>>> +
>>> +    "atmel,at91rm9200-clk-main":
>>> +        at91 main oscillator
>>> +
>>> +    "atmel,at91rm9200-clk-master" or
>>> +    "atmel,at91sam9x5-clk-master":
>>> +        at91 master clock
>>> +
>>> +    "atmel,at91sam9x5-clk-peripheral" or
>>> +    "atmel,at91rm9200-clk-peripheral":
>>> +        at91 peripheral clocks
>>> +
>>> +    "atmel,at91rm9200-clk-pll" or
>>> +    "atmel,at91sam9g45-clk-pll" or
>>> +    "atmel,at91sam9g20-clk-pllb" or
>>> +    "atmel,sama5d3-clk-pll":
>>> +        at91 pll clocks
>>> +
>>> +    "atmel,at91sam9x5-clk-plldiv":
>>> +        at91 plla divisor
>>> +
>>> +    "atmel,at91rm9200-clk-programmable" or
>>> +    "atmel,at91sam9g45-clk-programmable" or
>>> +    "atmel,at91sam9x5-clk-programmable":
>>> +        at91 programmable clocks
>>> +
>>> +    "atmel,at91sam9x5-clk-smd":
>>> +        at91 SMD (Soft Modem) clock
>>> +
>>> +    "atmel,at91rm9200-clk-system":
>>> +        at91 system clocks
>>> +
>>> +    "atmel,at91rm9200-clk-usb" or
>>> +    "atmel,at91sam9x5-clk-usb":
>>> +        at91 usb clock
>>> +
>>> +    "atmel,at91sam9x5-clk-utmi":
>>> +        at91 utmi clock
>>> +
>>> +Required properties for PMC node:
>>> +- reg : defines the IO memory reserved for the PMC.
>>> +- interrupts : shall be set to PMC interrupt line.
>>> +- interrupt-controller : tell that the PMC is an interrupt controller
>>> +- #interrupt-cells : must be set to 2. The first cell encodes the
>>> interrupt id
>>
>> Please add more information about these values.
>>
> The first cell encodes the clk/interrupt id, which is represented by the
> bit position in the PMC_SR register:
>    - MAIN clk = 0
>    - PLLA = 1
>    - ...
>>
>>> +             the second cell encodes the interrupt type.
>>
>> Here also: is it always the same type that shall be given? Following
>> which rule? What are the allowed values?
>
> Yes it's always IRQ_TYPE_LEVEL_HIGH, maybe I should just define one cell
> and drop the irq type cell.

Yes. I am in favor for what you propose.

>>
>>
>>> +For example:
>>> +     pmc: pmc@fffffc00 {
>>> +        compatible = "atmel,sama5d3-pmc";
>>> +        interrupts = <AT91_ID_SYS IRQ_TYPE_LEVEL_HIGH 7>;
>>
>> It is an habit not to use macro names in device tree examples (even if
>> it is true that it is more readable).
>
> I'll use numerical values instead of macros (anyway, the AT91_ID_XX will
> be dropped).
>
>>
>>> +        interrupt-controller;
>>> +        #interrupt-cells = <2>;
>>> +
>>> +        /* put at91 clocks here */
>>> +    };
>>> +
>>> +Required properties for main clock:
>>> +- interrupt-parent : must reference the PMC node.
>>> +- interrupts : shall be set to "<AT91_PMC_MOSCS IRQ_TYPE_LEVEL_HIGH>".
>>
>> Ditto. Here you can use the numerical value and also specify the macro
>> name. But the numerical value should prevail.
> Okay
>
>>
>>> +- #clock-cells : from common clock binding; shall be set to 0.
>>> +- clocks (optional if clock-frequency is provided) : shall be the
>>> slow clock
>>> +    phandle. This clock is used to compute the main clock rate if
>>> +    "clock-frequency" is not provided.
>>> +- clock-frequency: the main oscillator frequency.Prefer the use of
>>
>> Nit. one white space missing
>>
>>> +    "clock-frequency" over automatic clock rate computation.
>>
>>
>>> +
>>> +For example:
>>> +    main: mainck {
>>> +        compatible = "atmel,at91rm9200-clk-main";
>>> +        interrupt-parent = <&pmc>;
>>> +        interrupts = <AT91_PMC_MOSCS IRQ_TYPE_LEVEL_HIGH>;
>>
>> Ditto
>>
>>> +        #clock-cells = <0>;
>>> +        clocks = <&ck32k>;
>>> +        clock-frequency = <18432000>;
>>> +    };
>>> +
>>> +Required properties for master clock:
>>> +- interrupt-parent : must reference the PMC node.
>>> +- interrupts : shall be set to "<AT91_PMC_MCKRDY IRQ_TYPE_LEVEL_HIGH>".
>>
>> Ditto
>>
>>> +- #clock-cells : from common clock binding; shall be set to 0.
>>> +- clocks : shall be the master clock sources (see atmel datasheet)
>>> phandles.
>>> +    e.g. "<&ck32k>, <&main>, <&plla>, <&pllb>".
>>> +- atmel,clk-output-range : minimum and maximum clock frequency (two u32
>>> +               fields).
>>> +       e.g. output = <0 133000000>; <=> 0 to 133MHz.
>>> +- atmel,clk-divisors : master clock divisors table (four u32 fields).
>>> +        0 <=> reserved value.
>>> +        e.g. divisors = <1 2 4 6>;
>>> +- atmel,master-clk-have-div3-pres : some SoC use the reserved value
>>> 7 in the
>>> +                    PRES field as CLOCK_DIV3 (e.g sam9x5).
>>
>> I will check with care the master clock driver as this one is pretty
>> picky about changes that could affect it! Note that in previous clock
>> implementation we did not touched the MCK configuration, we were only
>> reading it...
>>
>> Anyway, let's keep this binding but make sure that driver is written
>> with extreme care ;-)
>>
>>> +
>>> +For example:
>>> +    mck: mck {
>>> +        compatible = "atmel,at91rm9200-clk-master";
>>> +        interrupt-parent = <&pmc>;
>>> +        interrupts = <AT91_PMC_MCKRDY IRQ_TYPE_LEVEL_HIGH>;
>>> +        #clock-cells = <0>;
>>> +        atmel,clk-output-range = <0 133000000>;
>>> +        atmel,clk-divisors = <1 2 4 0>;
>>> +    };
>>> +
>>> +Required properties for peripheral clocks:
>>> +- #clock-cells : from common clock binding; shall be set to 1. The
>>> second cell
>>> +    is used to encode the peripheral id. Peripheral ids are defined in
>>> +    atmel's SoC datasheets.
>>> +- clocks : shall be the master clock phandle.
>>> +    e.g. clocks = <&mck>;
>>> +- name: device tree node describing a specific system clock.
>>> +    * atmel,clk-id: peripheral id. Peripheral id macros should be used.
>>
>> No. Please use raw numbers. We will not switch to macros for these
>> peripheral IDs.
> Sure, I'll change this.
>>
>>> +    * atmel,clk-default-divisor (optional, only available for
>>> +      "atmel,at91sam9x5-clk-peripheral"): sam9x5 and sama5d3 SoC
>>> provides
>>> +      configurable peripheral clock divisor. If you define this
>>> property
>>> +      (u32), the default divisor will be applied when enabling
>>> +      peripheral clock. If not provided the peripheral clock is not
>>> +      divided.
>>> +
>>> +For example:
>>> +    periph: periphck {
>>> +        compatible = "atmel,at91sam9x5-clk-peripheral";
>>> +        #clock-cells = <1>;
>>> +        clocks = <&mck>;
>>> +
>>> +        pioA_clk {
>>> +            atmel,clk-id = <AT91SAM9X5_ID_PIOA>;
>>
>> Ditto.
>>
>>> +            atmel,clk-default-divisor = <1>;
>>> +        };
>>> +
>>> +        pioB_clk {
>>> +            atmel,clk-id = <AT91SAM9X5_ID_PIOB>;
>>> +            atmel,clk-default-divisor = <2>;
>>> +        };
>>> +    };
>>> +
>>> +
>>> +Required properties for pll clocks:
>>> +- interrupt-parent : must reference the PMC node.
>>> +- interrupts : shall be set to "<AT91_PMC_LOCKA IRQ_TYPE_LEVEL_HIGH>".
>>
>> Ditto
>>
>>> +- #clock-cells : from common clock binding; shall be set to 0.
>>> +- clocks : shall be the main clock phandle.
>>> +- atmel,clk-id : pll id. PLL id macros should be used.
>>
>> No macros here, simply raw numbers. So this mean that we must have
>> some documentation of these numbers.
>>
>>> +- atmel,clk-input-range : minimum and maximum source clock frequency
>>> (two u32
>>> +              fields).
>>> +      e.g. input = <1 32000000>; <=> 1 to 32MHz.
>>> +- #atmel,pll-clk-output-range-cells : number of cells reserved for
>>> pll output
>>> +                      range description. Sould be set to 2, 3
>>> +                      or 4.
>>> +    * 1st and 2nd cells represent the frequency range (min-max).
>>> +    * 3rd cell is optional and represents the OUT field value for
>>> the given
>>> +      range.
>>> +    * 4th cell is optional and represents the ICPLL field (PLLICPR
>>> +      register)
>>> +- atmel,pll-clk-output-ranges : pll output frequency ranges +
>>> optional parameter
>>> +                depending on #atmel,pll-output-range-cells
>>> +                property value.
>>> +
>>> +For example:
>>> +    plla: pllack {
>>> +        compatible = "atmel,at91sam9g45-clk-pll";
>>> +        interrupt-parent = <&pmc>;
>>> +        interrupts = <AT91_PMC_LOCKA IRQ_TYPE_LEVEL_HIGH>;
>>> +        #clock-cells = <0>;
>>> +        clocks = <&main>;
>>> +        atmel,clk-id = <AT91_PLLA_CLK>;
>>> +        atmel,clk-input-range = <2000000 32000000>;
>>> +        #atmel,pll-clk-output-range-cells = <4>;
>>> +        atmel,pll-clk-output-ranges = <74500000 800000000 0 0
>>> +                           69500000 750000000 1 0
>>> +                           64500000 700000000 2 0
>>> +                           59500000 650000000 3 0
>>> +                           54500000 600000000 0 1
>>> +                           49500000 550000000 1 1
>>> +                           44500000 500000000 2 1
>>> +                           40000000 450000000 3 1>;
>>> +    };
>>> +
>>> +Required properties for plldiv clocks:
>>> +- #clock-cells : from common clock binding; shall be set to 0.
>>> +- clocks : shall be the plla clock phandle.
>>> +
>>> +For example:
>>> +    plladiv: plladivck {
>>> +        compatible = "atmel,at91sam9x5-clk-plldiv";
>>> +        #clock-cells = <0>;
>>> +        clocks = <&plla>;
>>> +    };
>>
>> Maybe a little explanation about this clock. It is a fixed divided
>> (how many times?) clock issued from the specified clock.
>
> It is a fixed clock divider (by 2) and AFAIK clk parent must be plla.
> I'll add more precision about this clk.
>
>>
>>> +
>>> +Required properties for programmable clocks:
>>> +- interrupt-parent : must reference the PMC node.
>>> +- #clock-cells : from common clock binding; shall be set to 1. The
>>> second cell
>>> +    is used to encode the programmable clock id.
>>> +    Peripheral ids are in atmel's SoC
>>> +    datasheets.
>>> +- clocks : shall be the programmable clock source phandles.
>>> +    e.g. clocks = <&clk32k>, <&main>, <&plla>, <&pllb>;
>>> +- name: device tree node describing a specific prog clock.
>>> +    * atmel,clk-id : programmable clock id (register offset from  PCKx
>>> +             register).
>>> +    * interrupts : shall be set to
>>> +               "<AT91_PMC_PCKRDY(id) IRQ_TYPE_LEVEL_HIGH>".
>>
>> Ditto
>>
>>> +
>>> +For example:
>>> +    prog: progck {
>>> +        compatible = "atmel,at91sam9g45-clk-programmable";
>>> +        interrupt-parent = <&pmc>;
>>> +        #clock-cells = <1>;
>>> +        clocks = <&clk32k>, <&main>, <&plladiv>, <&utmi>, <&mck>;
>>> +
>>> +        prog0 {
>>> +            atmel,clk-id = <0>;
>>> +            interrupts = <AT91_PMC_PCKRDY(0) IRQ_TYPE_LEVEL_HIGH>;
>>
>> Ditto
>>
>>> +        };
>>> +
>>> +        prog1 {
>>> +            atmel,clk-id = <1>;
>>> +            interrupts = <AT91_PMC_PCKRDY(1) IRQ_TYPE_LEVEL_HIGH>;
>>> +        };
>>> +    };
>>> +
>>> +
>>> +Required properties for smd clock:
>>> +- #clock-cells : from common clock binding; shall be set to 0.
>>> +- clocks : shall be the smd clock source phandles.
>>> +    e.g. clocks = <&plladiv>, <&utmi>;
>>> +
>>> +For example:
>>> +    smd: smdck {
>>> +        compatible = "atmel,at91sam9x5-clk-smd";
>>> +        #clock-cells = <0>;
>>> +        clocks = <&plladiv>, <&utmi>;
>>> +    };
>>> +
>>> +Required properties for system clocks:
>>> +- #clock-cells : from common clock binding; shall be set to 1. The
>>> second cell
>>> +    is used to encode the system clock id (bit used in SCER/SCDR
>>> register).
>>> +- name: device tree node describing a specific system clock.
>>> +    * id: system clock id (bit position in SCER/SCDR/SCSR registers).
>>> +          System clock id macros should be used.
>>
>> Ditto
>>
>>> +
>>> +For example:
>>> +    system: systemck {
>>> +        compatible = "atmel,at91rm9200-clk-system";
>>> +        #clock-cells = <1>;
>>> +
>>> +        ddrck {
>>> +            atmel,clk-id = <AT91_DDRCK_SYS_CLK>;
>>> +        };
>>> +
>>> +        uhpck {
>>> +            atmel,clk-id = <AT91_UHP_SYS_CLK>;
>>> +        };
>>> +
>>> +        udpck {
>>> +            atmel,clk-id = <AT91_UDP_SYS_CLK>;
>>> +        };
>>> +    };
>>> +
>>> +
>>> +Required properties for usb clock:
>>> +- #clock-cells : from common clock binding; shall be set to 0.
>>> +- clocks : shall be the smd clock source phandles.
>>> +    e.g. clocks = <&pllb>;
>>> +- atmel,clk-divisors (only available for "atmel,at91rm9200-clk-usb"):
>>> +    usb clock divisor table.
>>> +    e.g. divisors = <1 2 4 0>;
>>> +- atmel,usb-clk-src0-unused (only available for
>>> "atmel,at91sam9x5-clk-usb"):
>>> +    Some SoC (sam9n12) use usb source 0 to disable the usb clock.
>>
>> I am not sure that we should use a special case for this device.
>> The enable/disable is still done by system clock register set.
>>
>> It is true that this bit is defined differently but just because the
>> only source for this clock is pllb.
>
> Yes, but at least, I need to know that I must add one to the clock
> parent id when I set the USBS field in the PMC_USB register.
> Or I can drop the atmel,usb-clk-src0-unused property and  just add a new
> "atmel,at91sam9n12-clk-usb" compatible string,
> which might be a better solution here.
>
> Tell me what you'd prefer.

Yep, that is what I was thinking about: use a specific 
"atmel,at91sam9n12-clk-usb" compatible string.

>>
>>> +
>>> +For example:
>>> +    usb: usbck {
>>> +        compatible = "atmel,at91sam9x5-clk-usb";
>>> +        #clock-cells = <0>;
>>> +        clocks = <&plladiv>, <&utmi>;
>>> +    };
>>> +
>>> +    usb: usbck {
>>> +        compatible = "atmel,at91rm9200-clk-usb";
>>> +        #clock-cells = <0>;
>>> +        clocks = <&pllb>;
>>> +        atmel,clk-divisors = <1 2 4 0>;
>>> +    };
>>> +
>>> +
>>> +Required properties for utmi clock:
>>> +- interrupt-parent : must reference the PMC node.
>>> +- interrupts : shall be set to "<AT91_PMC_LOCKU IRQ_TYPE_LEVEL_HIGH>".
>>> +- #clock-cells : from common clock binding; shall be set to 0.
>>> +- clocks : shall be the main clock source phandle.
>>> +
>>> +For example:
>>> +    utmi: utmick {
>>> +        compatible = "atmel,at91sam9x5-clk-utmi";
>>> +        interrupt-parent = <&pmc>;
>>> +        interrupts = <AT91_PMC_LOCKU IRQ_TYPE_LEVEL_HIGH>;
>>> +        #clock-cells = <0>;
>>> +        clocks = <&main>;
>>> +    };
>>>
>>
>> Many things in this patch that will have incident in driver code. I
>> will try to be coherent when I review the driver patches ;-)
>>
>> Anyway, all this seem good!
>>
>> Bye,
>
> Thanks for the detailed review.
>
>
>
>


-- 
Nicolas Ferre

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

* Re: [PATCH v3 09/19] clk: at91: add PMC system clocks
  2013-08-08  6:12 ` [PATCH v3 09/19] clk: at91: add PMC system clocks Boris BREZILLON
@ 2013-10-08 15:32   ` Nicolas Ferre
  0 siblings, 0 replies; 54+ messages in thread
From: Nicolas Ferre @ 2013-10-08 15:32 UTC (permalink / raw)
  To: Boris BREZILLON, Grant Likely, Rob Herring, Rob Landley,
	Andrew Victor, Jean-Christophe Plagniol-Villard, Russell King,
	Mike Turquette, Felipe Balbi, Greg Kroah-Hartman,
	Ludovic Desroches, Josh Wu, Richard Genoud
  Cc: devicetree, linux-kernel, linux-arm-kernel

On 08/08/2013 08:12, Boris BREZILLON :
> This patch adds new at91 system clock implementation using common clk
> framework.
>
> Some peripherals need to enable a "system" clock in order to work properly.
> Each system clock is given an id based on the bit position in SCER/SCDR
> registers.
>
> Signed-off-by: Boris BREZILLON <b.brezillon@overkiz.com>
> ---
>   drivers/clk/at91/Makefile     |    1 +
>   drivers/clk/at91/clk-system.c |  191 +++++++++++++++++++++++++++++++++++++++++
>   drivers/clk/at91/pmc.c        |    5 ++
>   drivers/clk/at91/pmc.h        |    3 +
>   4 files changed, 200 insertions(+)
>   create mode 100644 drivers/clk/at91/clk-system.c
>
> diff --git a/drivers/clk/at91/Makefile b/drivers/clk/at91/Makefile
> index e28fb2b..c2b7068 100644
> --- a/drivers/clk/at91/Makefile
> +++ b/drivers/clk/at91/Makefile
> @@ -4,3 +4,4 @@
>
>   obj-y += pmc.o
>   obj-y += clk-main.o clk-pll.o clk-plldiv.o clk-master.o
> +obj-y += clk-system.o
> diff --git a/drivers/clk/at91/clk-system.c b/drivers/clk/at91/clk-system.c
> new file mode 100644
> index 0000000..11a3eb8
> --- /dev/null
> +++ b/drivers/clk/at91/clk-system.c
> @@ -0,0 +1,191 @@
> +/*
> + * drivers/clk/at91/clk-system.c
> + *
> + *  Copyright (C) 2013 Boris BREZILLON <b.brezillon@overkiz.com>
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License as published by
> + * the Free Software Foundation; either version 2 of the License, or
> + * (at your option) any later version.
> + *
> + */
> +
> +#include <linux/clk-provider.h>
> +#include <linux/clkdev.h>
> +#include <linux/clk/at91_pmc.h>
> +#include <linux/of.h>
> +#include <linux/of_address.h>
> +#include <linux/io.h>
> +
> +#include "pmc.h"
> +
> +#define SYSTEM_MAX		32
> +
> +#define to_clk_system(hw) container_of(hw, struct clk_system, hw)
> +struct clk_system {
> +	struct clk_hw hw;
> +	struct at91_pmc *pmc;
> +	u8 id;
> +};
> +
> +static int clk_system_enable(struct clk_hw *hw)
> +{
> +	struct clk_system *sys = to_clk_system(hw);
> +	struct at91_pmc *pmc = sys->pmc;
> +
> +	pmc_write(pmc, AT91_PMC_SCER, 1 << sys->id);
> +	return 0;
> +}
> +
> +static void clk_system_disable(struct clk_hw *hw)
> +{
> +	struct clk_system *sys = to_clk_system(hw);
> +	struct at91_pmc *pmc = sys->pmc;
> +
> +	pmc_write(pmc, AT91_PMC_SCDR, 1 << sys->id);
> +}
> +
> +static int clk_system_is_enabled(struct clk_hw *hw)
> +{
> +	struct clk_system *sys = to_clk_system(hw);
> +	struct at91_pmc *pmc = sys->pmc;
> +
> +	return !!(pmc_read(pmc, AT91_PMC_SCSR) & (1 << sys->id));
> +}
> +
> +static const struct clk_ops system_ops = {
> +	.enable = clk_system_enable,
> +	.disable = clk_system_disable,
> +	.is_enabled = clk_system_is_enabled,
> +};
> +
> +static struct clk * __init
> +at91_clk_register_system(struct at91_pmc *pmc, const char *name, u8 id)
> +{
> +	struct clk_system *sys;
> +	struct clk *clk = NULL;
> +	struct clk_init_data init;
> +
> +	id &= 31;

defined constant. Or event return an error instead of masking it (same 
for pll ids if I remember well).

> +
> +	sys = kzalloc(sizeof(*sys), GFP_KERNEL);
> +	if (!sys)
> +		return ERR_PTR(-ENOMEM);
> +
> +	init.name = name;
> +	init.ops = &system_ops;
> +	init.parent_names = NULL;
> +	init.num_parents = 0;
> +	/*
> +	 * CLK_IGNORE_UNUSED is used to avoid ddrck switch off.
> +	 * TODO : we should implement a driver supporting at91 ddr controller
> +	 * (see drivers/memory) which would request and enable the ddrck clock.
> +	 * When this is done we will be able to remove CLK_IGNORE_UNUSED flag.
> +	 */
> +	init.flags = CLK_IS_ROOT | CLK_IGNORE_UNUSED;

Is it a root clock? Usually clock parent for USB is UTMI or PLLB, LCD is 
usually the MCK. But I do not know how it interfere with your clock tree...

> +
> +	sys->id = id;
> +	sys->hw.init = &init;
> +	sys->pmc = pmc;
> +
> +	clk = clk_register(NULL, &sys->hw);
> +
> +	if (IS_ERR(clk))
> +		kfree(sys);
> +
> +	return clk;
> +}
> +
> +struct clk_system_data {
> +	struct clk **clks;
> +	u8 *ids;
> +	unsigned int clk_num;
> +};
> +
> +static struct clk * __init
> +of_clk_src_system_get(struct of_phandle_args *clkspec, void *data)
> +{
> +	struct clk_system_data *clk_data = data;
> +	unsigned int id = clkspec->args[0];
> +	int i;
> +
> +	if (id >= SYSTEM_MAX)
> +		goto err;
> +
> +	for (i = 0; i < clk_data->clk_num; i++) {
> +		if (clk_data->ids[i] == id)
> +			return clk_data->clks[i];
> +	}
> +
> +err:
> +	pr_err("%s: invalid clock id %d\n", __func__, id);
> +	return ERR_PTR(-EINVAL);
> +}
> +
> +static void __init
> +of_at91_clk_sys_setup(struct device_node *np, struct at91_pmc *pmc)
> +{
> +	int i;
> +	int num;
> +	u32 id;
> +	struct clk *clk;
> +	u8 *ids;
> +	struct clk **clks;
> +	struct clk_system_data *clktab;
> +	const char *name;
> +	struct device_node *sysclknp;
> +
> +	num = of_get_child_count(np);
> +	if (num > SYSTEM_MAX)
> +		return;
> +
> +	clktab = kzalloc(sizeof(*clktab), GFP_KERNEL);
> +	if (!clktab)
> +		return;
> +
> +	ids = kzalloc(num * sizeof(*ids), GFP_KERNEL);
> +	if (!ids)
> +		goto out_free_clktab;
> +
> +	clks = kzalloc(num * sizeof(*clks), GFP_KERNEL);
> +	if (!clks)
> +		goto out_free_ids;
> +
> +	i = 0;
> +	for_each_child_of_node(np, sysclknp) {
> +		name = sysclknp->name;
> +
> +		if (of_property_read_u32(sysclknp, "atmel,clk-id", &id))
> +			goto out_free_clks;
> +		if (id >= SYSTEM_MAX)
> +			goto out_free_clks;
> +
> +		clk = at91_clk_register_system(pmc, name, id);
> +		if (IS_ERR(clk))
> +			goto out_free_clks;
> +
> +		clks[i] = clk;
> +		ids[i] = id;
> +
> +		i++;
> +	}
> +
> +	clktab->clk_num = num;
> +	clktab->clks = clks;
> +	clktab->ids = ids;
> +	of_clk_add_provider(np, of_clk_src_system_get, clktab);
> +	return;
> +
> +out_free_clks:
> +	kfree(clks);
> +out_free_ids:
> +	kfree(ids);
> +out_free_clktab:
> +	kfree(clktab);
> +}
> +
> +void __init of_at91rm9200_clk_sys_setup(struct device_node *np,
> +					struct at91_pmc *pmc)
> +{
> +	of_at91_clk_sys_setup(np, pmc);
> +}
> diff --git a/drivers/clk/at91/pmc.c b/drivers/clk/at91/pmc.c
> index 5258f1d..c674ef2 100644
> --- a/drivers/clk/at91/pmc.c
> +++ b/drivers/clk/at91/pmc.c
> @@ -251,6 +251,11 @@ static const struct of_device_id pmc_clk_ids[] __initdata = {
>   		.compatible = "atmel,at91sam9x5-clk-master",
>   		.data = of_at91sam9x5_clk_master_setup,
>   	},
> +	/* System clocks */
> +	{
> +		.compatible = "atmel,at91rm9200-clk-system",
> +		.data = of_at91rm9200_clk_sys_setup,
> +	},
>   	{ /*sentinel*/ }
>   };
>
> diff --git a/drivers/clk/at91/pmc.h b/drivers/clk/at91/pmc.h
> index 2e1dcb8..f88ef41 100644
> --- a/drivers/clk/at91/pmc.h
> +++ b/drivers/clk/at91/pmc.h
> @@ -74,4 +74,7 @@ extern void __init of_at91rm9200_clk_master_setup(struct device_node *np,
>   extern void __init of_at91sam9x5_clk_master_setup(struct device_node *np,
>   						  struct at91_pmc *pmc);
>
> +extern void __init of_at91rm9200_clk_sys_setup(struct device_node *np,
> +					       struct at91_pmc *pmc);
> +
>   #endif /* __PMC_H_ */
>


-- 
Nicolas Ferre

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

* Re: [PATCH v3 10/19] ARM: at91/dt: add system clk id definitions in dt-bindings include dir
  2013-08-08  6:15 ` [PATCH v3 10/19] ARM: at91/dt: add system clk id definitions in dt-bindings include dir Boris BREZILLON
@ 2013-10-08 15:36   ` Nicolas Ferre
  0 siblings, 0 replies; 54+ messages in thread
From: Nicolas Ferre @ 2013-10-08 15:36 UTC (permalink / raw)
  To: Boris BREZILLON, Grant Likely, Rob Herring, Rob Landley,
	Andrew Victor, Jean-Christophe Plagniol-Villard, Russell King,
	Mike Turquette, Felipe Balbi, Greg Kroah-Hartman,
	Ludovic Desroches, Josh Wu, Richard Genoud
  Cc: devicetree, linux-kernel, linux-arm-kernel

On 08/08/2013 08:15, Boris BREZILLON :
> This patch adds system clk ids definitions into dt-bindinds include dir
> (include/dt-bindings/clk/at91/'soc-name'/system-clk.h).
>
> These definitions will be used by dt definition to define and reference
> system clks.

As said earlier, I think that these definitions can be removed. We can 
stick with raw numbers and just document that we are using the offset of 
the coresponding bit in the register.

> Signed-off-by: Boris BREZILLON <b.brezillon@overkiz.com>
> ---
>   .../dt-bindings/clk/at91/at91rm9200/clk-system.h   |   16 +++++++++++++++
>   .../dt-bindings/clk/at91/at91sam9261/clk-system.h  |   15 ++++++++++++++
>   include/dt-bindings/clk/at91/common/clk-system.h   |   21 ++++++++++++++++++++
>   3 files changed, 52 insertions(+)
>   create mode 100644 include/dt-bindings/clk/at91/at91rm9200/clk-system.h
>   create mode 100644 include/dt-bindings/clk/at91/at91sam9261/clk-system.h
>   create mode 100644 include/dt-bindings/clk/at91/common/clk-system.h
>
> diff --git a/include/dt-bindings/clk/at91/at91rm9200/clk-system.h b/include/dt-bindings/clk/at91/at91rm9200/clk-system.h
> new file mode 100644
> index 0000000..43bccd5
> --- /dev/null
> +++ b/include/dt-bindings/clk/at91/at91rm9200/clk-system.h
> @@ -0,0 +1,16 @@
> +/*
> + * This header provides constants for AT91RM9200 system clocks.
> + *
> + * The constants defined in this header are being used in dts.
> + */
> +
> +#ifndef _DT_BINDINGS_CLK_AT91RM9200_SYSTEM_H
> +#define _DT_BINDINGS_CLK_AT91RM9200_SYSTEM_H
> +
> +#include <dt-bindings/clk/at91/common/system-clk.h>
> +
> +#define AT91RM9200_UDP_SYS_CLK		1
> +#define AT91RM9200_MCKUDP_SYS_CLK	2
> +#define AT91RM9200_UHP_SYS_CLK		4
> +
> +#endif
> diff --git a/include/dt-bindings/clk/at91/at91sam9261/clk-system.h b/include/dt-bindings/clk/at91/at91sam9261/clk-system.h
> new file mode 100644
> index 0000000..28a140a
> --- /dev/null
> +++ b/include/dt-bindings/clk/at91/at91sam9261/clk-system.h
> @@ -0,0 +1,15 @@
> +/*
> + * This header provides constants for AT91SAM9261 system clocks.
> + *
> + * The constants defined in this header are being used in dts.
> + */
> +
> +#ifndef _DT_BINDINGS_CLK_AT91SAM9261_SYSTEM_H
> +#define _DT_BINDINGS_CLK_AT91SAM9261_SYSTEM_H
> +
> +#include <dt-bindings/clk/at91/common/system-clk.h>
> +
> +#define AT91SAM9261_HCK0_SYS_CLK	16
> +#define AT91SAM9261_HCK1_SYS_CLK	17
> +
> +#endif
> diff --git a/include/dt-bindings/clk/at91/common/clk-system.h b/include/dt-bindings/clk/at91/common/clk-system.h
> new file mode 100644
> index 0000000..c0fb124
> --- /dev/null
> +++ b/include/dt-bindings/clk/at91/common/clk-system.h
> @@ -0,0 +1,21 @@
> +/*
> + * This header provides constants for AT91 system clocks.
> + *
> + * The constants defined in this header are being used in dts.
> + */
> +
> +#ifndef _DT_BINDINGS_CLK_AT91_SYSTEM_H
> +#define _DT_BINDINGS_CLK_AT91_SYSTEM_H
> +
> +#define AT91_PCK_SYS_CLK	0
> +#define AT91_DDRCK_SYS_CLK	2
> +#define AT91_LCDCK_SYS_CLK	3
> +#define AT91_SMDCK_SYS_CLK	4
> +#define AT91_UHP_SYS_CLK	6
> +#define AT91_UDP_SYS_CLK	7
> +
> +#define AT91_PROG_SYS_CLK(id)	(8 + id)
> +
> +#define AT91_MAX_SYS_CLKS	32
> +
> +#endif
>


-- 
Nicolas Ferre

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

* Re: [PATCH v3 11/19] clk: at91: add PMC peripheral clocks
  2013-08-08  6:16 ` [PATCH v3 11/19] clk: at91: add PMC peripheral clocks Boris BREZILLON
@ 2013-10-08 15:43   ` Nicolas Ferre
  0 siblings, 0 replies; 54+ messages in thread
From: Nicolas Ferre @ 2013-10-08 15:43 UTC (permalink / raw)
  To: Boris BREZILLON, Grant Likely, Rob Herring, Rob Landley,
	Andrew Victor, Jean-Christophe Plagniol-Villard, Russell King,
	Mike Turquette, Felipe Balbi, Greg Kroah-Hartman,
	Ludovic Desroches, Josh Wu, Richard Genoud
  Cc: devicetree, linux-kernel, linux-arm-kernel

On 08/08/2013 08:16, Boris BREZILLON :
> This patch adds new at91 peripheral clock implementation using common clk
> framework.
>
> Almost all peripherals provided by at91 SoCs need a clock to work properly.
> This clock is enabled/disabled using PCER/PCDR resgisters.
>
> Each peripheral is given an id (see atmel's datasheets) which is used to
> define and reference peripheral clocks.
>
> Some new SoCs (at91sam9x5 and sama5d3) provide a new register (PCR) where you
> can configure the peripheral clock as a division of the master clock.
> This will help reducing the peripherals power comsumption.
>
> Signed-off-by: Boris BREZILLON <b.brezillon@overkiz.com>
> ---
>   drivers/clk/at91/Makefile         |    2 +-
>   drivers/clk/at91/clk-peripheral.c |  401 +++++++++++++++++++++++++++++++++++++
>   drivers/clk/at91/pmc.c            |    9 +
>   drivers/clk/at91/pmc.h            |    5 +
>   4 files changed, 416 insertions(+), 1 deletion(-)
>   create mode 100644 drivers/clk/at91/clk-peripheral.c
>
> diff --git a/drivers/clk/at91/Makefile b/drivers/clk/at91/Makefile
> index c2b7068..04deba3 100644
> --- a/drivers/clk/at91/Makefile
> +++ b/drivers/clk/at91/Makefile
> @@ -4,4 +4,4 @@
>
>   obj-y += pmc.o
>   obj-y += clk-main.o clk-pll.o clk-plldiv.o clk-master.o
> -obj-y += clk-system.o
> +obj-y += clk-system.o clk-peripheral.o
> diff --git a/drivers/clk/at91/clk-peripheral.c b/drivers/clk/at91/clk-peripheral.c
> new file mode 100644
> index 0000000..1612739
> --- /dev/null
> +++ b/drivers/clk/at91/clk-peripheral.c
> @@ -0,0 +1,401 @@
> +/*
> + * drivers/clk/at91/clk-peripheral.c
> + *
> + *  Copyright (C) 2013 Boris BREZILLON <b.brezillon@overkiz.com>
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License as published by
> + * the Free Software Foundation; either version 2 of the License, or
> + * (at your option) any later version.
> + *
> + */
> +
> +#include <linux/clk-provider.h>
> +#include <linux/clkdev.h>
> +#include <linux/clk/at91_pmc.h>
> +#include <linux/of.h>
> +#include <linux/of_address.h>
> +#include <linux/io.h>
> +
> +#include "pmc.h"
> +
> +#define PERIPHERAL_MAX		64
> +
> +#define PERIPHERAL_AT91RM9200	0
> +#define PERIPHERAL_AT91SAM9X5	1
> +
> +#define to_clk_peripheral(hw) container_of(hw, struct clk_peripheral, hw)
> +struct clk_peripheral {
> +	struct clk_hw hw;
> +	struct at91_pmc *pmc;
> +	u32 id;
> +};
> +
> +#define to_clk_sam9x5_peripheral(hw) \
> +	container_of(hw, struct clk_sam9x5_peripheral, hw)
> +struct clk_sam9x5_peripheral {
> +	struct clk_hw hw;
> +	struct at91_pmc *pmc;
> +	u32 id;
> +	u8 div;
> +	u8 have_div_support;
> +};
> +
> +static int clk_peripheral_enable(struct clk_hw *hw)
> +{
> +	struct clk_peripheral *periph = to_clk_peripheral(hw);
> +	struct at91_pmc *pmc = periph->pmc;
> +	int offset = AT91_PMC_PCER;
> +
> +	if (periph->id < 2)
> +		return 0;
> +	if (periph->id > 31)

define constants

> +		offset = AT91_PMC_PCER1;
> +	pmc_write(pmc, offset, 1 << (periph->id & 31));

A little macro here.

> +	return 0;
> +}
> +
> +static void clk_peripheral_disable(struct clk_hw *hw)
> +{
> +	struct clk_peripheral *periph = to_clk_peripheral(hw);
> +	struct at91_pmc *pmc = periph->pmc;
> +	int offset = AT91_PMC_PCDR;
> +
> +	if (periph->id < 2)
> +		return;
> +	if (periph->id > 31)
> +		offset = AT91_PMC_PCDR1;
> +	pmc_write(pmc, offset, 1 << (periph->id & 31));

Ditto

> +}
> +
> +static int clk_peripheral_is_enabled(struct clk_hw *hw)
> +{
> +	struct clk_peripheral *periph = to_clk_peripheral(hw);
> +	struct at91_pmc *pmc = periph->pmc;
> +	int offset = AT91_PMC_PCSR;
> +
> +	if (periph->id < 2)
> +		return 1;
> +	if (periph->id > 31)
> +		offset = AT91_PMC_PCSR1;
> +	return !!(pmc_read(pmc, offset) & (1 << (periph->id & 31)));

Ditto

> +}
> +
> +static const struct clk_ops peripheral_ops = {
> +	.enable = clk_peripheral_enable,
> +	.disable = clk_peripheral_disable,
> +	.is_enabled = clk_peripheral_is_enabled,
> +};
> +
> +static struct clk * __init
> +at91_clk_register_peripheral(struct at91_pmc *pmc, const char *name,
> +			     const char *parent_name, u32 id)
> +{
> +	struct clk_peripheral *periph;
> +	struct clk *clk = NULL;
> +	struct clk_init_data init;
> +
> +	if (!pmc || !name || !parent_name)
> +		return ERR_PTR(-EINVAL);
> +
> +	id &= 31;

Ditto

> +	periph = kzalloc(sizeof(*periph), GFP_KERNEL);
> +	if (!periph)
> +		return ERR_PTR(-ENOMEM);
> +
> +	init.name = name;
> +	init.ops = &peripheral_ops;
> +	init.parent_names = (parent_name ? &parent_name : NULL);
> +	init.num_parents = (parent_name ? 1 : 0);
> +	init.flags = 0;
> +
> +	periph->id = id;
> +	periph->hw.init = &init;
> +	periph->pmc = pmc;
> +
> +	clk = clk_register(NULL, &periph->hw);
> +	if (IS_ERR(clk))
> +		kfree(periph);
> +
> +	return clk;
> +}
> +
> +static int clk_sam9x5_peripheral_enable(struct clk_hw *hw)
> +{
> +	struct clk_sam9x5_peripheral *periph = to_clk_sam9x5_peripheral(hw);
> +	struct at91_pmc *pmc = periph->pmc;
> +
> +	if (periph->id < 2)
> +		return 0;
> +	pmc_write(pmc, AT91_PMC_PCR,
> +		       (periph->id & AT91_PMC_PCR_PID) |
> +		       AT91_PMC_PCR_CMD |
> +		       AT91_PMC_PCR_DIV(periph->div) |
> +		       AT91_PMC_PCR_EN);
> +	return 0;
> +}
> +
> +static void clk_sam9x5_peripheral_disable(struct clk_hw *hw)
> +{
> +	struct clk_sam9x5_peripheral *periph = to_clk_sam9x5_peripheral(hw);
> +	struct at91_pmc *pmc = periph->pmc;
> +
> +	if (periph->id < 2)
> +		return;
> +
> +	pmc_write(pmc, AT91_PMC_PCR,
> +		       (periph->id & AT91_PMC_PCR_PID) |
> +		       AT91_PMC_PCR_CMD);
> +}
> +
> +static int clk_sam9x5_peripheral_is_enabled(struct clk_hw *hw)
> +{
> +	struct clk_sam9x5_peripheral *periph = to_clk_sam9x5_peripheral(hw);
> +	struct at91_pmc *pmc = periph->pmc;
> +	int ret;
> +
> +	if (periph->id < 2)
> +		return 1;
> +	pmc_lock(pmc);
> +	pmc_write(pmc, AT91_PMC_PCR,
> +		  (periph->id & AT91_PMC_PCR_PID));
> +	ret = !!(pmc_read(pmc, AT91_PMC_PCR) & AT91_PMC_PCR_EN);
> +	pmc_unlock(pmc);
> +
> +	return ret;
> +}
> +
> +static unsigned long
> +clk_sam9x5_peripheral_recalc_rate(struct clk_hw *hw,
> +				  unsigned long parent_rate)
> +{
> +	struct clk_sam9x5_peripheral *periph = to_clk_sam9x5_peripheral(hw);
> +	struct at91_pmc *pmc = periph->pmc;
> +	u32 shift;
> +
> +	if (periph->id < 2 || !periph->have_div_support)
> +		return parent_rate;
> +	pmc_lock(pmc);
> +	pmc_write(pmc, AT91_PMC_PCR,
> +		       (periph->id & AT91_PMC_PCR_PID));
> +	shift = (pmc_read(pmc, AT91_PMC_PCR) >> 16) & 0x3;

define constants

> +	pmc_unlock(pmc);
> +	return parent_rate >> shift;
> +}
> +
> +static long clk_sam9x5_peripheral_round_rate(struct clk_hw *hw,
> +					     unsigned long rate,
> +					     unsigned long *parent_rate)
> +{
> +	int shift;
> +	unsigned long best_rate;
> +	unsigned long best_diff;
> +	unsigned long cur_rate;
> +	unsigned long cur_diff;
> +	struct clk_sam9x5_peripheral *periph = to_clk_sam9x5_peripheral(hw);
> +
> +	if (periph->id < 2 || !periph->have_div_support)
> +		return *parent_rate;
> +	if (rate >= *parent_rate)
> +		return rate;
> +	best_diff = *parent_rate - rate;
> +	best_rate = *parent_rate;
> +	for (shift = 1; shift < 4; shift++) {
> +		cur_rate = *parent_rate >> shift;
> +		if (cur_rate < rate)
> +			cur_diff = rate - cur_rate;
> +		else
> +			cur_diff = cur_rate - rate;
> +		if (cur_diff < best_diff) {
> +			best_diff = cur_diff;
> +			best_rate = cur_rate;
> +		}
> +		if (!best_diff || cur_rate < rate)
> +			break;
> +	}
> +	return best_rate;
> +}
> +
> +static int clk_sam9x5_peripheral_set_rate(struct clk_hw *hw,
> +					  unsigned long rate,
> +					  unsigned long parent_rate)
> +{
> +	int shift;
> +	struct clk_sam9x5_peripheral *periph = to_clk_sam9x5_peripheral(hw);
> +	if (periph->id < 2 || !periph->have_div_support) {
> +		if (parent_rate == rate)
> +			return 0;
> +		else
> +			return -EINVAL;
> +	}
> +
> +	for (shift = 0; shift < 4; shift++) {
> +		if (parent_rate >> shift == rate) {
> +			periph->div = shift;
> +			return 0;
> +		}
> +	}
> +
> +	return -EINVAL;
> +}
> +
> +static const struct clk_ops sam9x5_peripheral_ops = {
> +	.enable = clk_sam9x5_peripheral_enable,
> +	.disable = clk_sam9x5_peripheral_disable,
> +	.is_enabled = clk_sam9x5_peripheral_is_enabled,
> +	.recalc_rate = clk_sam9x5_peripheral_recalc_rate,
> +	.round_rate = clk_sam9x5_peripheral_round_rate,
> +	.set_rate = clk_sam9x5_peripheral_set_rate,
> +};
> +
> +static struct clk * __init
> +at91_clk_register_sam9x5_peripheral(struct at91_pmc *pmc, const char *name,
> +				    const char *parent_name, u32 id,
> +				    u32 default_div)
> +{
> +	struct clk_sam9x5_peripheral *periph;
> +	struct clk *clk = NULL;
> +	struct clk_init_data init;
> +
> +	if (!pmc || !name || !parent_name)
> +		return ERR_PTR(-EINVAL);
> +
> +	periph = kzalloc(sizeof(*periph), GFP_KERNEL);
> +	if (!periph)
> +		return ERR_PTR(-ENOMEM);
> +
> +	init.name = name;
> +	init.ops = &sam9x5_peripheral_ops;
> +	init.parent_names = (parent_name ? &parent_name : NULL);
> +	init.num_parents = (parent_name ? 1 : 0);
> +	init.flags = CLK_SET_RATE_GATE;
> +
> +	periph->id = id;
> +	periph->hw.init = &init;
> +	periph->div = default_div;
> +	periph->pmc = pmc;
> +
> +	clk = clk_register(NULL, &periph->hw);
> +

Ditto

> +	if (IS_ERR(clk))
> +		kfree(periph);
> +
> +	return clk;
> +}
> +
> +struct clk_periph_data {
> +	struct clk **clks;
> +	u8 *ids;
> +	unsigned int clk_num;
> +};
> +
> +static struct clk * __init
> +of_clk_src_periph_get(struct of_phandle_args *clkspec, void *data)
> +{
> +	struct clk_periph_data *clk_data = data;
> +	unsigned int id = clkspec->args[0];
> +	int i;
> +
> +	if (id >= PERIPHERAL_MAX)
> +		goto err;
> +
> +	for (i = 0; i < clk_data->clk_num; i++) {
> +		if (clk_data->ids[i] == id)
> +			return clk_data->clks[i];
> +	}
> +
> +err:
> +	pr_err("%s: invalid clock id %d\n", __func__, id);
> +	return ERR_PTR(-EINVAL);
> +}
> +
> +static void __init
> +of_at91_clk_periph_setup(struct device_node *np, struct at91_pmc *pmc, u8 type)
> +{
> +	int num;
> +	int i;
> +	u32 id;
> +	struct clk *clk;
> +	const char *parent_name;
> +	const char *name;
> +	u32 divisor;
> +	struct clk **clks;
> +	u8 *ids;
> +	struct clk_periph_data *clktab;
> +	struct device_node *periphclknp;
> +
> +	parent_name = of_clk_get_parent_name(np, 0);
> +	if (!parent_name)
> +		return;
> +
> +	num = of_get_child_count(np);
> +	if (!num || num > PERIPHERAL_MAX)
> +		return;
> +
> +	clktab = kzalloc(sizeof(*clktab), GFP_KERNEL);
> +	if (!clktab)
> +		return;
> +
> +	ids = kzalloc(num * sizeof(*ids), GFP_KERNEL);
> +	if (!ids)
> +		goto out_free_clktab;
> +
> +	clks = kzalloc(num * sizeof(*clks), GFP_KERNEL);
> +	if (!clks)
> +		goto out_free_ids;
> +
> +	i = 0;
> +	for_each_child_of_node(np, periphclknp) {
> +		name = periphclknp->name;
> +
> +		if (of_property_read_u32(periphclknp, "atmel,clk-id", &id))
> +			goto out_free_clks;
> +		if (id >= PERIPHERAL_MAX)
> +			goto out_free_clks;
> +
> +		if (type == PERIPHERAL_AT91RM9200) {
> +			clk = at91_clk_register_peripheral(pmc, name,
> +							   parent_name, id);
> +		} else {
> +			if (of_property_read_u32(periphclknp,
> +						 "atmel,clk-default-divisor",
> +						 &divisor))
> +				divisor = 0;
> +
> +			clk = at91_clk_register_sam9x5_peripheral(pmc, name,
> +								  parent_name,
> +								  id,
> +								  divisor);
> +		}
> +		if (IS_ERR(clk))
> +			goto out_free_clks;
> +
> +		clks[i] = clk;
> +		ids[i++] = id;
> +	}
> +
> +	clktab->clk_num = num;
> +	clktab->clks = clks;
> +	clktab->ids = ids;
> +	of_clk_add_provider(np, of_clk_src_periph_get, clktab);
> +	return;
> +
> +out_free_clks:
> +	kfree(clks);
> +out_free_ids:
> +	kfree(ids);
> +out_free_clktab:
> +	kfree(clktab);
> +}
> +
> +void __init of_at91rm9200_clk_periph_setup(struct device_node *np,
> +					   struct at91_pmc *pmc)
> +{
> +	of_at91_clk_periph_setup(np, pmc, PERIPHERAL_AT91RM9200);
> +}
> +
> +void __init of_at91sam9x5_clk_periph_setup(struct device_node *np,
> +					   struct at91_pmc *pmc)
> +{
> +	of_at91_clk_periph_setup(np, pmc, PERIPHERAL_AT91SAM9X5);
> +}
> diff --git a/drivers/clk/at91/pmc.c b/drivers/clk/at91/pmc.c
> index c674ef2..1a56f1c 100644
> --- a/drivers/clk/at91/pmc.c
> +++ b/drivers/clk/at91/pmc.c
> @@ -256,6 +256,15 @@ static const struct of_device_id pmc_clk_ids[] __initdata = {
>   		.compatible = "atmel,at91rm9200-clk-system",
>   		.data = of_at91rm9200_clk_sys_setup,
>   	},
> +	/* Peripheral clocks */
> +	{
> +		.compatible = "atmel,at91rm9200-clk-peripheral",
> +		.data = of_at91rm9200_clk_periph_setup,
> +	},
> +	{
> +		.compatible = "atmel,at91sam9x5-clk-peripheral",
> +		.data = of_at91sam9x5_clk_periph_setup,
> +	},
>   	{ /*sentinel*/ }
>   };
>
> diff --git a/drivers/clk/at91/pmc.h b/drivers/clk/at91/pmc.h
> index f88ef41..08c30fb 100644
> --- a/drivers/clk/at91/pmc.h
> +++ b/drivers/clk/at91/pmc.h
> @@ -77,4 +77,9 @@ extern void __init of_at91sam9x5_clk_master_setup(struct device_node *np,
>   extern void __init of_at91rm9200_clk_sys_setup(struct device_node *np,
>   					       struct at91_pmc *pmc);
>
> +extern void __init of_at91rm9200_clk_periph_setup(struct device_node *np,
> +						  struct at91_pmc *pmc);
> +extern void __init of_at91sam9x5_clk_periph_setup(struct device_node *np,
> +						  struct at91_pmc *pmc);
> +
>   #endif /* __PMC_H_ */
>


-- 
Nicolas Ferre

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

* Re: [PATCH v3 12/19] clk: at91: add peripheral clk macros for peripheral clk dt bindings
  2013-08-08  7:10 ` [PATCH v3 12/19] clk: at91: add peripheral clk macros for peripheral clk dt bindings Boris BREZILLON
@ 2013-10-08 15:44   ` Nicolas Ferre
  2013-10-08 16:01     ` boris brezillon
  0 siblings, 1 reply; 54+ messages in thread
From: Nicolas Ferre @ 2013-10-08 15:44 UTC (permalink / raw)
  To: Boris BREZILLON, Grant Likely, Rob Herring, Rob Landley,
	Andrew Victor, Jean-Christophe Plagniol-Villard, Russell King,
	Mike Turquette, Felipe Balbi, Greg Kroah-Hartman,
	Ludovic Desroches, Josh Wu, Richard Genoud
  Cc: devicetree, linux-kernel, linux-arm-kernel

On 08/08/2013 09:10, Boris BREZILLON :
> This patch adds the peripheral divisors macros (for sam9x5 compatible IPs)
> which will be used by peripheral clk dt definitions.

I am in favor for these definitions. So let's keep them (with raw 
numbers toguether with these macros in documentation).

>
> Signed-off-by: Boris BREZILLON <b.brezillon@overkiz.com>
> ---
>   .../clk/at91/at91sam9x5/clk-peripheral.h           |   15 +++++++++++++++
>   1 file changed, 15 insertions(+)
>   create mode 100644 include/dt-bindings/clk/at91/at91sam9x5/clk-peripheral.h
>
> diff --git a/include/dt-bindings/clk/at91/at91sam9x5/clk-peripheral.h b/include/dt-bindings/clk/at91/at91sam9x5/clk-peripheral.h
> new file mode 100644
> index 0000000..a6dd506
> --- /dev/null
> +++ b/include/dt-bindings/clk/at91/at91sam9x5/clk-peripheral.h
> @@ -0,0 +1,15 @@
> +/*
> + * This header provides constants for AT91 peripheral clks.
> + *
> + * The constants defined in this header are being used in dts.
> + */
> +
> +#ifndef _DT_BINDINGS_CLK_AT91SAM9X5_PERIPH_H
> +#define _DT_BINDINGS_CLK_AT91SAM9X5_PERIPH_H
> +
> +#define AT91SAM9X5_PERIPH_CLK_DIV1	0
> +#define AT91SAM9X5_PERIPH_CLK_DIV2	1
> +#define AT91SAM9X5_PERIPH_CLK_DIV4	2
> +#define AT91SAM9X5_PERIPH_CLK_DIV8	3
> +
> +#endif
>


-- 
Nicolas Ferre

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

* Re: [PATCH v3 12/19] clk: at91: add peripheral clk macros for peripheral clk dt bindings
  2013-10-08 15:44   ` Nicolas Ferre
@ 2013-10-08 16:01     ` boris brezillon
  2013-10-08 16:15       ` Nicolas Ferre
  0 siblings, 1 reply; 54+ messages in thread
From: boris brezillon @ 2013-10-08 16:01 UTC (permalink / raw)
  To: Nicolas Ferre, Grant Likely, Rob Herring, Rob Landley,
	Andrew Victor, Jean-Christophe Plagniol-Villard, Russell King,
	Mike Turquette, Felipe Balbi, Greg Kroah-Hartman,
	Ludovic Desroches, Josh Wu, Richard Genoud
  Cc: devicetree, linux-kernel, linux-arm-kernel

On 08/10/2013 17:44, Nicolas Ferre wrote:
> On 08/08/2013 09:10, Boris BREZILLON :
>> This patch adds the peripheral divisors macros (for sam9x5 compatible 
>> IPs)
>> which will be used by peripheral clk dt definitions.
>
> I am in favor for these definitions. So let's keep them (with raw 
> numbers toguether with these macros in documentation).

I guess we should move them elsewhere if these are the only macros we keep.

What about "include/dt-bindings/clk/at91sam9x5-periph.h" ?
>
>>
>> Signed-off-by: Boris BREZILLON <b.brezillon@overkiz.com>
>> ---
>>   .../clk/at91/at91sam9x5/clk-peripheral.h           |   15 
>> +++++++++++++++
>>   1 file changed, 15 insertions(+)
>>   create mode 100644 
>> include/dt-bindings/clk/at91/at91sam9x5/clk-peripheral.h
>>
>> diff --git a/include/dt-bindings/clk/at91/at91sam9x5/clk-peripheral.h 
>> b/include/dt-bindings/clk/at91/at91sam9x5/clk-peripheral.h
>> new file mode 100644
>> index 0000000..a6dd506
>> --- /dev/null
>> +++ b/include/dt-bindings/clk/at91/at91sam9x5/clk-peripheral.h
>> @@ -0,0 +1,15 @@
>> +/*
>> + * This header provides constants for AT91 peripheral clks.
>> + *
>> + * The constants defined in this header are being used in dts.
>> + */
>> +
>> +#ifndef _DT_BINDINGS_CLK_AT91SAM9X5_PERIPH_H
>> +#define _DT_BINDINGS_CLK_AT91SAM9X5_PERIPH_H
>> +
>> +#define AT91SAM9X5_PERIPH_CLK_DIV1    0
>> +#define AT91SAM9X5_PERIPH_CLK_DIV2    1
>> +#define AT91SAM9X5_PERIPH_CLK_DIV4    2
>> +#define AT91SAM9X5_PERIPH_CLK_DIV8    3
>> +
>> +#endif
>>
>
>


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

* Re: [PATCH v3 13/19] clk: at91: add PMC programmable clocks
  2013-08-08  7:12 ` [PATCH v3 13/19] clk: at91: add PMC programmable clocks Boris BREZILLON
@ 2013-10-08 16:02   ` Nicolas Ferre
  2013-10-08 16:06     ` Nicolas Ferre
  0 siblings, 1 reply; 54+ messages in thread
From: Nicolas Ferre @ 2013-10-08 16:02 UTC (permalink / raw)
  To: Boris BREZILLON, Grant Likely, Rob Herring, Rob Landley,
	Andrew Victor, Jean-Christophe Plagniol-Villard, Russell King,
	Mike Turquette, Felipe Balbi, Greg Kroah-Hartman,
	Ludovic Desroches, Josh Wu, Richard Genoud
  Cc: devicetree, linux-kernel, linux-arm-kernel

On 08/08/2013 09:12, Boris BREZILLON :
> This patch adds new at91 programmable clocks implementation using common clk
> framework.
> A programmable clock is a clock which can be exported on a given pin to clock
> external devices.
> Each programmable clock is given an id (from 0 to 8).
> The number of available programmable clocks depends on the SoC you're using.
> Programmable clock driver only implements the clock setting (clock rate and
> parent setting). It must be chained to a system clock in order to
> enable/disable the generated clock.
> The PCKX pins used to output the clock signals must be assigned to the
> appropriate peripheral (see atmel's datasheets).
>
> Signed-off-by: Boris BREZILLON <b.brezillon@overkiz.com>
> ---
>   drivers/clk/at91/Makefile           |    2 +
>   drivers/clk/at91/clk-programmable.c |  419 +++++++++++++++++++++++++++++++++++
>   drivers/clk/at91/pmc.c              |   15 ++
>   drivers/clk/at91/pmc.h              |    9 +
>   4 files changed, 445 insertions(+)
>   create mode 100644 drivers/clk/at91/clk-programmable.c
>
> diff --git a/drivers/clk/at91/Makefile b/drivers/clk/at91/Makefile
> index 04deba3..3873b62 100644
> --- a/drivers/clk/at91/Makefile
> +++ b/drivers/clk/at91/Makefile
> @@ -5,3 +5,5 @@
>   obj-y += pmc.o
>   obj-y += clk-main.o clk-pll.o clk-plldiv.o clk-master.o
>   obj-y += clk-system.o clk-peripheral.o
> +
> +obj-$(CONFIG_AT91_PROGRAMMABLE_CLOCKS)	+= clk-programmable.o
> diff --git a/drivers/clk/at91/clk-programmable.c b/drivers/clk/at91/clk-programmable.c
> new file mode 100644
> index 0000000..f40de6a
> --- /dev/null
> +++ b/drivers/clk/at91/clk-programmable.c
> @@ -0,0 +1,419 @@
> +/*
> + * drivers/clk/at91/clk-programmable.c
> + *
> + *  Copyright (C) 2013 Boris BREZILLON <b.brezillon@overkiz.com>
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License as published by
> + * the Free Software Foundation; either version 2 of the License, or
> + * (at your option) any later version.
> + *
> + */
> +
> +#include <linux/clk-provider.h>
> +#include <linux/clkdev.h>
> +#include <linux/clk/at91_pmc.h>
> +#include <linux/of.h>
> +#include <linux/of_address.h>
> +#include <linux/of_irq.h>
> +#include <linux/io.h>
> +#include <linux/wait.h>
> +#include <linux/sched.h>
> +#include <linux/interrupt.h>
> +#include <linux/irq.h>
> +
> +#include "pmc.h"
> +
> +#define PROG_SOURCE_MAX		5
> +#define PROG_MAX		8
> +
> +struct clk_programmable_layout {
> +	u8 pres_shift;
> +	u8 css_mask;
> +	u8 have_slck_mck;
> +};
> +
> +#define to_clk_programmable(hw) container_of(hw, struct clk_programmable, hw)
> +struct clk_programmable {
> +	struct clk_hw hw;
> +	struct at91_pmc *pmc;
> +	unsigned int irq;
> +	wait_queue_head_t wait;
> +	u8 id;
> +	u8 css;
> +	u8 pres;
> +	u8 slckmck;
> +	const struct clk_programmable_layout *layout;
> +};
> +
> +static irqreturn_t clk_programmable_irq_handler(int irq, void *dev_id)
> +{
> +	struct clk_programmable *prog = (struct clk_programmable *)dev_id;
> +
> +	wake_up(&prog->wait);
> +
> +	return IRQ_HANDLED;
> +}
> +
> +static int clk_programmable_prepare(struct clk_hw *hw)
> +{
> +	u32 tmp;
> +	struct clk_programmable *prog = to_clk_programmable(hw);
> +	struct at91_pmc *pmc = prog->pmc;
> +	const struct clk_programmable_layout *layout = prog->layout;
> +
> +	tmp = prog->css | (prog->pres << layout->pres_shift);
> +	if (layout->have_slck_mck && prog->slckmck)
> +		tmp |= 1 << 8;

;-) => define constants

> +
> +	pmc_write(pmc, AT91_PMC_PCKR(prog->id), tmp);
> +
> +	while (!(pmc_read(pmc, AT91_PMC_SR) & (1 << (prog->id + 8))))

- create a macro
- is creating an event for each iteration of the while loop a good idea?
- for the while() loop, I would like a timeout and a a non-active wait 
function...

> +		wait_event(prog->wait,
> +			   pmc_read(pmc, AT91_PMC_SR) & (1 << (prog->id + 8)));
> +
> +	return 0;
> +}
> +
> +static int clk_programmable_is_ready(struct clk_hw *hw)
> +{
> +	struct clk_programmable *prog = to_clk_programmable(hw);
> +	struct at91_pmc *pmc = prog->pmc;
> +
> +	return !!(pmc_read(pmc, AT91_PMC_SR) & (1 << (prog->id + 8)));

Ditto

> +}
> +
> +static unsigned long clk_programmable_recalc_rate(struct clk_hw *hw,
> +						  unsigned long parent_rate)
> +{
> +	u32 tmp;
> +	struct clk_programmable *prog = to_clk_programmable(hw);
> +	struct at91_pmc *pmc = prog->pmc;
> +	const struct clk_programmable_layout *layout = prog->layout;
> +
> +	tmp = pmc_read(pmc, AT91_PMC_PCKR(prog->id));
> +	prog->pres = (tmp >> layout->pres_shift) & 0x7;

define constants

> +
> +	return parent_rate >> prog->pres;
> +}
> +
> +static long clk_programmable_round_rate(struct clk_hw *hw, unsigned long rate,
> +					unsigned long *parent_rate)
> +{
> +	unsigned long best_rate = *parent_rate;
> +	unsigned long best_diff;
> +	unsigned long new_diff;
> +	unsigned long cur_rate;
> +	int shift = shift;
> +
> +	if (rate > *parent_rate)
> +		return *parent_rate;
> +	else
> +		best_diff = *parent_rate - rate;
> +
> +	if (!best_diff)
> +		return best_rate;
> +
> +	for (shift = 1; shift < 7; shift++) {

Ditto

> +		cur_rate = *parent_rate >> shift;
> +
> +		if (cur_rate > rate)
> +			new_diff = cur_rate - rate;
> +		else
> +			new_diff = rate - cur_rate;
> +
> +		if (!new_diff)
> +			return cur_rate;
> +
> +		if (new_diff < best_diff) {
> +			best_diff = new_diff;
> +			best_rate = cur_rate;
> +		}
> +
> +		if (rate > cur_rate)
> +			break;
> +
> +	}
> +
> +	return best_rate;
> +}
> +
> +static int clk_programmable_set_parent(struct clk_hw *hw, u8 index)
> +{
> +	struct clk_programmable *prog = to_clk_programmable(hw);
> +	const struct clk_programmable_layout *layout = prog->layout;
> +	if (index > layout->css_mask) {
> +		if (index == 4 && layout->have_slck_mck) {

define "4"

> +			prog->css = 0;
> +			prog->slckmck = 1;
> +			return 0;
> +		} else

Style: add the "{"

> +			return -EINVAL;

and "}"

> +	}
> +
> +	prog->css = index;
> +	return 0;
> +}
> +
> +static u8 clk_programmable_get_parent(struct clk_hw *hw)
> +{
> +	u32 tmp;
> +	u8 ret;
> +	struct clk_programmable *prog = to_clk_programmable(hw);
> +	struct at91_pmc *pmc = prog->pmc;
> +	const struct clk_programmable_layout *layout = prog->layout;
> +
> +	tmp = pmc_read(pmc, AT91_PMC_PCKR(prog->id));
> +	prog->css = tmp & layout->css_mask;
> +	ret = prog->css;
> +	if (layout->have_slck_mck) {
> +		prog->slckmck = !!(tmp & (1 << 8));

Ditto

> +		if (prog->slckmck && !ret)
> +			ret = 4;

Ditto

> +	}
> +
> +	return ret;
> +}
> +
> +static int clk_programmable_set_rate(struct clk_hw *hw, unsigned long rate,
> +				     unsigned long parent_rate)
> +{
> +	struct clk_programmable *prog = to_clk_programmable(hw);
> +	unsigned long best_rate = parent_rate;
> +	unsigned long best_diff;
> +	unsigned long new_diff;
> +	unsigned long cur_rate;
> +	int shift = 0;
> +
> +	if (rate > parent_rate)
> +		return parent_rate;
> +	else
> +		best_diff = parent_rate - rate;
> +
> +	if (!best_diff) {
> +		prog->pres = shift;
> +		return 0;
> +	}
> +
> +	for (shift = 1; shift < 7; shift++) {

Ditto

> +		cur_rate = parent_rate >> shift;
> +
> +		if (cur_rate > rate)
> +			new_diff = cur_rate - rate;
> +		else
> +			new_diff = rate - cur_rate;
> +
> +		if (!new_diff)
> +			break;
> +
> +		if (new_diff < best_diff) {
> +			best_diff = new_diff;
> +			best_rate = cur_rate;
> +		}
> +
> +		if (rate > cur_rate)
> +			break;
> +
> +	}
> +
> +	prog->pres = shift;
> +	return 0;
> +}
> +
> +static const struct clk_ops programmable_ops = {
> +	.prepare = clk_programmable_prepare,
> +	.is_prepared = clk_programmable_is_ready,
> +	.recalc_rate = clk_programmable_recalc_rate,
> +	.round_rate = clk_programmable_round_rate,
> +	.get_parent = clk_programmable_get_parent,
> +	.set_parent = clk_programmable_set_parent,
> +	.set_rate = clk_programmable_set_rate,
> +};
> +
> +static struct clk * __init
> +at91_clk_register_programmable(struct at91_pmc *pmc, unsigned int irq,
> +			       const char *name, const char **parent_names,
> +			       u8 num_parents, u8 id,
> +			       const struct clk_programmable_layout *layout)
> +{
> +	int ret;
> +	struct clk_programmable *prog;
> +	struct clk *clk = NULL;
> +	struct clk_init_data init;
> +	char irq_name[11];
> +
> +	id &= 7;

Ditto

> +
> +	prog = kzalloc(sizeof(*prog), GFP_KERNEL);
> +	if (!prog)
> +		return ERR_PTR(-ENOMEM);
> +
> +	init.name = name;
> +	init.ops = &programmable_ops;
> +	init.parent_names = parent_names;
> +	init.num_parents = num_parents;
> +	init.flags = CLK_SET_RATE_GATE | CLK_SET_PARENT_GATE;
> +
> +	prog->id = id;
> +	prog->layout = layout;
> +	prog->hw.init = &init;
> +	prog->pmc = pmc;
> +	prog->irq = irq;
> +	init_waitqueue_head(&prog->wait);
> +	irq_set_status_flags(prog->irq, IRQ_NOAUTOEN);
> +	snprintf(irq_name, sizeof(irq_name), "clk-prog%d", id);
> +	ret = request_irq(prog->irq, clk_programmable_irq_handler,
> +			  IRQF_TRIGGER_HIGH, irq_name, prog);
> +	if (ret)
> +		return ERR_PTR(ret);
> +
> +	clk = clk_register(NULL, &prog->hw);
> +

^^

> +	if (IS_ERR(clk))
> +		kfree(prog);
> +
> +	return clk;
> +}
> +
> +static const struct clk_programmable_layout at91rm9200_programmable_layout = {
> +	.pres_shift = 2,
> +	.css_mask = 0x3,
> +	.have_slck_mck = 0,
> +};
> +
> +static const struct clk_programmable_layout at91sam9g45_programmable_layout = {
> +	.pres_shift = 2,
> +	.css_mask = 0x3,
> +	.have_slck_mck = 1,
> +};
> +
> +static const struct clk_programmable_layout at91sam9x5_programmable_layout = {
> +	.pres_shift = 4,
> +	.css_mask = 0x7,
> +	.have_slck_mck = 0,
> +};
> +
> +struct clk_prog_data {
> +	struct clk **clks;
> +	u8 *ids;
> +	unsigned int clk_num;
> +};
> +
> +static struct clk * __init
> +of_clk_src_periph_get(struct of_phandle_args *clkspec, void *data)
> +{
> +	struct clk_prog_data *clk_data = data;
> +	unsigned int id = clkspec->args[0];
> +	int i;
> +
> +	if (id >= PROG_MAX)
> +		goto err;
> +
> +	for (i = 0; i < clk_data->clk_num; i++) {
> +		if (clk_data->ids[i] == id)
> +			return clk_data->clks[i];
> +	}
> +
> +err:
> +	pr_err("%s: invalid clock id %d\n", __func__, id);
> +	return ERR_PTR(-EINVAL);
> +}
> +
> +static void __init
> +of_at91_clk_prog_setup(struct device_node *np, struct at91_pmc *pmc,
> +		       const struct clk_programmable_layout *layout)
> +{
> +	int num;
> +	u32 id;
> +	int i;
> +	unsigned int irq;
> +	struct clk *clk;
> +	int num_parents;
> +	u8 *ids;
> +	struct clk **clks;
> +	struct clk_prog_data *clktab;
> +	const char *parent_names[PROG_SOURCE_MAX];
> +	const char *name;
> +	struct device_node *progclknp;
> +
> +	num_parents = of_count_phandle_with_args(np, "clocks", "#clock-cells");
> +	if (num_parents <= 0 || num_parents > PROG_SOURCE_MAX)
> +		return;
> +
> +	for (i = 0; i < num_parents; ++i) {
> +		parent_names[i] = of_clk_get_parent_name(np, i);
> +		if (!parent_names[i])
> +			return;
> +	}
> +
> +	num = of_get_child_count(np);
> +	if (!num || num > PROG_MAX)
> +		return;
> +
> +	clktab = kzalloc(sizeof(*clktab), GFP_KERNEL);
> +	if (!clktab)
> +		return;
> +
> +	ids = kzalloc(num * sizeof(*ids), GFP_KERNEL);
> +	if (!ids)
> +		goto out_free_clktab;
> +
> +	clks = kzalloc(num * sizeof(*clks), GFP_KERNEL);
> +	if (!clks)
> +		goto out_free_ids;
> +
> +	i = 0;
> +	for_each_child_of_node(np, progclknp) {
> +		name = progclknp->name;
> +
> +		if (of_property_read_u32(progclknp, "atmel,clk-id", &id))
> +			goto out_free_clks;
> +		if (id >= PROG_MAX)
> +			goto out_free_clks;
> +
> +		irq = irq_of_parse_and_map(np, 0);
> +		if (!irq)
> +			goto out_free_clks;
> +
> +		clk = at91_clk_register_programmable(pmc, irq, name,
> +						     parent_names, num_parents,
> +						     id, layout);
> +		if (IS_ERR(clk))
> +			goto out_free_clks;
> +
> +		clks[i] = clk;
> +		ids[i++] = id;
> +	}
> +
> +	clktab->clk_num = num;
> +	clktab->clks = clks;
> +	clktab->ids = ids;
> +	of_clk_add_provider(np, of_clk_src_periph_get, clktab);
> +	return;
> +
> +out_free_clks:
> +	kfree(clks);
> +out_free_ids:
> +	kfree(ids);
> +out_free_clktab:
> +	kfree(clktab);
> +}
> +
> +
> +void __init of_at91rm9200_clk_prog_setup(struct device_node *np,
> +					 struct at91_pmc *pmc)
> +{
> +	of_at91_clk_prog_setup(np, pmc, &at91rm9200_programmable_layout);
> +}
> +
> +void __init of_at91sam9g45_clk_prog_setup(struct device_node *np,
> +					  struct at91_pmc *pmc)
> +{
> +	of_at91_clk_prog_setup(np, pmc, &at91sam9g45_programmable_layout);
> +}
> +
> +void __init of_at91sam9x5_clk_prog_setup(struct device_node *np,
> +					 struct at91_pmc *pmc)
> +{
> +	of_at91_clk_prog_setup(np, pmc, &at91sam9x5_programmable_layout);
> +}
> diff --git a/drivers/clk/at91/pmc.c b/drivers/clk/at91/pmc.c
> index 1a56f1c..66a627d 100644
> --- a/drivers/clk/at91/pmc.c
> +++ b/drivers/clk/at91/pmc.c
> @@ -265,6 +265,21 @@ static const struct of_device_id pmc_clk_ids[] __initdata = {
>   		.compatible = "atmel,at91sam9x5-clk-peripheral",
>   		.data = of_at91sam9x5_clk_periph_setup,
>   	},
> +	/* Programmable clocks */
> +#if defined(CONFIG_AT91_PROGRAMMABLE_CLOCKS)
> +	{
> +		.compatible = "atmel,at91rm9200-clk-programmable",
> +		.data = of_at91rm9200_clk_prog_setup,
> +	},
> +	{
> +		.compatible = "atmel,at91sam9g45-clk-programmable",
> +		.data = of_at91sam9g45_clk_prog_setup,
> +	},
> +	{
> +		.compatible = "atmel,at91sam9x5-clk-programmable",
> +		.data = of_at91sam9x5_clk_prog_setup,
> +	},
> +#endif
>   	{ /*sentinel*/ }
>   };
>
> diff --git a/drivers/clk/at91/pmc.h b/drivers/clk/at91/pmc.h
> index 08c30fb..5f20dc1 100644
> --- a/drivers/clk/at91/pmc.h
> +++ b/drivers/clk/at91/pmc.h
> @@ -82,4 +82,13 @@ extern void __init of_at91rm9200_clk_periph_setup(struct device_node *np,
>   extern void __init of_at91sam9x5_clk_periph_setup(struct device_node *np,
>   						  struct at91_pmc *pmc);
>
> +#if defined(CONFIG_AT91_PROGRAMMABLE_CLOCKS)
> +extern void __init of_at91rm9200_clk_prog_setup(struct device_node *np,
> +						struct at91_pmc *pmc);
> +extern void __init of_at91sam9g45_clk_prog_setup(struct device_node *np,
> +						 struct at91_pmc *pmc);
> +extern void __init of_at91sam9x5_clk_prog_setup(struct device_node *np,
> +						struct at91_pmc *pmc);
> +#endif
> +
>   #endif /* __PMC_H_ */
>


-- 
Nicolas Ferre

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

* Re: [PATCH v3 13/19] clk: at91: add PMC programmable clocks
  2013-10-08 16:02   ` Nicolas Ferre
@ 2013-10-08 16:06     ` Nicolas Ferre
  0 siblings, 0 replies; 54+ messages in thread
From: Nicolas Ferre @ 2013-10-08 16:06 UTC (permalink / raw)
  To: Nicolas Ferre, Boris BREZILLON, Grant Likely, Rob Herring,
	Rob Landley, Andrew Victor, Jean-Christophe Plagniol-Villard,
	Russell King, Mike Turquette, Felipe Balbi, Greg Kroah-Hartman,
	Ludovic Desroches, Josh Wu, Richard Genoud
  Cc: devicetree, linux-kernel, linux-arm-kernel

On 08/10/2013 18:02, Nicolas Ferre :
> On 08/08/2013 09:12, Boris BREZILLON :
>> This patch adds new at91 programmable clocks implementation using common clk
>> framework.
>> A programmable clock is a clock which can be exported on a given pin to clock
>> external devices.
>> Each programmable clock is given an id (from 0 to 8).
>> The number of available programmable clocks depends on the SoC you're using.
>> Programmable clock driver only implements the clock setting (clock rate and
>> parent setting). It must be chained to a system clock in order to
>> enable/disable the generated clock.
>> The PCKX pins used to output the clock signals must be assigned to the
>> appropriate peripheral (see atmel's datasheets).
>>
>> Signed-off-by: Boris BREZILLON <b.brezillon@overkiz.com>
>> ---
>>    drivers/clk/at91/Makefile           |    2 +
>>    drivers/clk/at91/clk-programmable.c |  419 +++++++++++++++++++++++++++++++++++
>>    drivers/clk/at91/pmc.c              |   15 ++
>>    drivers/clk/at91/pmc.h              |    9 +
>>    4 files changed, 445 insertions(+)
>>    create mode 100644 drivers/clk/at91/clk-programmable.c
>>
>> diff --git a/drivers/clk/at91/Makefile b/drivers/clk/at91/Makefile
>> index 04deba3..3873b62 100644
>> --- a/drivers/clk/at91/Makefile
>> +++ b/drivers/clk/at91/Makefile
>> @@ -5,3 +5,5 @@
>>    obj-y += pmc.o
>>    obj-y += clk-main.o clk-pll.o clk-plldiv.o clk-master.o
>>    obj-y += clk-system.o clk-peripheral.o
>> +
>> +obj-$(CONFIG_AT91_PROGRAMMABLE_CLOCKS)	+= clk-programmable.o
>> diff --git a/drivers/clk/at91/clk-programmable.c b/drivers/clk/at91/clk-programmable.c
>> new file mode 100644
>> index 0000000..f40de6a
>> --- /dev/null
>> +++ b/drivers/clk/at91/clk-programmable.c
>> @@ -0,0 +1,419 @@
>> +/*
>> + * drivers/clk/at91/clk-programmable.c
>> + *
>> + *  Copyright (C) 2013 Boris BREZILLON <b.brezillon@overkiz.com>
>> + *
>> + * This program is free software; you can redistribute it and/or modify
>> + * it under the terms of the GNU General Public License as published by
>> + * the Free Software Foundation; either version 2 of the License, or
>> + * (at your option) any later version.
>> + *
>> + */
>> +
>> +#include <linux/clk-provider.h>
>> +#include <linux/clkdev.h>
>> +#include <linux/clk/at91_pmc.h>
>> +#include <linux/of.h>
>> +#include <linux/of_address.h>
>> +#include <linux/of_irq.h>
>> +#include <linux/io.h>
>> +#include <linux/wait.h>
>> +#include <linux/sched.h>
>> +#include <linux/interrupt.h>
>> +#include <linux/irq.h>
>> +
>> +#include "pmc.h"
>> +
>> +#define PROG_SOURCE_MAX		5
>> +#define PROG_MAX		8
>> +
>> +struct clk_programmable_layout {
>> +	u8 pres_shift;
>> +	u8 css_mask;
>> +	u8 have_slck_mck;
>> +};
>> +
>> +#define to_clk_programmable(hw) container_of(hw, struct clk_programmable, hw)
>> +struct clk_programmable {
>> +	struct clk_hw hw;
>> +	struct at91_pmc *pmc;
>> +	unsigned int irq;
>> +	wait_queue_head_t wait;
>> +	u8 id;
>> +	u8 css;
>> +	u8 pres;
>> +	u8 slckmck;
>> +	const struct clk_programmable_layout *layout;
>> +};
>> +
>> +static irqreturn_t clk_programmable_irq_handler(int irq, void *dev_id)
>> +{
>> +	struct clk_programmable *prog = (struct clk_programmable *)dev_id;
>> +
>> +	wake_up(&prog->wait);
>> +
>> +	return IRQ_HANDLED;
>> +}
>> +
>> +static int clk_programmable_prepare(struct clk_hw *hw)
>> +{
>> +	u32 tmp;
>> +	struct clk_programmable *prog = to_clk_programmable(hw);
>> +	struct at91_pmc *pmc = prog->pmc;
>> +	const struct clk_programmable_layout *layout = prog->layout;
>> +
>> +	tmp = prog->css | (prog->pres << layout->pres_shift);
>> +	if (layout->have_slck_mck && prog->slckmck)
>> +		tmp |= 1 << 8;
>
> ;-) => define constants
>
>> +
>> +	pmc_write(pmc, AT91_PMC_PCKR(prog->id), tmp);
>> +
>> +	while (!(pmc_read(pmc, AT91_PMC_SR) & (1 << (prog->id + 8))))
>
> - create a macro
> - is creating an event for each iteration of the while loop a good idea?

Oops, it is not "creating" it is "waiting" which is pretty different ;-)
So, do not consider this remark.

> - for the while() loop, I would like a timeout and a a non-active wait
> function...

Okay, this is also false: sorry for the noise.

>
>> +		wait_event(prog->wait,
>> +			   pmc_read(pmc, AT91_PMC_SR) & (1 << (prog->id + 8)));
>> +
>> +	return 0;
>> +}
>> +
>> +static int clk_programmable_is_ready(struct clk_hw *hw)
>> +{
>> +	struct clk_programmable *prog = to_clk_programmable(hw);
>> +	struct at91_pmc *pmc = prog->pmc;
>> +
>> +	return !!(pmc_read(pmc, AT91_PMC_SR) & (1 << (prog->id + 8)));
>
> Ditto
>
>> +}
>> +
>> +static unsigned long clk_programmable_recalc_rate(struct clk_hw *hw,
>> +						  unsigned long parent_rate)
>> +{
>> +	u32 tmp;
>> +	struct clk_programmable *prog = to_clk_programmable(hw);
>> +	struct at91_pmc *pmc = prog->pmc;
>> +	const struct clk_programmable_layout *layout = prog->layout;
>> +
>> +	tmp = pmc_read(pmc, AT91_PMC_PCKR(prog->id));
>> +	prog->pres = (tmp >> layout->pres_shift) & 0x7;
>
> define constants
>
>> +
>> +	return parent_rate >> prog->pres;
>> +}
>> +
>> +static long clk_programmable_round_rate(struct clk_hw *hw, unsigned long rate,
>> +					unsigned long *parent_rate)
>> +{
>> +	unsigned long best_rate = *parent_rate;
>> +	unsigned long best_diff;
>> +	unsigned long new_diff;
>> +	unsigned long cur_rate;
>> +	int shift = shift;
>> +
>> +	if (rate > *parent_rate)
>> +		return *parent_rate;
>> +	else
>> +		best_diff = *parent_rate - rate;
>> +
>> +	if (!best_diff)
>> +		return best_rate;
>> +
>> +	for (shift = 1; shift < 7; shift++) {
>
> Ditto
>
>> +		cur_rate = *parent_rate >> shift;
>> +
>> +		if (cur_rate > rate)
>> +			new_diff = cur_rate - rate;
>> +		else
>> +			new_diff = rate - cur_rate;
>> +
>> +		if (!new_diff)
>> +			return cur_rate;
>> +
>> +		if (new_diff < best_diff) {
>> +			best_diff = new_diff;
>> +			best_rate = cur_rate;
>> +		}
>> +
>> +		if (rate > cur_rate)
>> +			break;
>> +
>> +	}
>> +
>> +	return best_rate;
>> +}
>> +
>> +static int clk_programmable_set_parent(struct clk_hw *hw, u8 index)
>> +{
>> +	struct clk_programmable *prog = to_clk_programmable(hw);
>> +	const struct clk_programmable_layout *layout = prog->layout;
>> +	if (index > layout->css_mask) {
>> +		if (index == 4 && layout->have_slck_mck) {
>
> define "4"
>
>> +			prog->css = 0;
>> +			prog->slckmck = 1;
>> +			return 0;
>> +		} else
>
> Style: add the "{"
>
>> +			return -EINVAL;
>
> and "}"
>
>> +	}
>> +
>> +	prog->css = index;
>> +	return 0;
>> +}
>> +
>> +static u8 clk_programmable_get_parent(struct clk_hw *hw)
>> +{
>> +	u32 tmp;
>> +	u8 ret;
>> +	struct clk_programmable *prog = to_clk_programmable(hw);
>> +	struct at91_pmc *pmc = prog->pmc;
>> +	const struct clk_programmable_layout *layout = prog->layout;
>> +
>> +	tmp = pmc_read(pmc, AT91_PMC_PCKR(prog->id));
>> +	prog->css = tmp & layout->css_mask;
>> +	ret = prog->css;
>> +	if (layout->have_slck_mck) {
>> +		prog->slckmck = !!(tmp & (1 << 8));
>
> Ditto
>
>> +		if (prog->slckmck && !ret)
>> +			ret = 4;
>
> Ditto
>
>> +	}
>> +
>> +	return ret;
>> +}
>> +
>> +static int clk_programmable_set_rate(struct clk_hw *hw, unsigned long rate,
>> +				     unsigned long parent_rate)
>> +{
>> +	struct clk_programmable *prog = to_clk_programmable(hw);
>> +	unsigned long best_rate = parent_rate;
>> +	unsigned long best_diff;
>> +	unsigned long new_diff;
>> +	unsigned long cur_rate;
>> +	int shift = 0;
>> +
>> +	if (rate > parent_rate)
>> +		return parent_rate;
>> +	else
>> +		best_diff = parent_rate - rate;
>> +
>> +	if (!best_diff) {
>> +		prog->pres = shift;
>> +		return 0;
>> +	}
>> +
>> +	for (shift = 1; shift < 7; shift++) {
>
> Ditto
>
>> +		cur_rate = parent_rate >> shift;
>> +
>> +		if (cur_rate > rate)
>> +			new_diff = cur_rate - rate;
>> +		else
>> +			new_diff = rate - cur_rate;
>> +
>> +		if (!new_diff)
>> +			break;
>> +
>> +		if (new_diff < best_diff) {
>> +			best_diff = new_diff;
>> +			best_rate = cur_rate;
>> +		}
>> +
>> +		if (rate > cur_rate)
>> +			break;
>> +
>> +	}
>> +
>> +	prog->pres = shift;
>> +	return 0;
>> +}
>> +
>> +static const struct clk_ops programmable_ops = {
>> +	.prepare = clk_programmable_prepare,
>> +	.is_prepared = clk_programmable_is_ready,
>> +	.recalc_rate = clk_programmable_recalc_rate,
>> +	.round_rate = clk_programmable_round_rate,
>> +	.get_parent = clk_programmable_get_parent,
>> +	.set_parent = clk_programmable_set_parent,
>> +	.set_rate = clk_programmable_set_rate,
>> +};
>> +
>> +static struct clk * __init
>> +at91_clk_register_programmable(struct at91_pmc *pmc, unsigned int irq,
>> +			       const char *name, const char **parent_names,
>> +			       u8 num_parents, u8 id,
>> +			       const struct clk_programmable_layout *layout)
>> +{
>> +	int ret;
>> +	struct clk_programmable *prog;
>> +	struct clk *clk = NULL;
>> +	struct clk_init_data init;
>> +	char irq_name[11];
>> +
>> +	id &= 7;
>
> Ditto
>
>> +
>> +	prog = kzalloc(sizeof(*prog), GFP_KERNEL);
>> +	if (!prog)
>> +		return ERR_PTR(-ENOMEM);
>> +
>> +	init.name = name;
>> +	init.ops = &programmable_ops;
>> +	init.parent_names = parent_names;
>> +	init.num_parents = num_parents;
>> +	init.flags = CLK_SET_RATE_GATE | CLK_SET_PARENT_GATE;
>> +
>> +	prog->id = id;
>> +	prog->layout = layout;
>> +	prog->hw.init = &init;
>> +	prog->pmc = pmc;
>> +	prog->irq = irq;
>> +	init_waitqueue_head(&prog->wait);
>> +	irq_set_status_flags(prog->irq, IRQ_NOAUTOEN);
>> +	snprintf(irq_name, sizeof(irq_name), "clk-prog%d", id);
>> +	ret = request_irq(prog->irq, clk_programmable_irq_handler,
>> +			  IRQF_TRIGGER_HIGH, irq_name, prog);
>> +	if (ret)
>> +		return ERR_PTR(ret);
>> +
>> +	clk = clk_register(NULL, &prog->hw);
>> +
>
> ^^
>
>> +	if (IS_ERR(clk))
>> +		kfree(prog);
>> +
>> +	return clk;
>> +}
>> +
>> +static const struct clk_programmable_layout at91rm9200_programmable_layout = {
>> +	.pres_shift = 2,
>> +	.css_mask = 0x3,
>> +	.have_slck_mck = 0,
>> +};
>> +
>> +static const struct clk_programmable_layout at91sam9g45_programmable_layout = {
>> +	.pres_shift = 2,
>> +	.css_mask = 0x3,
>> +	.have_slck_mck = 1,
>> +};
>> +
>> +static const struct clk_programmable_layout at91sam9x5_programmable_layout = {
>> +	.pres_shift = 4,
>> +	.css_mask = 0x7,
>> +	.have_slck_mck = 0,
>> +};
>> +
>> +struct clk_prog_data {
>> +	struct clk **clks;
>> +	u8 *ids;
>> +	unsigned int clk_num;
>> +};
>> +
>> +static struct clk * __init
>> +of_clk_src_periph_get(struct of_phandle_args *clkspec, void *data)
>> +{
>> +	struct clk_prog_data *clk_data = data;
>> +	unsigned int id = clkspec->args[0];
>> +	int i;
>> +
>> +	if (id >= PROG_MAX)
>> +		goto err;
>> +
>> +	for (i = 0; i < clk_data->clk_num; i++) {
>> +		if (clk_data->ids[i] == id)
>> +			return clk_data->clks[i];
>> +	}
>> +
>> +err:
>> +	pr_err("%s: invalid clock id %d\n", __func__, id);
>> +	return ERR_PTR(-EINVAL);
>> +}
>> +
>> +static void __init
>> +of_at91_clk_prog_setup(struct device_node *np, struct at91_pmc *pmc,
>> +		       const struct clk_programmable_layout *layout)
>> +{
>> +	int num;
>> +	u32 id;
>> +	int i;
>> +	unsigned int irq;
>> +	struct clk *clk;
>> +	int num_parents;
>> +	u8 *ids;
>> +	struct clk **clks;
>> +	struct clk_prog_data *clktab;
>> +	const char *parent_names[PROG_SOURCE_MAX];
>> +	const char *name;
>> +	struct device_node *progclknp;
>> +
>> +	num_parents = of_count_phandle_with_args(np, "clocks", "#clock-cells");
>> +	if (num_parents <= 0 || num_parents > PROG_SOURCE_MAX)
>> +		return;
>> +
>> +	for (i = 0; i < num_parents; ++i) {
>> +		parent_names[i] = of_clk_get_parent_name(np, i);
>> +		if (!parent_names[i])
>> +			return;
>> +	}
>> +
>> +	num = of_get_child_count(np);
>> +	if (!num || num > PROG_MAX)
>> +		return;
>> +
>> +	clktab = kzalloc(sizeof(*clktab), GFP_KERNEL);
>> +	if (!clktab)
>> +		return;
>> +
>> +	ids = kzalloc(num * sizeof(*ids), GFP_KERNEL);
>> +	if (!ids)
>> +		goto out_free_clktab;
>> +
>> +	clks = kzalloc(num * sizeof(*clks), GFP_KERNEL);
>> +	if (!clks)
>> +		goto out_free_ids;
>> +
>> +	i = 0;
>> +	for_each_child_of_node(np, progclknp) {
>> +		name = progclknp->name;
>> +
>> +		if (of_property_read_u32(progclknp, "atmel,clk-id", &id))
>> +			goto out_free_clks;
>> +		if (id >= PROG_MAX)
>> +			goto out_free_clks;
>> +
>> +		irq = irq_of_parse_and_map(np, 0);
>> +		if (!irq)
>> +			goto out_free_clks;
>> +
>> +		clk = at91_clk_register_programmable(pmc, irq, name,
>> +						     parent_names, num_parents,
>> +						     id, layout);
>> +		if (IS_ERR(clk))
>> +			goto out_free_clks;
>> +
>> +		clks[i] = clk;
>> +		ids[i++] = id;
>> +	}
>> +
>> +	clktab->clk_num = num;
>> +	clktab->clks = clks;
>> +	clktab->ids = ids;
>> +	of_clk_add_provider(np, of_clk_src_periph_get, clktab);
>> +	return;
>> +
>> +out_free_clks:
>> +	kfree(clks);
>> +out_free_ids:
>> +	kfree(ids);
>> +out_free_clktab:
>> +	kfree(clktab);
>> +}
>> +
>> +
>> +void __init of_at91rm9200_clk_prog_setup(struct device_node *np,
>> +					 struct at91_pmc *pmc)
>> +{
>> +	of_at91_clk_prog_setup(np, pmc, &at91rm9200_programmable_layout);
>> +}
>> +
>> +void __init of_at91sam9g45_clk_prog_setup(struct device_node *np,
>> +					  struct at91_pmc *pmc)
>> +{
>> +	of_at91_clk_prog_setup(np, pmc, &at91sam9g45_programmable_layout);
>> +}
>> +
>> +void __init of_at91sam9x5_clk_prog_setup(struct device_node *np,
>> +					 struct at91_pmc *pmc)
>> +{
>> +	of_at91_clk_prog_setup(np, pmc, &at91sam9x5_programmable_layout);
>> +}
>> diff --git a/drivers/clk/at91/pmc.c b/drivers/clk/at91/pmc.c
>> index 1a56f1c..66a627d 100644
>> --- a/drivers/clk/at91/pmc.c
>> +++ b/drivers/clk/at91/pmc.c
>> @@ -265,6 +265,21 @@ static const struct of_device_id pmc_clk_ids[] __initdata = {
>>    		.compatible = "atmel,at91sam9x5-clk-peripheral",
>>    		.data = of_at91sam9x5_clk_periph_setup,
>>    	},
>> +	/* Programmable clocks */
>> +#if defined(CONFIG_AT91_PROGRAMMABLE_CLOCKS)
>> +	{
>> +		.compatible = "atmel,at91rm9200-clk-programmable",
>> +		.data = of_at91rm9200_clk_prog_setup,
>> +	},
>> +	{
>> +		.compatible = "atmel,at91sam9g45-clk-programmable",
>> +		.data = of_at91sam9g45_clk_prog_setup,
>> +	},
>> +	{
>> +		.compatible = "atmel,at91sam9x5-clk-programmable",
>> +		.data = of_at91sam9x5_clk_prog_setup,
>> +	},
>> +#endif
>>    	{ /*sentinel*/ }
>>    };
>>
>> diff --git a/drivers/clk/at91/pmc.h b/drivers/clk/at91/pmc.h
>> index 08c30fb..5f20dc1 100644
>> --- a/drivers/clk/at91/pmc.h
>> +++ b/drivers/clk/at91/pmc.h
>> @@ -82,4 +82,13 @@ extern void __init of_at91rm9200_clk_periph_setup(struct device_node *np,
>>    extern void __init of_at91sam9x5_clk_periph_setup(struct device_node *np,
>>    						  struct at91_pmc *pmc);
>>
>> +#if defined(CONFIG_AT91_PROGRAMMABLE_CLOCKS)
>> +extern void __init of_at91rm9200_clk_prog_setup(struct device_node *np,
>> +						struct at91_pmc *pmc);
>> +extern void __init of_at91sam9g45_clk_prog_setup(struct device_node *np,
>> +						 struct at91_pmc *pmc);
>> +extern void __init of_at91sam9x5_clk_prog_setup(struct device_node *np,
>> +						struct at91_pmc *pmc);
>> +#endif
>> +
>>    #endif /* __PMC_H_ */
>>
>
>


-- 
Nicolas Ferre

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

* Re: [PATCH v3 14/19] clk: at91: add PMC utmi clock
  2013-08-08  7:14 ` [PATCH v3 14/19] clk: at91: add PMC utmi clock Boris BREZILLON
@ 2013-10-08 16:08   ` Nicolas Ferre
  0 siblings, 0 replies; 54+ messages in thread
From: Nicolas Ferre @ 2013-10-08 16:08 UTC (permalink / raw)
  To: Boris BREZILLON, Grant Likely, Rob Herring, Rob Landley,
	Andrew Victor, Jean-Christophe Plagniol-Villard, Russell King,
	Mike Turquette, Felipe Balbi, Greg Kroah-Hartman,
	Ludovic Desroches, Josh Wu, Richard Genoud
  Cc: devicetree, linux-kernel, linux-arm-kernel

On 08/08/2013 09:14, Boris BREZILLON :
> This adds new at91 utmi clock implementation using common clk framework.
>
> This clock is a pll with a fixed factor (x40).
> It is used as a source for usb clock.
>
> Signed-off-by: Boris BREZILLON <b.brezillon@overkiz.com>
> ---
>   arch/arm/mach-at91/Kconfig  |    7 ++
>   drivers/clk/at91/Makefile   |    1 +
>   drivers/clk/at91/clk-utmi.c |  161 +++++++++++++++++++++++++++++++++++++++++++
>   drivers/clk/at91/pmc.c      |    7 ++
>   drivers/clk/at91/pmc.h      |    5 ++
>   5 files changed, 181 insertions(+)
>   create mode 100644 drivers/clk/at91/clk-utmi.c
>
> diff --git a/arch/arm/mach-at91/Kconfig b/arch/arm/mach-at91/Kconfig
> index 85b53a4..6ad37da 100644
> --- a/arch/arm/mach-at91/Kconfig
> +++ b/arch/arm/mach-at91/Kconfig
> @@ -1,5 +1,8 @@
>   if ARCH_AT91
>
> +config HAVE_AT91_UTMI
> +	bool
> +
>   config HAVE_AT91_DBGU0
>   	bool
>
> @@ -78,6 +81,7 @@ config SOC_SAMA5D3
>   	select HAVE_FB_ATMEL
>   	select HAVE_AT91_DBGU1
>   	select AT91_USE_OLD_CLK
> +	select HAVE_AT91_UTMI
>   	help
>   	  Select this if you are using one of Atmel's SAMA5D3 family SoC.
>   	  This support covers SAMA5D31, SAMA5D33, SAMA5D34, SAMA5D35.
> @@ -124,6 +128,7 @@ config SOC_AT91SAM9RL
>   	select HAVE_FB_ATMEL
>   	select SOC_AT91SAM9
>   	select AT91_USE_OLD_CLK
> +	select HAVE_AT91_UTMI
>
>   config SOC_AT91SAM9G45
>   	bool "AT91SAM9G45 or AT91SAM9M10 families"
> @@ -131,6 +136,7 @@ config SOC_AT91SAM9G45
>   	select HAVE_FB_ATMEL
>   	select SOC_AT91SAM9
>   	select AT91_USE_OLD_CLK
> +	select HAVE_AT91_UTMI
>   	help
>   	  Select this if you are using one of Atmel's AT91SAM9G45 family SoC.
>   	  This support covers AT91SAM9G45, AT91SAM9G46, AT91SAM9M10 and AT91SAM9M11.
> @@ -141,6 +147,7 @@ config SOC_AT91SAM9X5
>   	select HAVE_FB_ATMEL
>   	select SOC_AT91SAM9
>   	select AT91_USE_OLD_CLK
> +	select HAVE_AT91_UTMI
>   	help
>   	  Select this if you are using one of Atmel's AT91SAM9x5 family SoC.
>   	  This means that your SAM9 name finishes with a '5' (except if it is
> diff --git a/drivers/clk/at91/Makefile b/drivers/clk/at91/Makefile
> index 3873b62..a824883 100644
> --- a/drivers/clk/at91/Makefile
> +++ b/drivers/clk/at91/Makefile
> @@ -7,3 +7,4 @@ obj-y += clk-main.o clk-pll.o clk-plldiv.o clk-master.o
>   obj-y += clk-system.o clk-peripheral.o
>
>   obj-$(CONFIG_AT91_PROGRAMMABLE_CLOCKS)	+= clk-programmable.o
> +obj-$(CONFIG_HAVE_AT91_UTMI)		+= clk-utmi.o
> diff --git a/drivers/clk/at91/clk-utmi.c b/drivers/clk/at91/clk-utmi.c
> new file mode 100644
> index 0000000..244ff9e
> --- /dev/null
> +++ b/drivers/clk/at91/clk-utmi.c
> @@ -0,0 +1,161 @@
> +/*
> + * drivers/clk/at91/clk-utmi.c
> + *
> + *  Copyright (C) 2013 Boris BREZILLON <b.brezillon@overkiz.com>
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License as published by
> + * the Free Software Foundation; either version 2 of the License, or
> + * (at your option) any later version.
> + *
> + */
> +
> +#include <linux/clk-provider.h>
> +#include <linux/clkdev.h>
> +#include <linux/clk/at91_pmc.h>
> +#include <linux/interrupt.h>
> +#include <linux/irq.h>
> +#include <linux/of.h>
> +#include <linux/of_address.h>
> +#include <linux/of_irq.h>
> +#include <linux/io.h>
> +#include <linux/sched.h>
> +#include <linux/wait.h>
> +
> +#include "pmc.h"
> +
> +#define to_clk_utmi(hw) container_of(hw, struct clk_utmi, hw)
> +
> +struct clk_utmi {
> +	struct clk_hw hw;
> +	struct at91_pmc *pmc;
> +	unsigned int irq;
> +	wait_queue_head_t wait;
> +};
> +
> +static irqreturn_t clk_utmi_irq_handler(int irq, void *dev_id)
> +{
> +	struct clk_utmi *utmi = (struct clk_utmi *)dev_id;
> +
> +	wake_up(&utmi->wait);
> +	disable_irq_nosync(utmi->irq);
> +
> +	return IRQ_HANDLED;
> +}
> +
> +static int clk_utmi_prepare(struct clk_hw *hw)
> +{
> +	struct clk_utmi *utmi = to_clk_utmi(hw);
> +	struct at91_pmc *pmc = utmi->pmc;
> +	u32 tmp = at91_pmc_read(AT91_CKGR_UCKR) | AT91_PMC_UPLLEN |
> +		  AT91_PMC_UPLLCOUNT | AT91_PMC_BIASEN;
> +
> +	pmc_write(pmc, AT91_CKGR_UCKR, tmp);
> +
> +	while (!(pmc_read(pmc, AT91_PMC_SR) & AT91_PMC_LOCKU)) {
> +		enable_irq(utmi->irq);
> +		wait_event(utmi->wait,
> +			   pmc_read(pmc, AT91_PMC_SR) & AT91_PMC_LOCKU);
> +	}
> +
> +	return 0;
> +}
> +
> +static int clk_utmi_is_ready(struct clk_hw *hw)
> +{
> +	struct clk_utmi *utmi = to_clk_utmi(hw);
> +	struct at91_pmc *pmc = utmi->pmc;
> +
> +	return !!(pmc_read(pmc, AT91_PMC_SR) & AT91_PMC_LOCKU);
> +}
> +
> +static void clk_utmi_disable(struct clk_hw *hw)
> +{
> +	struct clk_utmi *utmi = to_clk_utmi(hw);
> +	struct at91_pmc *pmc = utmi->pmc;
> +	u32 tmp = at91_pmc_read(AT91_CKGR_UCKR) & ~AT91_PMC_UPLLEN;
> +
> +	pmc_write(pmc, AT91_CKGR_UCKR, tmp);
> +}
> +
> +static unsigned long clk_utmi_recalc_rate(struct clk_hw *hw,
> +					  unsigned long parent_rate)
> +{
> +	return parent_rate * 40;

A constant or a little comment right here is necessary. As it is fixed 
by nature, I am not against such a number, but a comment is a must for 
this situation.

> +}
> +
> +static const struct clk_ops utmi_ops = {
> +	.prepare = clk_utmi_prepare,
> +	.is_prepared = clk_utmi_is_ready,
> +	.disable = clk_utmi_disable,
> +	.is_enabled = clk_utmi_is_ready,
> +	.recalc_rate = clk_utmi_recalc_rate,
> +};
> +
> +static struct clk * __init
> +at91_clk_register_utmi(struct at91_pmc *pmc, unsigned int irq,
> +		       const char *name, const char *parent_name)
> +{
> +	int ret;
> +	struct clk_utmi *utmi;
> +	struct clk *clk = NULL;
> +	struct clk_init_data init;
> +
> +	utmi = kzalloc(sizeof(*utmi), GFP_KERNEL);
> +	if (!utmi)
> +		return ERR_PTR(-ENOMEM);
> +
> +	init.name = name;
> +	init.ops = &utmi_ops;
> +	init.parent_names = parent_name ? &parent_name : NULL;
> +	init.num_parents = parent_name ? 1 : 0;
> +	init.flags = CLK_SET_RATE_GATE;
> +
> +	utmi->hw.init = &init;
> +	utmi->pmc = pmc;
> +	utmi->irq = irq;
> +	init_waitqueue_head(&utmi->wait);
> +	irq_set_status_flags(utmi->irq, IRQ_NOAUTOEN);
> +	ret = request_irq(utmi->irq, clk_utmi_irq_handler,
> +			  IRQF_TRIGGER_HIGH, "clk-utmi", utmi);
> +	if (ret)
> +		return ERR_PTR(ret);
> +
> +	clk = clk_register(NULL, &utmi->hw);
> +

..

> +	if (IS_ERR(clk))
> +		kfree(utmi);
> +
> +	return clk;
> +}
> +
> +static void __init
> +of_at91_clk_utmi_setup(struct device_node *np, struct at91_pmc *pmc)
> +{
> +	unsigned int irq;
> +	struct clk *clk;
> +	const char *parent_name;
> +	const char *name = np->name;
> +
> +	parent_name = of_clk_get_parent_name(np, 0);
> +
> +	of_property_read_string(np, "clock-output-names", &name);
> +
> +	irq = irq_of_parse_and_map(np, 0);
> +	if (!irq)
> +		return;
> +
> +	clk = at91_clk_register_utmi(pmc, irq, name, parent_name);
> +

..

> +	if (IS_ERR(clk))
> +		return;
> +
> +	of_clk_add_provider(np, of_clk_src_simple_get, clk);
> +	return;
> +}
> +
> +void __init of_at91sam9x5_clk_utmi_setup(struct device_node *np,
> +					 struct at91_pmc *pmc)
> +{
> +	of_at91_clk_utmi_setup(np, pmc);
> +}
> diff --git a/drivers/clk/at91/pmc.c b/drivers/clk/at91/pmc.c
> index 66a627d..238f0d2 100644
> --- a/drivers/clk/at91/pmc.c
> +++ b/drivers/clk/at91/pmc.c
> @@ -280,6 +280,13 @@ static const struct of_device_id pmc_clk_ids[] __initdata = {
>   		.data = of_at91sam9x5_clk_prog_setup,
>   	},
>   #endif
> +	/* UTMI clock */
> +#if defined(CONFIG_HAVE_AT91_UTMI)
> +	{
> +		.compatible = "atmel,at91sam9x5-clk-utmi",
> +		.data = of_at91sam9x5_clk_utmi_setup,
> +	},
> +#endif
>   	{ /*sentinel*/ }
>   };
>
> diff --git a/drivers/clk/at91/pmc.h b/drivers/clk/at91/pmc.h
> index 5f20dc1..3ba9503 100644
> --- a/drivers/clk/at91/pmc.h
> +++ b/drivers/clk/at91/pmc.h
> @@ -91,4 +91,9 @@ extern void __init of_at91sam9x5_clk_prog_setup(struct device_node *np,
>   						struct at91_pmc *pmc);
>   #endif
>
> +#if defined(CONFIG_HAVE_AT91_UTMI)
> +extern void __init of_at91sam9x5_clk_utmi_setup(struct device_node *np,
> +						struct at91_pmc *pmc);
> +#endif
> +
>   #endif /* __PMC_H_ */
>


-- 
Nicolas Ferre

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

* Re: [PATCH v3 12/19] clk: at91: add peripheral clk macros for peripheral clk dt bindings
  2013-10-08 16:01     ` boris brezillon
@ 2013-10-08 16:15       ` Nicolas Ferre
  2013-10-08 16:19         ` boris brezillon
  0 siblings, 1 reply; 54+ messages in thread
From: Nicolas Ferre @ 2013-10-08 16:15 UTC (permalink / raw)
  To: boris brezillon, Grant Likely, Rob Herring, Rob Landley,
	Andrew Victor, Jean-Christophe Plagniol-Villard, Russell King,
	Mike Turquette, Felipe Balbi, Greg Kroah-Hartman,
	Ludovic Desroches, Josh Wu, Richard Genoud
  Cc: devicetree, linux-kernel, linux-arm-kernel

On 08/10/2013 18:01, boris brezillon :
> On 08/10/2013 17:44, Nicolas Ferre wrote:
>> On 08/08/2013 09:10, Boris BREZILLON :
>>> This patch adds the peripheral divisors macros (for sam9x5 compatible
>>> IPs)
>>> which will be used by peripheral clk dt definitions.
>>
>> I am in favor for these definitions. So let's keep them (with raw
>> numbers toguether with these macros in documentation).
>
> I guess we should move them elsewhere if these are the only macros we keep.
>
> What about "include/dt-bindings/clk/at91sam9x5-periph.h" ?

Well, what about a more generic clk binding file for all at91-related 
definitions (if more come). We can still differentiate among devices 
into the file itself...

What do you think about:
include/dt-bindings/clk/at91.h
is it too generic?

BTW, I see the clk and clock directories. What is the difference?


>>> Signed-off-by: Boris BREZILLON <b.brezillon@overkiz.com>
>>> ---
>>>    .../clk/at91/at91sam9x5/clk-peripheral.h           |   15
>>> +++++++++++++++
>>>    1 file changed, 15 insertions(+)
>>>    create mode 100644
>>> include/dt-bindings/clk/at91/at91sam9x5/clk-peripheral.h
>>>
>>> diff --git a/include/dt-bindings/clk/at91/at91sam9x5/clk-peripheral.h
>>> b/include/dt-bindings/clk/at91/at91sam9x5/clk-peripheral.h
>>> new file mode 100644
>>> index 0000000..a6dd506
>>> --- /dev/null
>>> +++ b/include/dt-bindings/clk/at91/at91sam9x5/clk-peripheral.h
>>> @@ -0,0 +1,15 @@
>>> +/*
>>> + * This header provides constants for AT91 peripheral clks.
>>> + *
>>> + * The constants defined in this header are being used in dts.
>>> + */
>>> +
>>> +#ifndef _DT_BINDINGS_CLK_AT91SAM9X5_PERIPH_H
>>> +#define _DT_BINDINGS_CLK_AT91SAM9X5_PERIPH_H
>>> +
>>> +#define AT91SAM9X5_PERIPH_CLK_DIV1    0
>>> +#define AT91SAM9X5_PERIPH_CLK_DIV2    1
>>> +#define AT91SAM9X5_PERIPH_CLK_DIV4    2
>>> +#define AT91SAM9X5_PERIPH_CLK_DIV8    3
>>> +
>>> +#endif
>>>
>>
>>
>
>
>


-- 
Nicolas Ferre

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

* Re: [PATCH v3 12/19] clk: at91: add peripheral clk macros for peripheral clk dt bindings
  2013-10-08 16:15       ` Nicolas Ferre
@ 2013-10-08 16:19         ` boris brezillon
  0 siblings, 0 replies; 54+ messages in thread
From: boris brezillon @ 2013-10-08 16:19 UTC (permalink / raw)
  To: Nicolas Ferre, Grant Likely, Rob Herring, Rob Landley,
	Andrew Victor, Jean-Christophe Plagniol-Villard, Russell King,
	Mike Turquette, Felipe Balbi, Greg Kroah-Hartman,
	Ludovic Desroches, Josh Wu, Richard Genoud
  Cc: devicetree, linux-kernel, linux-arm-kernel

On 08/10/2013 18:15, Nicolas Ferre wrote:
> On 08/10/2013 18:01, boris brezillon :
>> On 08/10/2013 17:44, Nicolas Ferre wrote:
>>> On 08/08/2013 09:10, Boris BREZILLON :
>>>> This patch adds the peripheral divisors macros (for sam9x5 compatible
>>>> IPs)
>>>> which will be used by peripheral clk dt definitions.
>>>
>>> I am in favor for these definitions. So let's keep them (with raw
>>> numbers toguether with these macros in documentation).
>>
>> I guess we should move them elsewhere if these are the only macros we 
>> keep.
>>
>> What about "include/dt-bindings/clk/at91sam9x5-periph.h" ?
>
> Well, what about a more generic clk binding file for all at91-related 
> definitions (if more come). We can still differentiate among devices 
> into the file itself...
>
> What do you think about:
> include/dt-bindings/clk/at91.h
> is it too generic?

No, this is fine.

>
> BTW, I see the clk and clock directories. What is the difference?
>

I don't know, but they both store clk (signals) specific bindings, and 
as the framework is called "clk", I choose this directory.

Could a dt maintainer (or Mike) help us choosing the appropriate directory ?

>
>>>> Signed-off-by: Boris BREZILLON <b.brezillon@overkiz.com>
>>>> ---
>>>>    .../clk/at91/at91sam9x5/clk-peripheral.h           |   15
>>>> +++++++++++++++
>>>>    1 file changed, 15 insertions(+)
>>>>    create mode 100644
>>>> include/dt-bindings/clk/at91/at91sam9x5/clk-peripheral.h
>>>>
>>>> diff --git a/include/dt-bindings/clk/at91/at91sam9x5/clk-peripheral.h
>>>> b/include/dt-bindings/clk/at91/at91sam9x5/clk-peripheral.h
>>>> new file mode 100644
>>>> index 0000000..a6dd506
>>>> --- /dev/null
>>>> +++ b/include/dt-bindings/clk/at91/at91sam9x5/clk-peripheral.h
>>>> @@ -0,0 +1,15 @@
>>>> +/*
>>>> + * This header provides constants for AT91 peripheral clks.
>>>> + *
>>>> + * The constants defined in this header are being used in dts.
>>>> + */
>>>> +
>>>> +#ifndef _DT_BINDINGS_CLK_AT91SAM9X5_PERIPH_H
>>>> +#define _DT_BINDINGS_CLK_AT91SAM9X5_PERIPH_H
>>>> +
>>>> +#define AT91SAM9X5_PERIPH_CLK_DIV1    0
>>>> +#define AT91SAM9X5_PERIPH_CLK_DIV2    1
>>>> +#define AT91SAM9X5_PERIPH_CLK_DIV4    2
>>>> +#define AT91SAM9X5_PERIPH_CLK_DIV8    3
>>>> +
>>>> +#endif
>>>>
>>>
>>>
>>
>>
>>
>
>


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

* Re: [PATCH v3 15/19] clk: at91: add PMC usb clock
  2013-08-08  7:15 ` [PATCH v3 15/19] clk: at91: add PMC usb clock Boris BREZILLON
@ 2013-10-08 16:20   ` Nicolas Ferre
  0 siblings, 0 replies; 54+ messages in thread
From: Nicolas Ferre @ 2013-10-08 16:20 UTC (permalink / raw)
  To: Boris BREZILLON, Grant Likely, Rob Herring, Rob Landley,
	Andrew Victor, Jean-Christophe Plagniol-Villard, Russell King,
	Mike Turquette, Felipe Balbi, Greg Kroah-Hartman,
	Ludovic Desroches, Josh Wu, Richard Genoud
  Cc: devicetree, linux-kernel, linux-arm-kernel

On 08/08/2013 09:15, Boris BREZILLON :
> This patch adds new at91 usb clock implementation using common clk framework.
> This clock is used to clock usb ports (ohci, ehci and udc).

Blank line == "Ditto" ;-)

>
> Signed-off-by: Boris BREZILLON <b.brezillon@overkiz.com>
> ---
>   arch/arm/mach-at91/Kconfig |   11 ++
>   drivers/clk/at91/Makefile  |    1 +
>   drivers/clk/at91/clk-usb.c |  323 ++++++++++++++++++++++++++++++++++++++++++++
>   drivers/clk/at91/pmc.c     |   11 ++
>   drivers/clk/at91/pmc.h     |    7 +
>   5 files changed, 353 insertions(+)
>   create mode 100644 drivers/clk/at91/clk-usb.c
>
> diff --git a/arch/arm/mach-at91/Kconfig b/arch/arm/mach-at91/Kconfig
> index 6ad37da..b76dc4c 100644
> --- a/arch/arm/mach-at91/Kconfig
> +++ b/arch/arm/mach-at91/Kconfig
> @@ -3,6 +3,9 @@ if ARCH_AT91
>   config HAVE_AT91_UTMI
>   	bool
>
> +config HAVE_AT91_USB_CLK
> +	bool
> +
>   config HAVE_AT91_DBGU0
>   	bool
>
> @@ -82,6 +85,7 @@ config SOC_SAMA5D3
>   	select HAVE_AT91_DBGU1
>   	select AT91_USE_OLD_CLK
>   	select HAVE_AT91_UTMI
> +	select HAVE_AT91_USB_CLK
>   	help
>   	  Select this if you are using one of Atmel's SAMA5D3 family SoC.
>   	  This support covers SAMA5D31, SAMA5D33, SAMA5D34, SAMA5D35.
> @@ -96,12 +100,14 @@ config SOC_AT91RM9200
>   	select MULTI_IRQ_HANDLER
>   	select SPARSE_IRQ
>   	select AT91_USE_OLD_CLK
> +	select HAVE_AT91_USB_CLK
>
>   config SOC_AT91SAM9260
>   	bool "AT91SAM9260, AT91SAM9XE or AT91SAM9G20"
>   	select HAVE_AT91_DBGU0
>   	select SOC_AT91SAM9
>   	select AT91_USE_OLD_CLK
> +	select HAVE_AT91_USB_CLK
>   	help
>   	  Select this if you are using one of Atmel's AT91SAM9260, AT91SAM9XE
>   	  or AT91SAM9G20 SoC.
> @@ -112,6 +118,7 @@ config SOC_AT91SAM9261
>   	select HAVE_FB_ATMEL
>   	select SOC_AT91SAM9
>   	select AT91_USE_OLD_CLK
> +	select HAVE_AT91_USB_CLK
>   	help
>   	  Select this if you are using one of Atmel's AT91SAM9261 or AT91SAM9G10 SoC.
>
> @@ -121,6 +128,7 @@ config SOC_AT91SAM9263
>   	select HAVE_FB_ATMEL
>   	select SOC_AT91SAM9
>   	select AT91_USE_OLD_CLK
> +	select HAVE_AT91_USB_CLK
>
>   config SOC_AT91SAM9RL
>   	bool "AT91SAM9RL"
> @@ -137,6 +145,7 @@ config SOC_AT91SAM9G45
>   	select SOC_AT91SAM9
>   	select AT91_USE_OLD_CLK
>   	select HAVE_AT91_UTMI
> +	select HAVE_AT91_USB_CLK
>   	help
>   	  Select this if you are using one of Atmel's AT91SAM9G45 family SoC.
>   	  This support covers AT91SAM9G45, AT91SAM9G46, AT91SAM9M10 and AT91SAM9M11.
> @@ -148,6 +157,7 @@ config SOC_AT91SAM9X5
>   	select SOC_AT91SAM9
>   	select AT91_USE_OLD_CLK
>   	select HAVE_AT91_UTMI
> +	select HAVE_AT91_USB_CLK
>   	help
>   	  Select this if you are using one of Atmel's AT91SAM9x5 family SoC.
>   	  This means that your SAM9 name finishes with a '5' (except if it is
> @@ -161,6 +171,7 @@ config SOC_AT91SAM9N12
>   	select HAVE_FB_ATMEL
>   	select SOC_AT91SAM9
>   	select AT91_USE_OLD_CLK
> +	select HAVE_AT91_USB_CLK
>   	help
>   	  Select this if you are using Atmel's AT91SAM9N12 SoC.
>
> diff --git a/drivers/clk/at91/Makefile b/drivers/clk/at91/Makefile
> index a824883..61db058 100644
> --- a/drivers/clk/at91/Makefile
> +++ b/drivers/clk/at91/Makefile
> @@ -8,3 +8,4 @@ obj-y += clk-system.o clk-peripheral.o
>
>   obj-$(CONFIG_AT91_PROGRAMMABLE_CLOCKS)	+= clk-programmable.o
>   obj-$(CONFIG_HAVE_AT91_UTMI)		+= clk-utmi.o
> +obj-$(CONFIG_HAVE_AT91_USB_CLK)		+= clk-usb.o
> diff --git a/drivers/clk/at91/clk-usb.c b/drivers/clk/at91/clk-usb.c
> new file mode 100644
> index 0000000..12c20a0
> --- /dev/null
> +++ b/drivers/clk/at91/clk-usb.c
> @@ -0,0 +1,323 @@
> +/*
> + * drivers/clk/at91/clk-usb.c
> + *
> + *  Copyright (C) 2013 Boris BREZILLON <b.brezillon@overkiz.com>
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License as published by
> + * the Free Software Foundation; either version 2 of the License, or
> + * (at your option) any later version.
> + *
> + */
> +
> +#include <linux/clk-provider.h>
> +#include <linux/clkdev.h>
> +#include <linux/clk/at91_pmc.h>
> +#include <linux/of.h>
> +#include <linux/of_address.h>
> +#include <linux/io.h>
> +
> +#include "pmc.h"
> +
> +#define USB_SOURCE_MAX		2
> +
> +#define to_at91sam9x5_clk_usb(hw) \
> +	container_of(hw, struct at91sam9x5_clk_usb, hw)
> +struct at91sam9x5_clk_usb {
> +	struct clk_hw hw;
> +	struct at91_pmc *pmc;
> +	u8 usbs0_unused; /* sam9n12 uses usbs0 to disable usb clock */

Same remark as PLL patch. So maybe make the sam9n12 as a special case.

> +};
> +
> +#define to_at91rm9200_clk_usb(hw) \
> +	container_of(hw, struct at91rm9200_clk_usb, hw)
> +struct at91rm9200_clk_usb {
> +	struct clk_hw hw;
> +	struct at91_pmc *pmc;
> +	u32 divisors[4];
> +};
> +
> +static unsigned long at91sam9x5_clk_usb_recalc_rate(struct clk_hw *hw,
> +						    unsigned long parent_rate)
> +{
> +	u32 tmp;
> +	u8 usbdiv;
> +	struct at91sam9x5_clk_usb *usb = to_at91sam9x5_clk_usb(hw);
> +	struct at91_pmc *pmc = usb->pmc;
> +
> +	tmp = pmc_read(pmc, AT91_PMC_USB);
> +	usbdiv = (tmp & AT91_PMC_OHCIUSBDIV) >> 8;


> +	return parent_rate / (usbdiv + 1);
> +}
> +
> +static long at91sam9x5_clk_usb_round_rate(struct clk_hw *hw, unsigned long rate,
> +					  unsigned long *parent_rate)
> +{
> +	unsigned long div;
> +	unsigned long bestrate;
> +	unsigned long tmp;
> +
> +	if (rate >= *parent_rate)
> +		return *parent_rate;
> +
> +	div = *parent_rate / rate;
> +	if (div > 15)
> +		return *parent_rate / 16;


> +
> +	bestrate = *parent_rate / div;
> +	tmp = *parent_rate / (div + 1);
> +	if (bestrate - rate > rate - tmp)
> +		bestrate = tmp;
> +
> +	return bestrate;
> +}
> +
> +static int at91sam9x5_clk_usb_set_parent(struct clk_hw *hw, u8 index)
> +{
> +	u32 tmp;
> +	struct at91sam9x5_clk_usb *usb = to_at91sam9x5_clk_usb(hw);
> +	struct at91_pmc *pmc = usb->pmc;
> +
> +	if (usb->usbs0_unused)
> +		index++;
> +	if (index > 1)
> +		return -EINVAL;
> +	tmp = pmc_read(pmc, AT91_PMC_USB) & ~AT91_PMC_USBS;
> +	if (index)
> +		tmp |= AT91_PMC_USBS;
> +	pmc_write(pmc, AT91_PMC_USB, tmp);
> +	return 0;
> +}
> +
> +static u8 at91sam9x5_clk_usb_get_parent(struct clk_hw *hw)
> +{
> +	struct at91sam9x5_clk_usb *usb = to_at91sam9x5_clk_usb(hw);
> +	struct at91_pmc *pmc = usb->pmc;
> +
> +	if (usb->usbs0_unused)
> +		return 0;
> +
> +	return pmc_read(pmc, AT91_PMC_USB) & AT91_PMC_USBS;
> +}
> +
> +static int at91sam9x5_clk_usb_set_rate(struct clk_hw *hw, unsigned long rate,
> +				       unsigned long parent_rate)
> +{
> +	u32 tmp;
> +	struct at91sam9x5_clk_usb *usb = to_at91sam9x5_clk_usb(hw);
> +	struct at91_pmc *pmc = usb->pmc;
> +	unsigned long div = parent_rate / rate;
> +
> +	if (parent_rate % rate || div < 1 || div > 16)


> +		return -EINVAL;
> +
> +	tmp = pmc_read(pmc, AT91_PMC_USB) & ~AT91_PMC_OHCIUSBDIV;
> +	tmp |= (div - 1) << 8;
> +	pmc_write(pmc, AT91_PMC_USB, tmp);
> +
> +	return 0;
> +}
> +
> +static const struct clk_ops at91sam9x5_usb_ops = {
> +	.recalc_rate = at91sam9x5_clk_usb_recalc_rate,
> +	.round_rate = at91sam9x5_clk_usb_round_rate,
> +	.get_parent = at91sam9x5_clk_usb_get_parent,
> +	.set_parent = at91sam9x5_clk_usb_set_parent,
> +	.set_rate = at91sam9x5_clk_usb_set_rate,
> +};
> +
> +static struct clk * __init
> +at91sam9x5_clk_register_usb(struct at91_pmc *pmc, const char *name,
> +			    const char **parent_names, u8 num_parents,
> +			    u8 usbs0_unused)
> +{
> +	struct at91sam9x5_clk_usb *usb;
> +	struct clk *clk = NULL;
> +	struct clk_init_data init;
> +
> +	usb = kzalloc(sizeof(*usb), GFP_KERNEL);
> +	if (!usb)
> +		return ERR_PTR(-ENOMEM);
> +
> +	init.name = name;
> +	init.ops = &at91sam9x5_usb_ops;
> +	init.parent_names = parent_names;
> +	init.num_parents = num_parents;
> +	init.flags = CLK_SET_RATE_GATE | CLK_SET_PARENT_GATE;
> +
> +	usb->usbs0_unused = usbs0_unused;
> +	usb->hw.init = &init;
> +	usb->pmc = pmc;
> +
> +	clk = clk_register(NULL, &usb->hw);
> +


> +	if (IS_ERR(clk))
> +		kfree(usb);
> +
> +	return clk;
> +}
> +
> +static unsigned long at91rm9200_clk_usb_recalc_rate(struct clk_hw *hw,
> +						    unsigned long parent_rate)
> +{
> +	struct at91rm9200_clk_usb *usb = to_at91rm9200_clk_usb(hw);
> +	struct at91_pmc *pmc = usb->pmc;
> +	u32 tmp;
> +	u8 usbdiv;
> +
> +	tmp = pmc_read(pmc, AT91_CKGR_PLLBR);
> +	usbdiv = (tmp & AT91_PMC_USBDIV) >> 28;

macro

> +	if (usb->divisors[usbdiv])
> +		return parent_rate / usb->divisors[usbdiv];
> +
> +	return 0;
> +}
> +
> +static long at91rm9200_clk_usb_round_rate(struct clk_hw *hw, unsigned long rate,
> +					  unsigned long *parent_rate)
> +{
> +	struct at91rm9200_clk_usb *usb = to_at91rm9200_clk_usb(hw);
> +	unsigned long bestrate = 0;
> +	int bestdiff = -1;
> +	unsigned long tmprate;
> +	int tmpdiff;
> +	int i = 0;
> +
> +	for (i = 0; i < 4; i++) {
> +		if (!usb->divisors[i])
> +			continue;
> +		tmprate = *parent_rate / usb->divisors[i];
> +		if (tmprate < rate)
> +			tmpdiff = rate - tmprate;
> +		else
> +			tmpdiff = tmprate - rate;
> +
> +		if (bestdiff < 0 || bestdiff > tmpdiff) {
> +			bestrate = tmprate;
> +			bestdiff = tmpdiff;
> +		}
> +
> +		if (!bestdiff)
> +			break;
> +	}
> +
> +	return bestrate;
> +}
> +
> +static int at91rm9200_clk_usb_set_rate(struct clk_hw *hw, unsigned long rate,
> +				       unsigned long parent_rate)
> +{
> +	u32 tmp;
> +	int i;
> +	struct at91rm9200_clk_usb *usb = to_at91rm9200_clk_usb(hw);
> +	struct at91_pmc *pmc = usb->pmc;
> +	unsigned long div = parent_rate / rate;
> +
> +	if (parent_rate % rate)
> +		return -EINVAL;
> +	for (i = 0; i < 4; i++) {
> +		if (usb->divisors[i] == div) {
> +			tmp = pmc_read(pmc, AT91_CKGR_PLLBR) &
> +			      ~AT91_PMC_USBDIV;
> +			tmp |= i << 8;



> +			pmc_write(pmc, AT91_PMC_USB, tmp);
> +			return 0;
> +		}
> +	}
> +
> +	return -EINVAL;
> +}
> +
> +static const struct clk_ops at91rm9200_usb_ops = {
> +	.recalc_rate = at91rm9200_clk_usb_recalc_rate,
> +	.round_rate = at91rm9200_clk_usb_round_rate,
> +	.set_rate = at91rm9200_clk_usb_set_rate,
> +};
> +
> +static struct clk * __init
> +at91rm9200_clk_register_usb(struct at91_pmc *pmc, const char *name,
> +			    const char *parent_name, const u32 *divisors)
> +{
> +	struct at91rm9200_clk_usb *usb;
> +	struct clk *clk = NULL;
> +	struct clk_init_data init;
> +
> +	usb = kzalloc(sizeof(*usb), GFP_KERNEL);
> +	if (!usb)
> +		return ERR_PTR(-ENOMEM);
> +
> +	init.name = name;
> +	init.ops = &at91rm9200_usb_ops;
> +	init.parent_names = &parent_name;
> +	init.num_parents = 1;
> +	init.flags = 0;
> +
> +	usb->hw.init = &init;
> +	usb->pmc = pmc;
> +	memcpy(usb->divisors, divisors, sizeof(usb->divisors));
> +
> +	clk = clk_register(NULL, &usb->hw);
> +


> +	if (IS_ERR(clk))
> +		kfree(usb);
> +
> +	return clk;
> +}
> +
> +void __init of_at91sam9x5_clk_usb_setup(struct device_node *np,
> +					struct at91_pmc *pmc)
> +{
> +	struct clk *clk;
> +	int i;
> +	int num_parents;
> +	u8 usbs0_unused;
> +	const char *parent_names[USB_SOURCE_MAX];
> +	const char *name = np->name;
> +
> +	num_parents = of_count_phandle_with_args(np, "clocks", "#clock-cells");
> +	if (num_parents <= 0 || num_parents > USB_SOURCE_MAX)
> +		return;
> +
> +	for (i = 0; i < num_parents; i++) {
> +		parent_names[i] = of_clk_get_parent_name(np, i);
> +		if (!parent_names[i])
> +			return;
> +	}
> +
> +	usbs0_unused = of_property_read_bool(np, "atmel,usb-clk-src0-unused");
> +	of_property_read_string(np, "clock-output-names", &name);
> +
> +	clk = at91sam9x5_clk_register_usb(pmc, name, parent_names, num_parents,
> +					  usbs0_unused);
> +


> +	if (IS_ERR(clk))
> +		return;
> +
> +	of_clk_add_provider(np, of_clk_src_simple_get, clk);
> +}
> +
> +void __init of_at91rm9200_clk_usb_setup(struct device_node *np,
> +					struct at91_pmc *pmc)
> +{
> +	struct clk *clk;
> +	const char *parent_name;
> +	const char *name = np->name;
> +	u32 divisors[4] = {0, 0, 0, 0};
> +
> +	parent_name = of_clk_get_parent_name(np, 0);
> +	if (!parent_name)
> +		return;
> +
> +	of_property_read_u32_array(np, "atmel,clk-divisors", divisors, 4);
> +	if (!divisors[0])
> +		return;
> +
> +	of_property_read_string(np, "clock-output-names", &name);
> +
> +	clk = at91rm9200_clk_register_usb(pmc, name, parent_name, divisors);
> +


> +	if (IS_ERR(clk))
> +		return;
> +
> +	of_clk_add_provider(np, of_clk_src_simple_get, clk);
> +}
> diff --git a/drivers/clk/at91/pmc.c b/drivers/clk/at91/pmc.c
> index 238f0d2..e46de3d 100644
> --- a/drivers/clk/at91/pmc.c
> +++ b/drivers/clk/at91/pmc.c
> @@ -287,6 +287,17 @@ static const struct of_device_id pmc_clk_ids[] __initdata = {
>   		.data = of_at91sam9x5_clk_utmi_setup,
>   	},
>   #endif
> +	/* USB clock */
> +#if defined(CONFIG_HAVE_AT91_USB_CLK)
> +	{
> +		.compatible = "atmel,at91rm9200-clk-usb",
> +		.data = of_at91rm9200_clk_usb_setup,
> +	},
> +	{
> +		.compatible = "atmel,at91sam9x5-clk-usb",
> +		.data = of_at91sam9x5_clk_usb_setup,
> +	},
> +#endif
>   	{ /*sentinel*/ }
>   };
>
> diff --git a/drivers/clk/at91/pmc.h b/drivers/clk/at91/pmc.h
> index 3ba9503..b2efff5 100644
> --- a/drivers/clk/at91/pmc.h
> +++ b/drivers/clk/at91/pmc.h
> @@ -96,4 +96,11 @@ extern void __init of_at91sam9x5_clk_utmi_setup(struct device_node *np,
>   						struct at91_pmc *pmc);
>   #endif
>
> +#if defined(CONFIG_HAVE_AT91_USB_CLK)
> +extern void __init of_at91rm9200_clk_usb_setup(struct device_node *np,
> +					       struct at91_pmc *pmc);
> +extern void __init of_at91sam9x5_clk_usb_setup(struct device_node *np,
> +					       struct at91_pmc *pmc);
> +#endif
> +
>   #endif /* __PMC_H_ */
>


-- 
Nicolas Ferre

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

* Re: [PATCH v3 16/19] clk: at91: add PMC smd clock
  2013-08-08  7:17 ` [PATCH v3 16/19] clk: at91: add PMC smd clock Boris BREZILLON
@ 2013-10-08 16:22   ` Nicolas Ferre
  0 siblings, 0 replies; 54+ messages in thread
From: Nicolas Ferre @ 2013-10-08 16:22 UTC (permalink / raw)
  To: Boris BREZILLON, Grant Likely, Rob Herring, Rob Landley,
	Andrew Victor, Jean-Christophe Plagniol-Villard, Russell King,
	Mike Turquette, Felipe Balbi, Greg Kroah-Hartman,
	Ludovic Desroches, Josh Wu, Richard Genoud
  Cc: devicetree, linux-kernel, linux-arm-kernel

On 08/08/2013 09:17, Boris BREZILLON :
> This patch adds at91 smd (Soft Modem) clock implementation using common clk
> framework.
>
> Not used by any driver right now.
>
> Signed-off-by: Boris BREZILLON <b.brezillon@overkiz.com>
> ---
>   arch/arm/mach-at91/Kconfig |    5 ++
>   drivers/clk/at91/Makefile  |    1 +
>   drivers/clk/at91/clk-smd.c |  171 ++++++++++++++++++++++++++++++++++++++++++++
>   drivers/clk/at91/pmc.c     |    7 ++
>   drivers/clk/at91/pmc.h     |    5 ++
>   5 files changed, 189 insertions(+)
>   create mode 100644 drivers/clk/at91/clk-smd.c
>
> diff --git a/arch/arm/mach-at91/Kconfig b/arch/arm/mach-at91/Kconfig
> index b76dc4c..97033f7 100644
> --- a/arch/arm/mach-at91/Kconfig
> +++ b/arch/arm/mach-at91/Kconfig
> @@ -39,6 +39,9 @@ config AT91_SAM9G45_RESET
>   config AT91_SAM9_TIME
>   	bool
>
> +config HAVE_AT91_SMD
> +	bool
> +
>   config SOC_AT91SAM9
>   	bool
>   	select AT91_SAM9_TIME
> @@ -85,6 +88,7 @@ config SOC_SAMA5D3
>   	select HAVE_AT91_DBGU1
>   	select AT91_USE_OLD_CLK
>   	select HAVE_AT91_UTMI
> +	select HAVE_AT91_SMD
>   	select HAVE_AT91_USB_CLK
>   	help
>   	  Select this if you are using one of Atmel's SAMA5D3 family SoC.
> @@ -157,6 +161,7 @@ config SOC_AT91SAM9X5
>   	select SOC_AT91SAM9
>   	select AT91_USE_OLD_CLK
>   	select HAVE_AT91_UTMI
> +	select HAVE_AT91_SMD
>   	select HAVE_AT91_USB_CLK
>   	help
>   	  Select this if you are using one of Atmel's AT91SAM9x5 family SoC.
> diff --git a/drivers/clk/at91/Makefile b/drivers/clk/at91/Makefile
> index 61db058..0e92b71 100644
> --- a/drivers/clk/at91/Makefile
> +++ b/drivers/clk/at91/Makefile
> @@ -9,3 +9,4 @@ obj-y += clk-system.o clk-peripheral.o
>   obj-$(CONFIG_AT91_PROGRAMMABLE_CLOCKS)	+= clk-programmable.o
>   obj-$(CONFIG_HAVE_AT91_UTMI)		+= clk-utmi.o
>   obj-$(CONFIG_HAVE_AT91_USB_CLK)		+= clk-usb.o
> +obj-$(CONFIG_HAVE_AT91_SMD)		+= clk-smd.o
> diff --git a/drivers/clk/at91/clk-smd.c b/drivers/clk/at91/clk-smd.c
> new file mode 100644
> index 0000000..a7cf14a
> --- /dev/null
> +++ b/drivers/clk/at91/clk-smd.c
> @@ -0,0 +1,171 @@
> +/*
> + * drivers/clk/at91/clk-smd.c
> + *
> + *  Copyright (C) 2013 Boris BREZILLON <b.brezillon@overkiz.com>
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License as published by
> + * the Free Software Foundation; either version 2 of the License, or
> + * (at your option) any later version.
> + *
> + */
> +
> +#include <linux/clk-provider.h>
> +#include <linux/clkdev.h>
> +#include <linux/clk/at91_pmc.h>
> +#include <linux/of.h>
> +#include <linux/of_address.h>
> +#include <linux/io.h>
> +
> +#include "pmc.h"
> +
> +#define SMD_SOURCE_MAX		2
> +
> +#define to_at91sam9x5_clk_smd(hw) \
> +	container_of(hw, struct at91sam9x5_clk_smd, hw)
> +struct at91sam9x5_clk_smd {
> +	struct clk_hw hw;
> +	struct at91_pmc *pmc;
> +};
> +
> +static unsigned long at91sam9x5_clk_smd_recalc_rate(struct clk_hw *hw,
> +						    unsigned long parent_rate)
> +{
> +	u32 tmp;
> +	u8 smddiv;
> +	struct at91sam9x5_clk_smd *smd = to_at91sam9x5_clk_smd(hw);
> +	struct at91_pmc *pmc = smd->pmc;
> +
> +	tmp = pmc_read(pmc, AT91_PMC_SMD);
> +	smddiv = (tmp & AT91_PMC_SMD_DIV) >> 8;


> +	return parent_rate / (smddiv + 1);
> +}
> +
> +static long at91sam9x5_clk_smd_round_rate(struct clk_hw *hw, unsigned long rate,
> +					  unsigned long *parent_rate)
> +{
> +	unsigned long div;
> +	unsigned long bestrate;
> +	unsigned long tmp;
> +
> +	if (rate >= *parent_rate)
> +		return *parent_rate;
> +
> +	div = *parent_rate / rate;
> +	if (div > 15)


> +		return *parent_rate / 16;


> +
> +	bestrate = *parent_rate / div;
> +	tmp = *parent_rate / (div + 1);
> +	if (bestrate - rate > rate - tmp)
> +		bestrate = tmp;
> +
> +	return bestrate;
> +}
> +
> +static int at91sam9x5_clk_smd_set_parent(struct clk_hw *hw, u8 index)
> +{
> +	u32 tmp;
> +	struct at91sam9x5_clk_smd *smd = to_at91sam9x5_clk_smd(hw);
> +	struct at91_pmc *pmc = smd->pmc;
> +
> +	if (index > 1)
> +		return -EINVAL;
> +	tmp = pmc_read(pmc, AT91_PMC_SMD) & ~AT91_PMC_SMDS;
> +	if (index)
> +		tmp |= AT91_PMC_SMDS;
> +	pmc_write(pmc, AT91_PMC_SMD, tmp);
> +	return 0;
> +}
> +
> +static u8 at91sam9x5_clk_smd_get_parent(struct clk_hw *hw)
> +{
> +	struct at91sam9x5_clk_smd *smd = to_at91sam9x5_clk_smd(hw);
> +	struct at91_pmc *pmc = smd->pmc;
> +
> +	return pmc_read(pmc, AT91_PMC_SMD) & AT91_PMC_SMDS;
> +}
> +
> +static int at91sam9x5_clk_smd_set_rate(struct clk_hw *hw, unsigned long rate,
> +				       unsigned long parent_rate)
> +{
> +	u32 tmp;
> +	struct at91sam9x5_clk_smd *smd = to_at91sam9x5_clk_smd(hw);
> +	struct at91_pmc *pmc = smd->pmc;
> +	unsigned long div = parent_rate / rate;
> +
> +	if (parent_rate % rate || div < 1 || div > 16)

> +		return -EINVAL;
> +	tmp = pmc_read(pmc, AT91_PMC_SMD) & ~AT91_PMC_SMD_DIV;
> +	tmp |= (div - 1) << 8;


> +	pmc_write(pmc, AT91_PMC_SMD, tmp);
> +
> +	return 0;
> +}
> +
> +static const struct clk_ops at91sam9x5_smd_ops = {
> +	.recalc_rate = at91sam9x5_clk_smd_recalc_rate,
> +	.round_rate = at91sam9x5_clk_smd_round_rate,
> +	.get_parent = at91sam9x5_clk_smd_get_parent,
> +	.set_parent = at91sam9x5_clk_smd_set_parent,
> +	.set_rate = at91sam9x5_clk_smd_set_rate,
> +};
> +
> +static struct clk * __init
> +at91sam9x5_clk_register_smd(struct at91_pmc *pmc, const char *name,
> +			    const char **parent_names, u8 num_parents)
> +{
> +	struct at91sam9x5_clk_smd *smd;
> +	struct clk *clk = NULL;
> +	struct clk_init_data init;
> +
> +	smd = kzalloc(sizeof(*smd), GFP_KERNEL);
> +	if (!smd)
> +		return ERR_PTR(-ENOMEM);
> +
> +	init.name = name;
> +	init.ops = &at91sam9x5_smd_ops;
> +	init.parent_names = parent_names;
> +	init.num_parents = num_parents;
> +	init.flags = CLK_SET_RATE_GATE | CLK_SET_PARENT_GATE;
> +
> +	smd->hw.init = &init;
> +	smd->pmc = pmc;
> +
> +	clk = clk_register(NULL, &smd->hw);
> +
> +	if (IS_ERR(clk))
> +		kfree(smd);
> +
> +	return clk;
> +}
> +
> +void __init of_at91sam9x5_clk_smd_setup(struct device_node *np,
> +					struct at91_pmc *pmc)
> +{
> +	struct clk *clk;
> +	int i;
> +	int num_parents;
> +	const char *parent_names[SMD_SOURCE_MAX];
> +	const char *name = np->name;
> +
> +	num_parents = of_count_phandle_with_args(np, "clocks", "#clock-cells");
> +	if (num_parents <= 0 || num_parents >= SMD_SOURCE_MAX)
> +		return;
> +
> +	for (i = 0; i < num_parents; i++) {
> +		parent_names[i] = of_clk_get_parent_name(np, i);
> +		if (!parent_names[i])
> +			return;
> +	}
> +
> +	of_property_read_string(np, "clock-output-names", &name);
> +
> +	clk = at91sam9x5_clk_register_smd(pmc, name, parent_names,
> +					  num_parents);
> +


> +	if (IS_ERR(clk))
> +		return;
> +
> +	of_clk_add_provider(np, of_clk_src_simple_get, clk);
> +}
> diff --git a/drivers/clk/at91/pmc.c b/drivers/clk/at91/pmc.c
> index e46de3d..0a731c8 100644
> --- a/drivers/clk/at91/pmc.c
> +++ b/drivers/clk/at91/pmc.c
> @@ -298,6 +298,13 @@ static const struct of_device_id pmc_clk_ids[] __initdata = {
>   		.data = of_at91sam9x5_clk_usb_setup,
>   	},
>   #endif
> +	/* SMD clock */
> +#if defined(CONFIG_HAVE_AT91_SMD)
> +	{
> +		.compatible = "atmel,at91sam9x5-clk-smd",
> +		.data = of_at91sam9x5_clk_smd_setup,
> +	},
> +#endif
>   	{ /*sentinel*/ }
>   };
>
> diff --git a/drivers/clk/at91/pmc.h b/drivers/clk/at91/pmc.h
> index b2efff5..43f2516 100644
> --- a/drivers/clk/at91/pmc.h
> +++ b/drivers/clk/at91/pmc.h
> @@ -103,4 +103,9 @@ extern void __init of_at91sam9x5_clk_usb_setup(struct device_node *np,
>   					       struct at91_pmc *pmc);
>   #endif
>
> +#if defined(CONFIG_HAVE_AT91_SMD)
> +extern void __init of_at91sam9x5_clk_smd_setup(struct device_node *np,
> +					       struct at91_pmc *pmc);
> +#endif
> +
>   #endif /* __PMC_H_ */
>


-- 
Nicolas Ferre

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

* Re: [PATCH v3 18/19] ARM: at91: move pit timer to common clk framework
  2013-08-08  8:17 ` [PATCH v3 18/19] ARM: at91: move pit timer to common clk framework Boris BREZILLON
@ 2013-10-08 16:28   ` Nicolas Ferre
  0 siblings, 0 replies; 54+ messages in thread
From: Nicolas Ferre @ 2013-10-08 16:28 UTC (permalink / raw)
  To: Boris BREZILLON, Grant Likely, Rob Herring, Rob Landley,
	Andrew Victor, Jean-Christophe Plagniol-Villard, Russell King,
	Mike Turquette, Felipe Balbi, Greg Kroah-Hartman,
	Ludovic Desroches, Josh Wu, Richard Genoud
  Cc: devicetree, linux-kernel, linux-arm-kernel

On 08/08/2013 10:17, Boris BREZILLON :
> Use device tree to get the source clock of the PIT (Periodic Interval Timer).
> If the clock is not found in device tree (or dt is not enabled) we'll try to
> get it using clk_lookup definitions.
>
> Signed-off-by: Boris BREZILLON <b.brezillon@overkiz.com>

Acked-by: Nicolas Ferre <nicolas.ferre@atmel.com>

> ---
>   arch/arm/mach-at91/at91sam926x_time.c |   14 +++++++++++++-
>   1 file changed, 13 insertions(+), 1 deletion(-)
>
> diff --git a/arch/arm/mach-at91/at91sam926x_time.c b/arch/arm/mach-at91/at91sam926x_time.c
> index 3a4bc2e..8ac976a 100644
> --- a/arch/arm/mach-at91/at91sam926x_time.c
> +++ b/arch/arm/mach-at91/at91sam926x_time.c
> @@ -39,6 +39,7 @@
>   static u32 pit_cycle;		/* write-once */
>   static u32 pit_cnt;		/* access only w/system irq blocked */
>   static void __iomem *pit_base_addr __read_mostly;
> +static struct clk *mck;
>
>   static inline unsigned int pit_read(unsigned int reg_offset)
>   {
> @@ -195,10 +196,14 @@ static int __init of_at91sam926x_pit_init(void)
>   	if (!pit_base_addr)
>   		goto node_err;
>
> +	mck = of_clk_get(np, 0);
> +
>   	/* Get the interrupts property */
>   	ret = irq_of_parse_and_map(np, 0);
>   	if (!ret) {
>   		pr_crit("AT91: PIT: Unable to get IRQ from DT\n");
> +		if (!IS_ERR(mck))
> +			clk_put(mck);
>   		goto ioremap_err;
>   	}
>   	at91sam926x_pit_irq.irq = ret;
> @@ -230,6 +235,8 @@ void __init at91sam926x_pit_init(void)
>   	unsigned	bits;
>   	int		ret;
>
> +	mck = ERR_PTR(-ENOENT);
> +
>   	/* For device tree enabled device: initialize here */
>   	of_at91sam926x_pit_init();
>
> @@ -237,7 +244,12 @@ void __init at91sam926x_pit_init(void)
>   	 * Use our actual MCK to figure out how many MCK/16 ticks per
>   	 * 1/HZ period (instead of a compile-time constant LATCH).
>   	 */
> -	pit_rate = clk_get_rate(clk_get(NULL, "mck")) / 16;
> +	if (IS_ERR(mck))
> +		mck = clk_get(NULL, "mck");
> +
> +	if (IS_ERR(mck))
> +		panic("AT91: PIT: Unable to get mck clk\n");
> +	pit_rate = clk_get_rate(mck) / 16;
>   	pit_cycle = (pit_rate + HZ/2) / HZ;
>   	WARN_ON(((pit_cycle - 1) & ~AT91_PIT_PIV) != 0);
>
>


-- 
Nicolas Ferre

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

* Re: [PATCH v3 19/19] ARM: at91: add new compatible strings for pmc driver
  2013-08-08  8:19 ` [PATCH v3 19/19] ARM: at91: add new compatible strings for pmc driver Boris BREZILLON
@ 2013-10-08 16:29   ` Nicolas Ferre
  0 siblings, 0 replies; 54+ messages in thread
From: Nicolas Ferre @ 2013-10-08 16:29 UTC (permalink / raw)
  To: Boris BREZILLON, Grant Likely, Rob Herring, Rob Landley,
	Andrew Victor, Jean-Christophe Plagniol-Villard, Russell King,
	Mike Turquette, Felipe Balbi, Greg Kroah-Hartman,
	Ludovic Desroches, Josh Wu, Richard Genoud
  Cc: devicetree, linux-kernel, linux-arm-kernel

On 08/08/2013 10:19, Boris BREZILLON :
> This patch adds new compatible string for PMC node to prepare the
> transition to common clk.
>
> These compatible string come from pmc driver in clk subsystem and are
> needed to provide new device tree compatibility with old at91 clks
> (device tree using common clks will use the new compatible strings).
>
> Signed-off-by: Boris BREZILLON <b.brezillon@overkiz.com>
> ---
>   arch/arm/mach-at91/clock.c |    6 ++++++
>   1 file changed, 6 insertions(+)
>
> diff --git a/arch/arm/mach-at91/clock.c b/arch/arm/mach-at91/clock.c
> index 5f02aea..4d4463a 100644
> --- a/arch/arm/mach-at91/clock.c
> +++ b/arch/arm/mach-at91/clock.c
> @@ -884,6 +884,12 @@ static int __init at91_pmc_init(unsigned long main_clock)
>   #if defined(CONFIG_OF)
>   static struct of_device_id pmc_ids[] = {
>   	{ .compatible = "atmel,at91rm9200-pmc" },
> +	{ .compatible = "atmel,at91sam9260-pmc" },
> +	{ .compatible = "atmel,at91sam9g45-pmc" },
> +	{ .compatible = "atmel,at91sam9n12-pmc" },
> +	{ .compatible = "atmel,at91sam9x5-pmc" },
> +	{ .compatible = "atmel,at91sam9g35-pmc" },

With removal of this compatibility string:

Acked-by: Nicolas Ferre <nicolas.ferre@atmel.com>

> +	{ .compatible = "atmel,sama5d3-pmc" },
>   	{ /*sentinel*/ }
>   };
>
>


-- 
Nicolas Ferre

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

* Re: [PATCH v3 02/19] ARM: at91: add Kconfig options for common clk support
  2013-10-07 15:12   ` Nicolas Ferre
  2013-10-07 16:05     ` boris brezillon
@ 2013-10-09  9:56     ` boris brezillon
  2013-10-09 10:05       ` Nicolas Ferre
  1 sibling, 1 reply; 54+ messages in thread
From: boris brezillon @ 2013-10-09  9:56 UTC (permalink / raw)
  To: Nicolas Ferre, Grant Likely, Rob Herring, Rob Landley,
	Andrew Victor, Jean-Christophe Plagniol-Villard, Russell King,
	Mike Turquette, Felipe Balbi, Greg Kroah-Hartman,
	Ludovic Desroches, Josh Wu, Richard Genoud
  Cc: devicetree, linux-kernel, linux-arm-kernel

On 07/10/2013 17:12, Nicolas Ferre wrote:
> On 08/08/2013 07:02, Boris BREZILLON :
>> This patch adds the following Kconfig options to prepare the 
>> transition to
>> common clk framework:
>>
>> - AT91_USE_OLD_CLK: this option is selected by every SoC which does not
>>    support new at91 clks based on common clk framework (SoC which 
>> does not
>>    define the clock tree in its device tree).
>>    This options is also selected when the user choose non dt boards 
>> support
>>    (new at91 clks can only be registered from a device tree definition).
>>
>> - COMMON_CLK_AT91: this option cannot be selected directly. Instead 
>> it is
>
> I would have prefered to keep "AT91" as a prefix => "AT91_COMMON_CLK"
> But it is not so important.
>
Now I remember why I choose this name.
Take a look at drivers/clk/Makefile, the chip specific clks are defined 
this way:

COMMON_CLK_XXX.

Do you still want to rename it ?

>>    enabled if these 3 conditions are met:
>>     * at least one of the selected SoCs have a PMC (Power Management
>>       Controller) Unit
>>     * device tree support is enabled
>>     * the old at91 clk implementation is disabled (every selected SoC 
>> define
>>       its clks in its device tree and non dt boards support is disabled)
>>
>> - OLD_CLK_AT91: this option cannot be selected directly. Instead it is
>
> Here also.
>

I can change this one.

>>    enabled if these 2 conditions are met:
>>     * at least one of the selected SoCs have a PMC (Power Management
>>       Controller) Unit
>>     * at least one of the selected SoCs does not define its clks in its
>>       device tree or non dt-boards support is enabled
>>
>> This patch selects AT91_USE_OLD_CLK in all currently supported SoCs. 
>> These
>> selects will be removed after clk definitions are properly added in each
>> soc's device tree.
>> It also selects AT91_USE_OLD_CLK in all non-dt boards support.
>>
>> AT91_PMC_UNIT references are replaced by OLD_CLK_AT91, because PMC 
>> Unit is
>> enabled for both old and common clk implementations, and old clk
>> implementation should not be compiled if COMMON_CLK is enabled.
>>
>> To avoid future link errors, a new stub is created for 
>> at91_dt_clock_init
>> function if OLD_CLK_AT91 is disabled.
>>
>> A new check is added in dt init functions (setup.c) to prepare for SoCs
>> supporting new clk implementation. These SoCs won't setup the
>> register_clocks callback (clk registration is done using of_clk_init).
>>
>> Signed-off-by: Boris BREZILLON <b.brezillon@overkiz.com>
>> ---
>>   arch/arm/mach-at91/Kconfig        |   21 +++++++++++++++++++++
>>   arch/arm/mach-at91/Kconfig.non_dt |    6 ++++++
>>   arch/arm/mach-at91/Makefile       |    2 +-
>>   arch/arm/mach-at91/generic.h      |    3 ++-
>>   arch/arm/mach-at91/setup.c        |    6 ++++--
>>   5 files changed, 34 insertions(+), 4 deletions(-)
>>
>> diff --git a/arch/arm/mach-at91/Kconfig b/arch/arm/mach-at91/Kconfig
>> index 699b71e..85b53a4 100644
>> --- a/arch/arm/mach-at91/Kconfig
>> +++ b/arch/arm/mach-at91/Kconfig
>> @@ -6,10 +6,22 @@ config HAVE_AT91_DBGU0
>>   config HAVE_AT91_DBGU1
>>       bool
>>
>> +config AT91_USE_OLD_CLK
>> +    bool
>> +
>>   config AT91_PMC_UNIT
>>       bool
>>       default !ARCH_AT91X40
>>
>> +config COMMON_CLK_AT91
>> +    bool
>> +    default AT91_PMC_UNIT && USE_OF && !AT91_USE_OLD_CLK
>> +    select COMMON_CLK
>> +
>> +config OLD_CLK_AT91
>> +    bool
>> +    default AT91_PMC_UNIT && AT91_USE_OLD_CLK
>> +
>>   config AT91_SAM9_ALT_RESET
>>       bool
>>       default !ARCH_AT91X40
>> @@ -65,6 +77,7 @@ config SOC_SAMA5D3
>>       select SOC_SAMA5
>>       select HAVE_FB_ATMEL
>>       select HAVE_AT91_DBGU1
>> +    select AT91_USE_OLD_CLK
>>       help
>>         Select this if you are using one of Atmel's SAMA5D3 family SoC.
>>         This support covers SAMA5D31, SAMA5D33, SAMA5D34, SAMA5D35.
>> @@ -78,11 +91,13 @@ config SOC_AT91RM9200
>>       select HAVE_AT91_DBGU0
>>       select MULTI_IRQ_HANDLER
>>       select SPARSE_IRQ
>> +    select AT91_USE_OLD_CLK
>>
>>   config SOC_AT91SAM9260
>>       bool "AT91SAM9260, AT91SAM9XE or AT91SAM9G20"
>>       select HAVE_AT91_DBGU0
>>       select SOC_AT91SAM9
>> +    select AT91_USE_OLD_CLK
>>       help
>>         Select this if you are using one of Atmel's AT91SAM9260, 
>> AT91SAM9XE
>>         or AT91SAM9G20 SoC.
>> @@ -92,6 +107,7 @@ config SOC_AT91SAM9261
>>       select HAVE_AT91_DBGU0
>>       select HAVE_FB_ATMEL
>>       select SOC_AT91SAM9
>> +    select AT91_USE_OLD_CLK
>>       help
>>         Select this if you are using one of Atmel's AT91SAM9261 or 
>> AT91SAM9G10 SoC.
>>
>> @@ -100,18 +116,21 @@ config SOC_AT91SAM9263
>>       select HAVE_AT91_DBGU1
>>       select HAVE_FB_ATMEL
>>       select SOC_AT91SAM9
>> +    select AT91_USE_OLD_CLK
>>
>>   config SOC_AT91SAM9RL
>>       bool "AT91SAM9RL"
>>       select HAVE_AT91_DBGU0
>>       select HAVE_FB_ATMEL
>>       select SOC_AT91SAM9
>> +    select AT91_USE_OLD_CLK
>>
>>   config SOC_AT91SAM9G45
>>       bool "AT91SAM9G45 or AT91SAM9M10 families"
>>       select HAVE_AT91_DBGU1
>>       select HAVE_FB_ATMEL
>>       select SOC_AT91SAM9
>> +    select AT91_USE_OLD_CLK
>>       help
>>         Select this if you are using one of Atmel's AT91SAM9G45 
>> family SoC.
>>         This support covers AT91SAM9G45, AT91SAM9G46, AT91SAM9M10 and 
>> AT91SAM9M11.
>> @@ -121,6 +140,7 @@ config SOC_AT91SAM9X5
>>       select HAVE_AT91_DBGU0
>>       select HAVE_FB_ATMEL
>>       select SOC_AT91SAM9
>> +    select AT91_USE_OLD_CLK
>>       help
>>         Select this if you are using one of Atmel's AT91SAM9x5 family 
>> SoC.
>>         This means that your SAM9 name finishes with a '5' (except if 
>> it is
>> @@ -133,6 +153,7 @@ config SOC_AT91SAM9N12
>>       select HAVE_AT91_DBGU0
>>       select HAVE_FB_ATMEL
>>       select SOC_AT91SAM9
>> +    select AT91_USE_OLD_CLK
>>       help
>>         Select this if you are using Atmel's AT91SAM9N12 SoC.
>>
>> diff --git a/arch/arm/mach-at91/Kconfig.non_dt 
>> b/arch/arm/mach-at91/Kconfig.non_dt
>> index ca900be..b736b57 100644
>> --- a/arch/arm/mach-at91/Kconfig.non_dt
>> +++ b/arch/arm/mach-at91/Kconfig.non_dt
>> @@ -12,26 +12,32 @@ config ARCH_AT91_NONE
>>   config ARCH_AT91RM9200
>>       bool "AT91RM9200"
>>       select SOC_AT91RM9200
>> +    select AT91_USE_OLD_CLK
>>
>>   config ARCH_AT91SAM9260
>>       bool "AT91SAM9260 or AT91SAM9XE or AT91SAM9G20"
>>       select SOC_AT91SAM9260
>> +    select AT91_USE_OLD_CLK
>>
>>   config ARCH_AT91SAM9261
>>       bool "AT91SAM9261 or AT91SAM9G10"
>>       select SOC_AT91SAM9261
>> +    select AT91_USE_OLD_CLK
>>
>>   config ARCH_AT91SAM9263
>>       bool "AT91SAM9263"
>>       select SOC_AT91SAM9263
>> +    select AT91_USE_OLD_CLK
>>
>>   config ARCH_AT91SAM9RL
>>       bool "AT91SAM9RL"
>>       select SOC_AT91SAM9RL
>> +    select AT91_USE_OLD_CLK
>>
>>   config ARCH_AT91SAM9G45
>>       bool "AT91SAM9G45"
>>       select SOC_AT91SAM9G45
>> +    select AT91_USE_OLD_CLK
>>
>>   config ARCH_AT91X40
>>       bool "AT91x40"
>> diff --git a/arch/arm/mach-at91/Makefile b/arch/arm/mach-at91/Makefile
>> index 3b0a953..8539411 100644
>> --- a/arch/arm/mach-at91/Makefile
>> +++ b/arch/arm/mach-at91/Makefile
>> @@ -7,7 +7,7 @@ obj-m        :=
>>   obj-n        :=
>>   obj-        :=
>>
>> -obj-$(CONFIG_AT91_PMC_UNIT)    += clock.o
>> +obj-$(CONFIG_OLD_CLK_AT91)    += clock.o
>>   obj-$(CONFIG_AT91_SAM9_ALT_RESET) += at91sam9_alt_reset.o
>>   obj-$(CONFIG_AT91_SAM9G45_RESET) += at91sam9g45_reset.o
>>   obj-$(CONFIG_AT91_SAM9_TIME)    += at91sam926x_time.o
>> diff --git a/arch/arm/mach-at91/generic.h b/arch/arm/mach-at91/generic.h
>> index dc6e2f5..375c42e 100644
>> --- a/arch/arm/mach-at91/generic.h
>> +++ b/arch/arm/mach-at91/generic.h
>> @@ -44,11 +44,12 @@ extern void at91sam926x_pit_init(void);
>>   extern void at91x40_timer_init(void);
>>
>>    /* Clocks */
>> -#ifdef CONFIG_AT91_PMC_UNIT
>> +#ifdef CONFIG_OLD_CLK_AT91
>>   extern int __init at91_clock_init(unsigned long main_clock);
>>   extern int __init at91_dt_clock_init(void);
>>   #else
>>   static int inline at91_clock_init(unsigned long main_clock) { 
>> return 0; }
>> +static int inline at91_dt_clock_init(void) { return 0; }
>>   #endif
>>   struct device;
>>
>> diff --git a/arch/arm/mach-at91/setup.c b/arch/arm/mach-at91/setup.c
>> index 41aa68b..06052fc 100644
>> --- a/arch/arm/mach-at91/setup.c
>> +++ b/arch/arm/mach-at91/setup.c
>> @@ -483,7 +483,8 @@ void __init at91rm9200_dt_initialize(void)
>>       at91_dt_clock_init();
>>
>>       /* Register the processor-specific clocks */
>> -    at91_boot_soc.register_clocks();
>> +    if (at91_boot_soc.register_clocks)
>> +        at91_boot_soc.register_clocks();
>>
>>       at91_boot_soc.init();
>>   }
>> @@ -498,7 +499,8 @@ void __init at91_dt_initialize(void)
>>       at91_dt_clock_init();
>>
>>       /* Register the processor-specific clocks */
>> -    at91_boot_soc.register_clocks();
>> +    if (at91_boot_soc.register_clocks)
>> +        at91_boot_soc.register_clocks();
>>
>>       if (at91_boot_soc.init)
>>           at91_boot_soc.init();
>>
>
>


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

* Re: [PATCH v3 02/19] ARM: at91: add Kconfig options for common clk support
  2013-10-09  9:56     ` boris brezillon
@ 2013-10-09 10:05       ` Nicolas Ferre
  0 siblings, 0 replies; 54+ messages in thread
From: Nicolas Ferre @ 2013-10-09 10:05 UTC (permalink / raw)
  To: boris brezillon, Grant Likely, Rob Herring, Rob Landley,
	Andrew Victor, Jean-Christophe Plagniol-Villard, Russell King,
	Mike Turquette, Felipe Balbi, Greg Kroah-Hartman,
	Ludovic Desroches, Josh Wu, Richard Genoud
  Cc: devicetree, linux-kernel, linux-arm-kernel

On 09/10/2013 11:56, boris brezillon :
> On 07/10/2013 17:12, Nicolas Ferre wrote:
>> On 08/08/2013 07:02, Boris BREZILLON :
>>> This patch adds the following Kconfig options to prepare the
>>> transition to
>>> common clk framework:
>>>
>>> - AT91_USE_OLD_CLK: this option is selected by every SoC which does not
>>>     support new at91 clks based on common clk framework (SoC which
>>> does not
>>>     define the clock tree in its device tree).
>>>     This options is also selected when the user choose non dt boards
>>> support
>>>     (new at91 clks can only be registered from a device tree definition).
>>>
>>> - COMMON_CLK_AT91: this option cannot be selected directly. Instead
>>> it is
>>
>> I would have prefered to keep "AT91" as a prefix => "AT91_COMMON_CLK"
>> But it is not so important.
>>
> Now I remember why I choose this name.
> Take a look at drivers/clk/Makefile, the chip specific clks are defined
> this way:
>
> COMMON_CLK_XXX.
>
> Do you still want to rename it ?

Nope!

>
>>>     enabled if these 3 conditions are met:
>>>      * at least one of the selected SoCs have a PMC (Power Management
>>>        Controller) Unit
>>>      * device tree support is enabled
>>>      * the old at91 clk implementation is disabled (every selected SoC
>>> define
>>>        its clks in its device tree and non dt boards support is disabled)
>>>
>>> - OLD_CLK_AT91: this option cannot be selected directly. Instead it is
>>
>> Here also.
>>
>
> I can change this one.

No, let's stick to what you defined it will be fine.


>>>     enabled if these 2 conditions are met:
>>>      * at least one of the selected SoCs have a PMC (Power Management
>>>        Controller) Unit
>>>      * at least one of the selected SoCs does not define its clks in its
>>>        device tree or non dt-boards support is enabled
>>>
>>> This patch selects AT91_USE_OLD_CLK in all currently supported SoCs.
>>> These
>>> selects will be removed after clk definitions are properly added in each
>>> soc's device tree.
>>> It also selects AT91_USE_OLD_CLK in all non-dt boards support.
>>>
>>> AT91_PMC_UNIT references are replaced by OLD_CLK_AT91, because PMC
>>> Unit is
>>> enabled for both old and common clk implementations, and old clk
>>> implementation should not be compiled if COMMON_CLK is enabled.
>>>
>>> To avoid future link errors, a new stub is created for
>>> at91_dt_clock_init
>>> function if OLD_CLK_AT91 is disabled.
>>>
>>> A new check is added in dt init functions (setup.c) to prepare for SoCs
>>> supporting new clk implementation. These SoCs won't setup the
>>> register_clocks callback (clk registration is done using of_clk_init).
>>>
>>> Signed-off-by: Boris BREZILLON <b.brezillon@overkiz.com>
>>> ---
>>>    arch/arm/mach-at91/Kconfig        |   21 +++++++++++++++++++++
>>>    arch/arm/mach-at91/Kconfig.non_dt |    6 ++++++
>>>    arch/arm/mach-at91/Makefile       |    2 +-
>>>    arch/arm/mach-at91/generic.h      |    3 ++-
>>>    arch/arm/mach-at91/setup.c        |    6 ++++--
>>>    5 files changed, 34 insertions(+), 4 deletions(-)
>>>
>>> diff --git a/arch/arm/mach-at91/Kconfig b/arch/arm/mach-at91/Kconfig
>>> index 699b71e..85b53a4 100644
>>> --- a/arch/arm/mach-at91/Kconfig
>>> +++ b/arch/arm/mach-at91/Kconfig
>>> @@ -6,10 +6,22 @@ config HAVE_AT91_DBGU0
>>>    config HAVE_AT91_DBGU1
>>>        bool
>>>
>>> +config AT91_USE_OLD_CLK
>>> +    bool
>>> +
>>>    config AT91_PMC_UNIT
>>>        bool
>>>        default !ARCH_AT91X40
>>>
>>> +config COMMON_CLK_AT91
>>> +    bool
>>> +    default AT91_PMC_UNIT && USE_OF && !AT91_USE_OLD_CLK
>>> +    select COMMON_CLK
>>> +
>>> +config OLD_CLK_AT91
>>> +    bool
>>> +    default AT91_PMC_UNIT && AT91_USE_OLD_CLK
>>> +
>>>    config AT91_SAM9_ALT_RESET
>>>        bool
>>>        default !ARCH_AT91X40
>>> @@ -65,6 +77,7 @@ config SOC_SAMA5D3
>>>        select SOC_SAMA5
>>>        select HAVE_FB_ATMEL
>>>        select HAVE_AT91_DBGU1
>>> +    select AT91_USE_OLD_CLK
>>>        help
>>>          Select this if you are using one of Atmel's SAMA5D3 family SoC.
>>>          This support covers SAMA5D31, SAMA5D33, SAMA5D34, SAMA5D35.
>>> @@ -78,11 +91,13 @@ config SOC_AT91RM9200
>>>        select HAVE_AT91_DBGU0
>>>        select MULTI_IRQ_HANDLER
>>>        select SPARSE_IRQ
>>> +    select AT91_USE_OLD_CLK
>>>
>>>    config SOC_AT91SAM9260
>>>        bool "AT91SAM9260, AT91SAM9XE or AT91SAM9G20"
>>>        select HAVE_AT91_DBGU0
>>>        select SOC_AT91SAM9
>>> +    select AT91_USE_OLD_CLK
>>>        help
>>>          Select this if you are using one of Atmel's AT91SAM9260,
>>> AT91SAM9XE
>>>          or AT91SAM9G20 SoC.
>>> @@ -92,6 +107,7 @@ config SOC_AT91SAM9261
>>>        select HAVE_AT91_DBGU0
>>>        select HAVE_FB_ATMEL
>>>        select SOC_AT91SAM9
>>> +    select AT91_USE_OLD_CLK
>>>        help
>>>          Select this if you are using one of Atmel's AT91SAM9261 or
>>> AT91SAM9G10 SoC.
>>>
>>> @@ -100,18 +116,21 @@ config SOC_AT91SAM9263
>>>        select HAVE_AT91_DBGU1
>>>        select HAVE_FB_ATMEL
>>>        select SOC_AT91SAM9
>>> +    select AT91_USE_OLD_CLK
>>>
>>>    config SOC_AT91SAM9RL
>>>        bool "AT91SAM9RL"
>>>        select HAVE_AT91_DBGU0
>>>        select HAVE_FB_ATMEL
>>>        select SOC_AT91SAM9
>>> +    select AT91_USE_OLD_CLK
>>>
>>>    config SOC_AT91SAM9G45
>>>        bool "AT91SAM9G45 or AT91SAM9M10 families"
>>>        select HAVE_AT91_DBGU1
>>>        select HAVE_FB_ATMEL
>>>        select SOC_AT91SAM9
>>> +    select AT91_USE_OLD_CLK
>>>        help
>>>          Select this if you are using one of Atmel's AT91SAM9G45
>>> family SoC.
>>>          This support covers AT91SAM9G45, AT91SAM9G46, AT91SAM9M10 and
>>> AT91SAM9M11.
>>> @@ -121,6 +140,7 @@ config SOC_AT91SAM9X5
>>>        select HAVE_AT91_DBGU0
>>>        select HAVE_FB_ATMEL
>>>        select SOC_AT91SAM9
>>> +    select AT91_USE_OLD_CLK
>>>        help
>>>          Select this if you are using one of Atmel's AT91SAM9x5 family
>>> SoC.
>>>          This means that your SAM9 name finishes with a '5' (except if
>>> it is
>>> @@ -133,6 +153,7 @@ config SOC_AT91SAM9N12
>>>        select HAVE_AT91_DBGU0
>>>        select HAVE_FB_ATMEL
>>>        select SOC_AT91SAM9
>>> +    select AT91_USE_OLD_CLK
>>>        help
>>>          Select this if you are using Atmel's AT91SAM9N12 SoC.
>>>
>>> diff --git a/arch/arm/mach-at91/Kconfig.non_dt
>>> b/arch/arm/mach-at91/Kconfig.non_dt
>>> index ca900be..b736b57 100644
>>> --- a/arch/arm/mach-at91/Kconfig.non_dt
>>> +++ b/arch/arm/mach-at91/Kconfig.non_dt
>>> @@ -12,26 +12,32 @@ config ARCH_AT91_NONE
>>>    config ARCH_AT91RM9200
>>>        bool "AT91RM9200"
>>>        select SOC_AT91RM9200
>>> +    select AT91_USE_OLD_CLK
>>>
>>>    config ARCH_AT91SAM9260
>>>        bool "AT91SAM9260 or AT91SAM9XE or AT91SAM9G20"
>>>        select SOC_AT91SAM9260
>>> +    select AT91_USE_OLD_CLK
>>>
>>>    config ARCH_AT91SAM9261
>>>        bool "AT91SAM9261 or AT91SAM9G10"
>>>        select SOC_AT91SAM9261
>>> +    select AT91_USE_OLD_CLK
>>>
>>>    config ARCH_AT91SAM9263
>>>        bool "AT91SAM9263"
>>>        select SOC_AT91SAM9263
>>> +    select AT91_USE_OLD_CLK
>>>
>>>    config ARCH_AT91SAM9RL
>>>        bool "AT91SAM9RL"
>>>        select SOC_AT91SAM9RL
>>> +    select AT91_USE_OLD_CLK
>>>
>>>    config ARCH_AT91SAM9G45
>>>        bool "AT91SAM9G45"
>>>        select SOC_AT91SAM9G45
>>> +    select AT91_USE_OLD_CLK
>>>
>>>    config ARCH_AT91X40
>>>        bool "AT91x40"
>>> diff --git a/arch/arm/mach-at91/Makefile b/arch/arm/mach-at91/Makefile
>>> index 3b0a953..8539411 100644
>>> --- a/arch/arm/mach-at91/Makefile
>>> +++ b/arch/arm/mach-at91/Makefile
>>> @@ -7,7 +7,7 @@ obj-m        :=
>>>    obj-n        :=
>>>    obj-        :=
>>>
>>> -obj-$(CONFIG_AT91_PMC_UNIT)    += clock.o
>>> +obj-$(CONFIG_OLD_CLK_AT91)    += clock.o
>>>    obj-$(CONFIG_AT91_SAM9_ALT_RESET) += at91sam9_alt_reset.o
>>>    obj-$(CONFIG_AT91_SAM9G45_RESET) += at91sam9g45_reset.o
>>>    obj-$(CONFIG_AT91_SAM9_TIME)    += at91sam926x_time.o
>>> diff --git a/arch/arm/mach-at91/generic.h b/arch/arm/mach-at91/generic.h
>>> index dc6e2f5..375c42e 100644
>>> --- a/arch/arm/mach-at91/generic.h
>>> +++ b/arch/arm/mach-at91/generic.h
>>> @@ -44,11 +44,12 @@ extern void at91sam926x_pit_init(void);
>>>    extern void at91x40_timer_init(void);
>>>
>>>     /* Clocks */
>>> -#ifdef CONFIG_AT91_PMC_UNIT
>>> +#ifdef CONFIG_OLD_CLK_AT91
>>>    extern int __init at91_clock_init(unsigned long main_clock);
>>>    extern int __init at91_dt_clock_init(void);
>>>    #else
>>>    static int inline at91_clock_init(unsigned long main_clock) {
>>> return 0; }
>>> +static int inline at91_dt_clock_init(void) { return 0; }
>>>    #endif
>>>    struct device;
>>>
>>> diff --git a/arch/arm/mach-at91/setup.c b/arch/arm/mach-at91/setup.c
>>> index 41aa68b..06052fc 100644
>>> --- a/arch/arm/mach-at91/setup.c
>>> +++ b/arch/arm/mach-at91/setup.c
>>> @@ -483,7 +483,8 @@ void __init at91rm9200_dt_initialize(void)
>>>        at91_dt_clock_init();
>>>
>>>        /* Register the processor-specific clocks */
>>> -    at91_boot_soc.register_clocks();
>>> +    if (at91_boot_soc.register_clocks)
>>> +        at91_boot_soc.register_clocks();
>>>
>>>        at91_boot_soc.init();
>>>    }
>>> @@ -498,7 +499,8 @@ void __init at91_dt_initialize(void)
>>>        at91_dt_clock_init();
>>>
>>>        /* Register the processor-specific clocks */
>>> -    at91_boot_soc.register_clocks();
>>> +    if (at91_boot_soc.register_clocks)
>>> +        at91_boot_soc.register_clocks();
>>>
>>>        if (at91_boot_soc.init)
>>>            at91_boot_soc.init();
>>>
>>
>>
>
>
>


-- 
Nicolas Ferre

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

end of thread, other threads:[~2013-10-09 10:05 UTC | newest]

Thread overview: 54+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2013-08-08  4:53 [PATCH v3 00/19] ARM: at91: move to common clk framework Boris BREZILLON
2013-08-08  4:59 ` [PATCH v3 01/19] ARM: at91: move at91_pmc.h to include/linux/clk/at91_pmc.h Boris BREZILLON
2013-08-08  5:01 ` [PATCH v3 03/19] clk: at91: add PMC base support Boris BREZILLON
2013-10-07 15:07   ` Nicolas Ferre
2013-10-07 15:57     ` boris brezillon
2013-08-08  5:02 ` [PATCH v3 02/19] ARM: at91: add Kconfig options for common clk support Boris BREZILLON
2013-10-07 15:12   ` Nicolas Ferre
2013-10-07 16:05     ` boris brezillon
2013-10-09  9:56     ` boris brezillon
2013-10-09 10:05       ` Nicolas Ferre
2013-08-08  5:04 ` [PATCH v3 04/19] clk: at91: add PMC macro file for dt definitions Boris BREZILLON
2013-10-07 15:17   ` Nicolas Ferre
2013-10-07 16:06     ` boris brezillon
2013-08-08  5:06 ` [PATCH v3 05/19] clk: at91: add PMC main clock Boris BREZILLON
2013-10-07 16:51   ` Nicolas Ferre
2013-10-07 19:11     ` boris brezillon
2013-10-08  8:24       ` Nicolas Ferre
2013-10-08  9:00         ` boris brezillon
2013-08-08  6:07 ` [PATCH v3 06/19] clk: at91: add PMC pll clocks Boris BREZILLON
2013-10-08 10:28   ` Nicolas Ferre
2013-10-08 11:45     ` boris brezillon
2013-08-08  6:09 ` [PATCH v3 07/19] clk: at91: add pll id macros for pll dt bindings Boris BREZILLON
2013-10-08 10:30   ` Nicolas Ferre
2013-10-08 12:03     ` boris brezillon
2013-08-08  6:10 ` [PATCH v3 08/19] clk: at91: add PMC master clock Boris BREZILLON
2013-08-08  6:12 ` [PATCH v3 09/19] clk: at91: add PMC system clocks Boris BREZILLON
2013-10-08 15:32   ` Nicolas Ferre
2013-08-08  6:15 ` [PATCH v3 10/19] ARM: at91/dt: add system clk id definitions in dt-bindings include dir Boris BREZILLON
2013-10-08 15:36   ` Nicolas Ferre
2013-08-08  6:16 ` [PATCH v3 11/19] clk: at91: add PMC peripheral clocks Boris BREZILLON
2013-10-08 15:43   ` Nicolas Ferre
2013-08-08  7:10 ` [PATCH v3 12/19] clk: at91: add peripheral clk macros for peripheral clk dt bindings Boris BREZILLON
2013-10-08 15:44   ` Nicolas Ferre
2013-10-08 16:01     ` boris brezillon
2013-10-08 16:15       ` Nicolas Ferre
2013-10-08 16:19         ` boris brezillon
2013-08-08  7:12 ` [PATCH v3 13/19] clk: at91: add PMC programmable clocks Boris BREZILLON
2013-10-08 16:02   ` Nicolas Ferre
2013-10-08 16:06     ` Nicolas Ferre
2013-08-08  7:14 ` [PATCH v3 14/19] clk: at91: add PMC utmi clock Boris BREZILLON
2013-10-08 16:08   ` Nicolas Ferre
2013-08-08  7:15 ` [PATCH v3 15/19] clk: at91: add PMC usb clock Boris BREZILLON
2013-10-08 16:20   ` Nicolas Ferre
2013-08-08  7:17 ` [PATCH v3 16/19] clk: at91: add PMC smd clock Boris BREZILLON
2013-10-08 16:22   ` Nicolas Ferre
2013-08-08  7:19 ` [PATCH v3 17/19] clk: at91: add PMC clk device tree binding doc Boris BREZILLON
2013-10-08  9:44   ` Nicolas Ferre
2013-10-08 12:37     ` boris brezillon
2013-10-08 12:42       ` Nicolas Ferre
2013-08-08  8:17 ` [PATCH v3 18/19] ARM: at91: move pit timer to common clk framework Boris BREZILLON
2013-10-08 16:28   ` Nicolas Ferre
2013-08-08  8:19 ` [PATCH v3 19/19] ARM: at91: add new compatible strings for pmc driver Boris BREZILLON
2013-10-08 16:29   ` Nicolas Ferre
2013-08-20 10:21 ` [PATCH v3 00/19] ARM: at91: move to common clk framework boris brezillon

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