Re: [PATCH v3 03/19] clk: at91: add PMC base support

2013-10-07 Thread boris brezillon

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 
---
  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 000..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 000..f6bd03d
--- /dev/null
+++ b/drivers/clk/at91/pmc.c
@@ -0,0 +1,298 @@
+/*
+ * drivers/clk/at91/pmc.c
+ *
+ *  Copyright (C) 2013 Boris BREZILLON 
+ *
+ * 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 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+
+#include 
+
+#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, _lock_class);
+
+irq_set_chip_and_handler(virq, _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 

Re: [PATCH v3 03/19] clk: at91: add PMC base support

2013-10-07 Thread Nicolas Ferre

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 
---
  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 000..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 000..f6bd03d
--- /dev/null
+++ b/drivers/clk/at91/pmc.c
@@ -0,0 +1,298 @@
+/*
+ * drivers/clk/at91/pmc.c
+ *
+ *  Copyright (C) 2013 Boris BREZILLON 
+ *
+ * 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 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+
+#include 
+
+#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, _lock_class);
+
+   irq_set_chip_and_handler(virq, _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;

Re: [PATCH v3 03/19] clk: at91: add PMC base support

2013-10-07 Thread Nicolas Ferre

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.brezil...@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 000..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 000..f6bd03d
--- /dev/null
+++ b/drivers/clk/at91/pmc.c
@@ -0,0 +1,298 @@
+/*
+ * drivers/clk/at91/pmc.c
+ *
+ *  Copyright (C) 2013 Boris BREZILLON b.brezil...@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 

Re: [PATCH v3 03/19] clk: at91: add PMC base support

2013-10-07 Thread boris brezillon

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.brezil...@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 000..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 000..f6bd03d
--- /dev/null
+++ b/drivers/clk/at91/pmc.c
@@ -0,0 +1,298 @@
+/*
+ * drivers/clk/at91/pmc.c
+ *
+ *  Copyright (C) 2013 Boris BREZILLON b.brezil...@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]  

[PATCH v3 03/19] clk: at91: add PMC base support

2013-08-07 Thread 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 
---
 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 000..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 000..f6bd03d
--- /dev/null
+++ b/drivers/clk/at91/pmc.c
@@ -0,0 +1,298 @@
+/*
+ * drivers/clk/at91/pmc.c
+ *
+ *  Copyright (C) 2013 Boris BREZILLON 
+ *
+ * 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 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+
+#include 
+
+#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, _lock_class);
+
+   irq_set_chip_and_handler(virq, _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)
+  

[PATCH v3 03/19] clk: at91: add PMC base support

2013-08-07 Thread 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.brezil...@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 000..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 000..f6bd03d
--- /dev/null
+++ b/drivers/clk/at91/pmc.c
@@ -0,0 +1,298 @@
+/*
+ * drivers/clk/at91/pmc.c
+ *
+ *  Copyright (C) 2013 Boris BREZILLON b.brezil...@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;