Re: [PATCH v3 03/19] clk: at91: add PMC base support
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
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
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
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
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
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;