From 9020b7cc27439e23a0e993f79ef8632fea5e88d5 Mon Sep 17 00:00:00 2001 From: Daniel Mack Date: Thu, 19 Jul 2012 19:58:39 +0200 Subject: RTC: add DT bindings to pxa-rtc This patch adds generic device tree bindings to the PXA RTC driver. Documentation for bindings were also added. Signed-off-by: Daniel Mack Cc: Robert Jarzmik Cc: Alessandro Zummo Acked-by: Arnd Bergmann Signed-off-by: Haojian Zhuang --- drivers/rtc/rtc-pxa.c | 11 +++++++++++ 1 file changed, 11 insertions(+) (limited to 'drivers') diff --git a/drivers/rtc/rtc-pxa.c b/drivers/rtc/rtc-pxa.c index 0075c8fd93d8..f771b2ee4b18 100644 --- a/drivers/rtc/rtc-pxa.c +++ b/drivers/rtc/rtc-pxa.c @@ -27,6 +27,8 @@ #include #include #include +#include +#include #include @@ -396,6 +398,14 @@ static int __exit pxa_rtc_remove(struct platform_device *pdev) return 0; } +#ifdef CONFIG_OF +static struct of_device_id pxa_rtc_dt_ids[] = { + { .compatible = "marvell,pxa-rtc" }, + {} +}; +MODULE_DEVICE_TABLE(of, pxa_rtc_dt_ids); +#endif + #ifdef CONFIG_PM static int pxa_rtc_suspend(struct device *dev) { @@ -425,6 +435,7 @@ static struct platform_driver pxa_rtc_driver = { .remove = __exit_p(pxa_rtc_remove), .driver = { .name = "pxa-rtc", + .of_match_table = of_match_ptr(pxa_rtc_dt_ids), #ifdef CONFIG_PM .pm = &pxa_rtc_pm_ops, #endif -- cgit v1.2.3 From 1e7ba630d4aeabef8e022a4099b20ab9f660d37d Mon Sep 17 00:00:00 2001 From: Daniel Mack Date: Sun, 22 Jul 2012 19:51:02 +0200 Subject: MTD: pxa3xx-nand: add devicetree bindings This patch contains a hack to get the DMA resources of the device when probed from a devicetree node. This can be removed once a generic DMA controller framework lands. A mtd_part_parser_data is passed mtd_device_parse_register which contains a reference to the device node, so MTD partitions can be added as children. Signed-off-by: Daniel Mack Cc: David Woodhouse Acked-by: Arnd Bergmann Signed-off-by: Haojian Zhuang --- .../devicetree/bindings/mtd/pxa3xx-nand.txt | 31 ++++++++ drivers/mtd/nand/pxa3xx_nand.c | 85 ++++++++++++++++++---- 2 files changed, 102 insertions(+), 14 deletions(-) create mode 100644 Documentation/devicetree/bindings/mtd/pxa3xx-nand.txt (limited to 'drivers') diff --git a/Documentation/devicetree/bindings/mtd/pxa3xx-nand.txt b/Documentation/devicetree/bindings/mtd/pxa3xx-nand.txt new file mode 100644 index 000000000000..f1421e2bbab7 --- /dev/null +++ b/Documentation/devicetree/bindings/mtd/pxa3xx-nand.txt @@ -0,0 +1,31 @@ +PXA3xx NAND DT bindings + +Required properties: + + - compatible: Should be "marvell,pxa3xx-nand" + - reg: The register base for the controller + - interrupts: The interrupt to map + - #address-cells: Set to <1> if the node includes partitions + +Optional properties: + + - marvell,nand-enable-arbiter: Set to enable the bus arbiter + - marvell,nand-keep-config: Set to keep the NAND controller config as set + by the bootloader + - num-cs: Number of chipselect lines to usw + +Example: + + nand0: nand@43100000 { + compatible = "marvell,pxa3xx-nand"; + reg = <0x43100000 90>; + interrupts = <45>; + #address-cells = <1>; + + marvell,nand-enable-arbiter; + marvell,nand-keep-config; + num-cs = <1>; + + /* partitions (optional) */ + }; + diff --git a/drivers/mtd/nand/pxa3xx_nand.c b/drivers/mtd/nand/pxa3xx_nand.c index 252aaefcacfa..b0319d8934ad 100644 --- a/drivers/mtd/nand/pxa3xx_nand.c +++ b/drivers/mtd/nand/pxa3xx_nand.c @@ -22,6 +22,8 @@ #include #include #include +#include +#include #include #include @@ -1081,21 +1083,31 @@ static int alloc_nand_resource(struct platform_device *pdev) } clk_enable(info->clk); - r = platform_get_resource(pdev, IORESOURCE_DMA, 0); - if (r == NULL) { - dev_err(&pdev->dev, "no resource defined for data DMA\n"); - ret = -ENXIO; - goto fail_put_clk; - } - info->drcmr_dat = r->start; + /* + * This is a dirty hack to make this driver work from devicetree + * bindings. It can be removed once we have a prober DMA controller + * framework for DT. + */ + if (pdev->dev.of_node && cpu_is_pxa3xx()) { + info->drcmr_dat = 97; + info->drcmr_cmd = 99; + } else { + r = platform_get_resource(pdev, IORESOURCE_DMA, 0); + if (r == NULL) { + dev_err(&pdev->dev, "no resource defined for data DMA\n"); + ret = -ENXIO; + goto fail_put_clk; + } + info->drcmr_dat = r->start; - r = platform_get_resource(pdev, IORESOURCE_DMA, 1); - if (r == NULL) { - dev_err(&pdev->dev, "no resource defined for command DMA\n"); - ret = -ENXIO; - goto fail_put_clk; + r = platform_get_resource(pdev, IORESOURCE_DMA, 1); + if (r == NULL) { + dev_err(&pdev->dev, "no resource defined for command DMA\n"); + ret = -ENXIO; + goto fail_put_clk; + } + info->drcmr_cmd = r->start; } - info->drcmr_cmd = r->start; irq = platform_get_irq(pdev, 0); if (irq < 0) { @@ -1200,12 +1212,55 @@ static int pxa3xx_nand_remove(struct platform_device *pdev) return 0; } +#ifdef CONFIG_OF +static struct of_device_id pxa3xx_nand_dt_ids[] = { + { .compatible = "marvell,pxa3xx-nand" }, + {} +}; +MODULE_DEVICE_TABLE(of, i2c_pxa_dt_ids); + +static int pxa3xx_nand_probe_dt(struct platform_device *pdev) +{ + struct pxa3xx_nand_platform_data *pdata; + struct device_node *np = pdev->dev.of_node; + const struct of_device_id *of_id = + of_match_device(pxa3xx_nand_dt_ids, &pdev->dev); + + if (!of_id) + return 0; + + pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL); + if (!pdata) + return -ENOMEM; + + if (of_get_property(np, "marvell,nand-enable-arbiter", NULL)) + pdata->enable_arbiter = 1; + if (of_get_property(np, "marvell,nand-keep-config", NULL)) + pdata->keep_config = 1; + of_property_read_u32(np, "num-cs", &pdata->num_cs); + + pdev->dev.platform_data = pdata; + + return 0; +} +#else +static inline int pxa3xx_nand_probe_dt(struct platform_device *) +{ + return 0; +} +#endif + static int pxa3xx_nand_probe(struct platform_device *pdev) { struct pxa3xx_nand_platform_data *pdata; + struct mtd_part_parser_data ppdata = {}; struct pxa3xx_nand_info *info; int ret, cs, probe_success; + ret = pxa3xx_nand_probe_dt(pdev); + if (ret) + return ret; + pdata = pdev->dev.platform_data; if (!pdata) { dev_err(&pdev->dev, "no platform data defined\n"); @@ -1229,8 +1284,9 @@ static int pxa3xx_nand_probe(struct platform_device *pdev) continue; } + ppdata.of_node = pdev->dev.of_node; ret = mtd_device_parse_register(info->host[cs]->mtd, NULL, - NULL, pdata->parts[cs], + &ppdata, pdata->parts[cs], pdata->nr_parts[cs]); if (!ret) probe_success = 1; @@ -1306,6 +1362,7 @@ static int pxa3xx_nand_resume(struct platform_device *pdev) static struct platform_driver pxa3xx_nand_driver = { .driver = { .name = "pxa3xx-nand", + .of_match_table = of_match_ptr(pxa3xx_nand_dt_ids), }, .probe = pxa3xx_nand_probe, .remove = pxa3xx_nand_remove, -- cgit v1.2.3 From 9450be76d0e3ebedf301aa09e4f98b4d3a175229 Mon Sep 17 00:00:00 2001 From: Daniel Mack Date: Sun, 22 Jul 2012 16:55:44 +0200 Subject: GPIO: gpio-pxa: simplify pxa_gpio_to_irq() and pxa_irq_to_chip() Simplify the code in gpio-pxa.c and make them based on irq_base. When not probed from devicetree, initialize irq_base from PXA_GPIO_TO_IRQ() or MMP_GPIO_TO_IRQ(), respectively, so the non-DT case still works. Only tested on PXA3xx. Signed-off-by: Daniel Mack Acked-by: Arnd Bergmann Acked-by: Linus Walleij Signed-off-by: Haojian Zhuang --- drivers/gpio/gpio-pxa.c | 70 +++++++++++-------------------------------------- 1 file changed, 16 insertions(+), 54 deletions(-) (limited to 'drivers') diff --git a/drivers/gpio/gpio-pxa.c b/drivers/gpio/gpio-pxa.c index 58a6a63a6ece..6d0cb9dff27d 100644 --- a/drivers/gpio/gpio-pxa.c +++ b/drivers/gpio/gpio-pxa.c @@ -59,6 +59,7 @@ #define BANK_OFF(n) (((n) < 3) ? (n) << 2 : 0x100 + (((n) - 3) << 2)) int pxa_last_gpio; +static int irq_base; #ifdef CONFIG_OF static struct irq_domain *domain; @@ -166,63 +167,14 @@ static inline int __gpio_is_occupied(unsigned gpio) return ret; } -#ifdef CONFIG_ARCH_PXA -static inline int __pxa_gpio_to_irq(int gpio) -{ - if (gpio_is_pxa_type(gpio_type)) - return PXA_GPIO_TO_IRQ(gpio); - return -1; -} - -static inline int __pxa_irq_to_gpio(int irq) -{ - if (gpio_is_pxa_type(gpio_type)) - return irq - PXA_GPIO_TO_IRQ(0); - return -1; -} -#else -static inline int __pxa_gpio_to_irq(int gpio) { return -1; } -static inline int __pxa_irq_to_gpio(int irq) { return -1; } -#endif - -#ifdef CONFIG_ARCH_MMP -static inline int __mmp_gpio_to_irq(int gpio) -{ - if (gpio_is_mmp_type(gpio_type)) - return MMP_GPIO_TO_IRQ(gpio); - return -1; -} - -static inline int __mmp_irq_to_gpio(int irq) -{ - if (gpio_is_mmp_type(gpio_type)) - return irq - MMP_GPIO_TO_IRQ(0); - return -1; -} -#else -static inline int __mmp_gpio_to_irq(int gpio) { return -1; } -static inline int __mmp_irq_to_gpio(int irq) { return -1; } -#endif - static int pxa_gpio_to_irq(struct gpio_chip *chip, unsigned offset) { - int gpio, ret; - - gpio = chip->base + offset; - ret = __pxa_gpio_to_irq(gpio); - if (ret >= 0) - return ret; - return __mmp_gpio_to_irq(gpio); + return chip->base + offset + irq_base; } int pxa_irq_to_gpio(int irq) { - int ret; - - ret = __pxa_irq_to_gpio(irq); - if (ret >= 0) - return ret; - return __mmp_irq_to_gpio(irq); + return irq - irq_base; } static int pxa_gpio_direction_input(struct gpio_chip *chip, unsigned offset) @@ -510,7 +462,7 @@ const struct irq_domain_ops pxa_irq_domain_ops = { #ifdef CONFIG_OF static int __devinit pxa_gpio_probe_dt(struct platform_device *pdev) { - int ret, nr_banks, nr_gpios, irq_base; + int ret, nr_banks, nr_gpios; struct device_node *prev, *next, *np = pdev->dev.of_node; const struct of_device_id *of_id = of_match_device(pxa_gpio_dt_ids, &pdev->dev); @@ -564,10 +516,20 @@ static int __devinit pxa_gpio_probe(struct platform_device *pdev) int irq0 = 0, irq1 = 0, irq_mux, gpio_offset = 0; ret = pxa_gpio_probe_dt(pdev); - if (ret < 0) + if (ret < 0) { pxa_last_gpio = pxa_gpio_nums(); - else +#ifdef CONFIG_ARCH_PXA + if (gpio_is_pxa_type(gpio_type)) + irq_base = PXA_GPIO_TO_IRQ(0); +#endif +#ifdef CONFIG_ARCH_MMP + if (gpio_is_mmp_type(gpio_type)) + irq_base = MMP_GPIO_TO_IRQ(0); +#endif + } else { use_of = 1; + } + if (!pxa_last_gpio) return -EINVAL; -- cgit v1.2.3 From 0d2ee5d773c209504db643ec4d4b9f3624a6663f Mon Sep 17 00:00:00 2001 From: Chao Xie Date: Tue, 31 Jul 2012 14:13:09 +0800 Subject: gpio: pxa: add chain_eneter and chain_exit for irq handler Signed-off-by: Chao Xie Signed-off-by: Haojian Zhuang --- drivers/gpio/gpio-pxa.c | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'drivers') diff --git a/drivers/gpio/gpio-pxa.c b/drivers/gpio/gpio-pxa.c index 6d0cb9dff27d..db5c2958f973 100644 --- a/drivers/gpio/gpio-pxa.c +++ b/drivers/gpio/gpio-pxa.c @@ -26,6 +26,8 @@ #include #include +#include + #include /* @@ -331,6 +333,9 @@ static void pxa_gpio_demux_handler(unsigned int irq, struct irq_desc *desc) struct pxa_gpio_chip *c; int loop, gpio, gpio_base, n; unsigned long gedr; + struct irq_chip *chip = irq_desc_get_chip(desc); + + chained_irq_enter(chip, desc); do { loop = 0; @@ -350,6 +355,8 @@ static void pxa_gpio_demux_handler(unsigned int irq, struct irq_desc *desc) } } } while (loop); + + chained_irq_exit(chip, desc); } static void pxa_ack_muxed_gpio(struct irq_data *d) -- cgit v1.2.3 From 6e308f87c821e5b9316d9eb69e96d8a33910412a Mon Sep 17 00:00:00 2001 From: Haojian Zhuang Date: Mon, 20 Aug 2012 13:40:31 +0800 Subject: mtd: nand: append missing parameter and value Signed-off-by: Haojian Zhuang --- drivers/mtd/nand/pxa3xx_nand.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/mtd/nand/pxa3xx_nand.c b/drivers/mtd/nand/pxa3xx_nand.c index b0319d8934ad..d944d6ef7da8 100644 --- a/drivers/mtd/nand/pxa3xx_nand.c +++ b/drivers/mtd/nand/pxa3xx_nand.c @@ -1034,7 +1034,7 @@ static int alloc_nand_resource(struct platform_device *pdev) struct pxa3xx_nand_platform_data *pdata; struct pxa3xx_nand_info *info; struct pxa3xx_nand_host *host; - struct nand_chip *chip; + struct nand_chip *chip = NULL; struct mtd_info *mtd; struct resource *r; int ret, irq, cs; @@ -1244,7 +1244,7 @@ static int pxa3xx_nand_probe_dt(struct platform_device *pdev) return 0; } #else -static inline int pxa3xx_nand_probe_dt(struct platform_device *) +static inline int pxa3xx_nand_probe_dt(struct platform_device *pdev) { return 0; } -- cgit v1.2.3 From f9a6aa4303bd15bbdb24d9fe374e4e6850298460 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Mon, 6 Aug 2012 18:32:08 +0200 Subject: clk: convert ARM RealView to common clk This converts the ARM RealView machine over to using the common clock. The approach is similar to the one used for the Integrator, and we're reusing the ICST wrapper code. We have to put the clock intialization in the timer init function for the clocks to be available when initializing the timer, keeping them in early_init() is too early for the common clk. Since we now have to go down and compile drivers/clk/versatile a CONFIG_COMMON_CLK_VERSATILE symbol has been added so the proper code gets compiled into the kernel for either machine. A leftover CLK_VERSATILE in the Integrator Kconfig was fixed up to use the new symbol as well. Tested on ARM RealView PB1176. Cc: Pawel Moll Signed-off-by: Linus Walleij Signed-off-by: Mike Turquette --- arch/arm/Kconfig | 7 +- arch/arm/mach-realview/core.c | 106 ------------------------- arch/arm/mach-realview/include/mach/clkdev.h | 16 ---- arch/arm/mach-realview/realview_eb.c | 2 + arch/arm/mach-realview/realview_pb1176.c | 2 + arch/arm/mach-realview/realview_pb11mp.c | 2 + arch/arm/mach-realview/realview_pba8.c | 2 + arch/arm/mach-realview/realview_pbx.c | 2 + drivers/clk/Kconfig | 7 ++ drivers/clk/Makefile | 2 +- drivers/clk/versatile/Makefile | 1 + drivers/clk/versatile/clk-realview.c | 114 +++++++++++++++++++++++++++ include/linux/platform_data/clk-realview.h | 1 + 13 files changed, 137 insertions(+), 127 deletions(-) delete mode 100644 arch/arm/mach-realview/include/mach/clkdev.h create mode 100644 drivers/clk/versatile/clk-realview.c create mode 100644 include/linux/platform_data/clk-realview.h (limited to 'drivers') diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index fb6014868d33..1a01ffa331d0 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig @@ -273,7 +273,7 @@ config ARCH_INTEGRATOR select ARM_AMBA select ARCH_HAS_CPUFREQ select COMMON_CLK - select CLK_VERSATILE + select COMMON_CLK_VERSATILE select HAVE_TCM select ICST select GENERIC_CLOCKEVENTS @@ -289,13 +289,12 @@ config ARCH_INTEGRATOR config ARCH_REALVIEW bool "ARM Ltd. RealView family" select ARM_AMBA - select CLKDEV_LOOKUP - select HAVE_MACH_CLKDEV + select COMMON_CLK + select COMMON_CLK_VERSATILE select ICST select GENERIC_CLOCKEVENTS select ARCH_WANT_OPTIONAL_GPIOLIB select PLAT_VERSATILE - select PLAT_VERSATILE_CLOCK select PLAT_VERSATILE_CLCD select ARM_TIMER_SP804 select GPIO_PL061 if GPIOLIB diff --git a/arch/arm/mach-realview/core.c b/arch/arm/mach-realview/core.c index 45868bb43cbd..ff007d15e0ec 100644 --- a/arch/arm/mach-realview/core.c +++ b/arch/arm/mach-realview/core.c @@ -30,7 +30,6 @@ #include #include #include -#include #include #include @@ -226,115 +225,10 @@ struct mmci_platform_data realview_mmc1_plat_data = { .cd_invert = true, }; -/* - * Clock handling - */ -static const struct icst_params realview_oscvco_params = { - .ref = 24000000, - .vco_max = ICST307_VCO_MAX, - .vco_min = ICST307_VCO_MIN, - .vd_min = 4 + 8, - .vd_max = 511 + 8, - .rd_min = 1 + 2, - .rd_max = 127 + 2, - .s2div = icst307_s2div, - .idx2s = icst307_idx2s, -}; - -static void realview_oscvco_set(struct clk *clk, struct icst_vco vco) -{ - void __iomem *sys_lock = __io_address(REALVIEW_SYS_BASE) + REALVIEW_SYS_LOCK_OFFSET; - u32 val; - - val = readl(clk->vcoreg) & ~0x7ffff; - val |= vco.v | (vco.r << 9) | (vco.s << 16); - - writel(0xa05f, sys_lock); - writel(val, clk->vcoreg); - writel(0, sys_lock); -} - -static const struct clk_ops oscvco_clk_ops = { - .round = icst_clk_round, - .set = icst_clk_set, - .setvco = realview_oscvco_set, -}; - -static struct clk oscvco_clk = { - .ops = &oscvco_clk_ops, - .params = &realview_oscvco_params, -}; - -/* - * These are fixed clocks. - */ -static struct clk ref24_clk = { - .rate = 24000000, -}; - -static struct clk sp804_clk = { - .rate = 1000000, -}; - -static struct clk dummy_apb_pclk; - -static struct clk_lookup lookups[] = { - { /* Bus clock */ - .con_id = "apb_pclk", - .clk = &dummy_apb_pclk, - }, { /* UART0 */ - .dev_id = "dev:uart0", - .clk = &ref24_clk, - }, { /* UART1 */ - .dev_id = "dev:uart1", - .clk = &ref24_clk, - }, { /* UART2 */ - .dev_id = "dev:uart2", - .clk = &ref24_clk, - }, { /* UART3 */ - .dev_id = "fpga:uart3", - .clk = &ref24_clk, - }, { /* UART3 is on the dev chip in PB1176 */ - .dev_id = "dev:uart3", - .clk = &ref24_clk, - }, { /* UART4 only exists in PB1176 */ - .dev_id = "fpga:uart4", - .clk = &ref24_clk, - }, { /* KMI0 */ - .dev_id = "fpga:kmi0", - .clk = &ref24_clk, - }, { /* KMI1 */ - .dev_id = "fpga:kmi1", - .clk = &ref24_clk, - }, { /* MMC0 */ - .dev_id = "fpga:mmc0", - .clk = &ref24_clk, - }, { /* CLCD is in the PB1176 and EB DevChip */ - .dev_id = "dev:clcd", - .clk = &oscvco_clk, - }, { /* PB:CLCD */ - .dev_id = "issp:clcd", - .clk = &oscvco_clk, - }, { /* SSP */ - .dev_id = "dev:ssp0", - .clk = &ref24_clk, - }, { /* SP804 timers */ - .dev_id = "sp804", - .clk = &sp804_clk, - }, -}; - void __init realview_init_early(void) { void __iomem *sys = __io_address(REALVIEW_SYS_BASE); - if (machine_is_realview_pb1176()) - oscvco_clk.vcoreg = sys + REALVIEW_SYS_OSC0_OFFSET; - else - oscvco_clk.vcoreg = sys + REALVIEW_SYS_OSC4_OFFSET; - - clkdev_add_table(lookups, ARRAY_SIZE(lookups)); - versatile_sched_clock_init(sys + REALVIEW_SYS_24MHz_OFFSET, 24000000); } diff --git a/arch/arm/mach-realview/include/mach/clkdev.h b/arch/arm/mach-realview/include/mach/clkdev.h deleted file mode 100644 index e58d0771b64e..000000000000 --- a/arch/arm/mach-realview/include/mach/clkdev.h +++ /dev/null @@ -1,16 +0,0 @@ -#ifndef __ASM_MACH_CLKDEV_H -#define __ASM_MACH_CLKDEV_H - -#include - -struct clk { - unsigned long rate; - const struct clk_ops *ops; - const struct icst_params *params; - void __iomem *vcoreg; -}; - -#define __clk_get(clk) ({ 1; }) -#define __clk_put(clk) do { } while (0) - -#endif diff --git a/arch/arm/mach-realview/realview_eb.c b/arch/arm/mach-realview/realview_eb.c index baf382c5e776..a33e33b76733 100644 --- a/arch/arm/mach-realview/realview_eb.c +++ b/arch/arm/mach-realview/realview_eb.c @@ -27,6 +27,7 @@ #include #include #include +#include #include #include @@ -414,6 +415,7 @@ static void __init realview_eb_timer_init(void) else timer_irq = IRQ_EB_TIMER0_1; + realview_clk_init(__io_address(REALVIEW_SYS_BASE), false); realview_timer_init(timer_irq); realview_eb_twd_init(); } diff --git a/arch/arm/mach-realview/realview_pb1176.c b/arch/arm/mach-realview/realview_pb1176.c index b1d7cafa1a6d..f0298cbc203e 100644 --- a/arch/arm/mach-realview/realview_pb1176.c +++ b/arch/arm/mach-realview/realview_pb1176.c @@ -29,6 +29,7 @@ #include #include #include +#include #include #include @@ -326,6 +327,7 @@ static void __init realview_pb1176_timer_init(void) timer2_va_base = __io_address(REALVIEW_PB1176_TIMER2_3_BASE); timer3_va_base = __io_address(REALVIEW_PB1176_TIMER2_3_BASE) + 0x20; + realview_clk_init(__io_address(REALVIEW_SYS_BASE), true); realview_timer_init(IRQ_DC1176_TIMER0); } diff --git a/arch/arm/mach-realview/realview_pb11mp.c b/arch/arm/mach-realview/realview_pb11mp.c index a98c536e3327..1f019f76f7b5 100644 --- a/arch/arm/mach-realview/realview_pb11mp.c +++ b/arch/arm/mach-realview/realview_pb11mp.c @@ -27,6 +27,7 @@ #include #include #include +#include #include #include @@ -312,6 +313,7 @@ static void __init realview_pb11mp_timer_init(void) timer2_va_base = __io_address(REALVIEW_PB11MP_TIMER2_3_BASE); timer3_va_base = __io_address(REALVIEW_PB11MP_TIMER2_3_BASE) + 0x20; + realview_clk_init(__io_address(REALVIEW_SYS_BASE), false); realview_timer_init(IRQ_TC11MP_TIMER0_1); realview_pb11mp_twd_init(); } diff --git a/arch/arm/mach-realview/realview_pba8.c b/arch/arm/mach-realview/realview_pba8.c index 59650174e6ed..5032775dbfee 100644 --- a/arch/arm/mach-realview/realview_pba8.c +++ b/arch/arm/mach-realview/realview_pba8.c @@ -27,6 +27,7 @@ #include #include #include +#include #include #include @@ -261,6 +262,7 @@ static void __init realview_pba8_timer_init(void) timer2_va_base = __io_address(REALVIEW_PBA8_TIMER2_3_BASE); timer3_va_base = __io_address(REALVIEW_PBA8_TIMER2_3_BASE) + 0x20; + realview_clk_init(__io_address(REALVIEW_SYS_BASE), false); realview_timer_init(IRQ_PBA8_TIMER0_1); } diff --git a/arch/arm/mach-realview/realview_pbx.c b/arch/arm/mach-realview/realview_pbx.c index 3f2f605624e9..de64ba0ddb95 100644 --- a/arch/arm/mach-realview/realview_pbx.c +++ b/arch/arm/mach-realview/realview_pbx.c @@ -26,6 +26,7 @@ #include #include #include +#include #include #include @@ -320,6 +321,7 @@ static void __init realview_pbx_timer_init(void) timer2_va_base = __io_address(REALVIEW_PBX_TIMER2_3_BASE); timer3_va_base = __io_address(REALVIEW_PBX_TIMER2_3_BASE) + 0x20; + realview_clk_init(__io_address(REALVIEW_SYS_BASE), false); realview_timer_init(IRQ_PBX_TIMER0_1); realview_pbx_twd_init(); } diff --git a/drivers/clk/Kconfig b/drivers/clk/Kconfig index 7f0b5ca78516..89b726d1afe5 100644 --- a/drivers/clk/Kconfig +++ b/drivers/clk/Kconfig @@ -40,4 +40,11 @@ config COMMON_CLK_WM831X Supports the clocking subsystem of the WM831x/2x series of PMICs from Wolfson Microlectronics. +config COMMON_CLK_VERSATILE + tristate "Clock driver for ARM Reference designs" + depends on ARCH_INTEGRATOR || ARCH_REALVIEW + ---help--- + Supports clocking on ARM Reference designs Integrator/AP, + Integrator/CP, RealView PB1176, EB, PB11MP and PBX. + endmenu diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile index d4c7253eb307..e30376c4ff5d 100644 --- a/drivers/clk/Makefile +++ b/drivers/clk/Makefile @@ -9,7 +9,7 @@ obj-$(CONFIG_ARCH_MXS) += mxs/ obj-$(CONFIG_ARCH_SOCFPGA) += socfpga/ obj-$(CONFIG_PLAT_SPEAR) += spear/ obj-$(CONFIG_ARCH_U300) += clk-u300.o -obj-$(CONFIG_ARCH_INTEGRATOR) += versatile/ +obj-$(CONFIG_COMMON_CLK_VERSATILE) += versatile/ obj-$(CONFIG_ARCH_PRIMA2) += clk-prima2.o # Chip specific diff --git a/drivers/clk/versatile/Makefile b/drivers/clk/versatile/Makefile index 50cf6a2ee693..c0a0f6478798 100644 --- a/drivers/clk/versatile/Makefile +++ b/drivers/clk/versatile/Makefile @@ -1,3 +1,4 @@ # Makefile for Versatile-specific clocks obj-$(CONFIG_ICST) += clk-icst.o obj-$(CONFIG_ARCH_INTEGRATOR) += clk-integrator.o +obj-$(CONFIG_ARCH_REALVIEW) += clk-realview.o diff --git a/drivers/clk/versatile/clk-realview.c b/drivers/clk/versatile/clk-realview.c new file mode 100644 index 000000000000..e21a99cef378 --- /dev/null +++ b/drivers/clk/versatile/clk-realview.c @@ -0,0 +1,114 @@ +#include +#include +#include +#include +#include + +#include +#include + +#include "clk-icst.h" + +/* + * Implementation of the ARM RealView clock trees. + */ + +static void __iomem *sys_lock; +static void __iomem *sys_vcoreg; + +/** + * realview_oscvco_get() - get ICST OSC settings for the RealView + */ +static struct icst_vco realview_oscvco_get(void) +{ + u32 val; + struct icst_vco vco; + + val = readl(sys_vcoreg); + vco.v = val & 0x1ff; + vco.r = (val >> 9) & 0x7f; + vco.s = (val >> 16) & 03; + return vco; +} + +static void realview_oscvco_set(struct icst_vco vco) +{ + u32 val; + + val = readl(sys_vcoreg) & ~0x7ffff; + val |= vco.v | (vco.r << 9) | (vco.s << 16); + + /* This magic unlocks the CM VCO so it can be controlled */ + writel(0xa05f, sys_lock); + writel(val, sys_vcoreg); + /* This locks the CM again */ + writel(0, sys_lock); +} + +static const struct icst_params realview_oscvco_params = { + .ref = 24000000, + .vco_max = ICST307_VCO_MAX, + .vco_min = ICST307_VCO_MIN, + .vd_min = 4 + 8, + .vd_max = 511 + 8, + .rd_min = 1 + 2, + .rd_max = 127 + 2, + .s2div = icst307_s2div, + .idx2s = icst307_idx2s, +}; + +static const struct clk_icst_desc __initdata realview_icst_desc = { + .params = &realview_oscvco_params, + .getvco = realview_oscvco_get, + .setvco = realview_oscvco_set, +}; + +/* + * realview_clk_init() - set up the RealView clock tree + */ +void __init realview_clk_init(void __iomem *sysbase, bool is_pb1176) +{ + struct clk *clk; + + sys_lock = sysbase + REALVIEW_SYS_LOCK_OFFSET; + if (is_pb1176) + sys_vcoreg = sysbase + REALVIEW_SYS_OSC0_OFFSET; + else + sys_vcoreg = sysbase + REALVIEW_SYS_OSC4_OFFSET; + + + /* APB clock dummy */ + clk = clk_register_fixed_rate(NULL, "apb_pclk", NULL, CLK_IS_ROOT, 0); + clk_register_clkdev(clk, "apb_pclk", NULL); + + /* 24 MHz clock */ + clk = clk_register_fixed_rate(NULL, "clk24mhz", NULL, CLK_IS_ROOT, + 24000000); + clk_register_clkdev(clk, NULL, "dev:uart0"); + clk_register_clkdev(clk, NULL, "dev:uart1"); + clk_register_clkdev(clk, NULL, "dev:uart2"); + clk_register_clkdev(clk, NULL, "fpga:kmi0"); + clk_register_clkdev(clk, NULL, "fpga:kmi1"); + clk_register_clkdev(clk, NULL, "fpga:mmc0"); + clk_register_clkdev(clk, NULL, "dev:ssp0"); + if (is_pb1176) { + /* + * UART3 is on the dev chip in PB1176 + * UART4 only exists in PB1176 + */ + clk_register_clkdev(clk, NULL, "dev:uart3"); + clk_register_clkdev(clk, NULL, "dev:uart4"); + } else + clk_register_clkdev(clk, NULL, "fpga:uart3"); + + + /* 1 MHz clock */ + clk = clk_register_fixed_rate(NULL, "clk1mhz", NULL, CLK_IS_ROOT, + 1000000); + clk_register_clkdev(clk, NULL, "sp804"); + + /* ICST VCO clock */ + clk = icst_clk_register(NULL, &realview_icst_desc); + clk_register_clkdev(clk, NULL, "dev:clcd"); + clk_register_clkdev(clk, NULL, "issp:clcd"); +} diff --git a/include/linux/platform_data/clk-realview.h b/include/linux/platform_data/clk-realview.h new file mode 100644 index 000000000000..2e426a7dbc51 --- /dev/null +++ b/include/linux/platform_data/clk-realview.h @@ -0,0 +1 @@ +void realview_clk_init(void __iomem *sysbase, bool is_pb1176); -- cgit v1.2.3 From 6b63f023184e34b404b96bb9a8c4ac6692ff3fbd Mon Sep 17 00:00:00 2001 From: Chao Xie Date: Mon, 20 Aug 2012 02:55:11 +0000 Subject: clk: mmp: add mmp specific clocks add mmp specific clocks including apbc cloks, apmu clocks, and pll2, fraction clocks Signed-off-by: Chao Xie Reviewed-by: Arnd Bergmann Acked-by: Haojian Zhuang Signed-off-by: Mike Turquette --- drivers/clk/Makefile | 3 + drivers/clk/mmp/Makefile | 5 ++ drivers/clk/mmp/clk-apbc.c | 152 ++++++++++++++++++++++++++++++++++++++++++++ drivers/clk/mmp/clk-apmu.c | 97 ++++++++++++++++++++++++++++ drivers/clk/mmp/clk-frac.c | 153 +++++++++++++++++++++++++++++++++++++++++++++ drivers/clk/mmp/clk.h | 35 +++++++++++ 6 files changed, 445 insertions(+) create mode 100644 drivers/clk/mmp/Makefile create mode 100644 drivers/clk/mmp/clk-apbc.c create mode 100644 drivers/clk/mmp/clk-apmu.c create mode 100644 drivers/clk/mmp/clk-frac.c create mode 100644 drivers/clk/mmp/clk.h (limited to 'drivers') diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile index e30376c4ff5d..fa5e1d210b84 100644 --- a/drivers/clk/Makefile +++ b/drivers/clk/Makefile @@ -11,6 +11,9 @@ obj-$(CONFIG_PLAT_SPEAR) += spear/ obj-$(CONFIG_ARCH_U300) += clk-u300.o obj-$(CONFIG_COMMON_CLK_VERSATILE) += versatile/ obj-$(CONFIG_ARCH_PRIMA2) += clk-prima2.o +ifeq ($(CONFIG_COMMON_CLK), y) +obj-$(CONFIG_ARCH_MMP) += mmp/ +endif # Chip specific obj-$(CONFIG_COMMON_CLK_WM831X) += clk-wm831x.o diff --git a/drivers/clk/mmp/Makefile b/drivers/clk/mmp/Makefile new file mode 100644 index 000000000000..b5bc88cc8967 --- /dev/null +++ b/drivers/clk/mmp/Makefile @@ -0,0 +1,5 @@ +# +# Makefile for mmp specific clk +# + +obj-y += clk-apbc.o clk-apmu.o clk-frac.o diff --git a/drivers/clk/mmp/clk-apbc.c b/drivers/clk/mmp/clk-apbc.c new file mode 100644 index 000000000000..d14120eaa71f --- /dev/null +++ b/drivers/clk/mmp/clk-apbc.c @@ -0,0 +1,152 @@ +/* + * mmp APB clock operation source file + * + * Copyright (C) 2012 Marvell + * Chao Xie + * + * This file is licensed under the terms of the GNU General Public + * License version 2. This program is licensed "as is" without any + * warranty of any kind, whether express or implied. + */ + +#include +#include +#include +#include +#include +#include + +#include "clk.h" + +/* Common APB clock register bit definitions */ +#define APBC_APBCLK (1 << 0) /* APB Bus Clock Enable */ +#define APBC_FNCLK (1 << 1) /* Functional Clock Enable */ +#define APBC_RST (1 << 2) /* Reset Generation */ +#define APBC_POWER (1 << 7) /* Reset Generation */ + +#define to_clk_apbc(hw) container_of(hw, struct clk_apbc, hw) +struct clk_apbc { + struct clk_hw hw; + void __iomem *base; + unsigned int delay; + unsigned int flags; + spinlock_t *lock; +}; + +static int clk_apbc_prepare(struct clk_hw *hw) +{ + struct clk_apbc *apbc = to_clk_apbc(hw); + unsigned int data; + unsigned long flags = 0; + + /* + * It may share same register as MUX clock, + * and it will impact FNCLK enable. Spinlock is needed + */ + if (apbc->lock) + spin_lock_irqsave(apbc->lock, flags); + + data = readl_relaxed(apbc->base); + if (apbc->flags & APBC_POWER_CTRL) + data |= APBC_POWER; + data |= APBC_FNCLK; + writel_relaxed(data, apbc->base); + + if (apbc->lock) + spin_unlock_irqrestore(apbc->lock, flags); + + udelay(apbc->delay); + + if (apbc->lock) + spin_lock_irqsave(apbc->lock, flags); + + data = readl_relaxed(apbc->base); + data |= APBC_APBCLK; + writel_relaxed(data, apbc->base); + + if (apbc->lock) + spin_unlock_irqrestore(apbc->lock, flags); + + udelay(apbc->delay); + + if (!(apbc->flags & APBC_NO_BUS_CTRL)) { + if (apbc->lock) + spin_lock_irqsave(apbc->lock, flags); + + data = readl_relaxed(apbc->base); + data &= ~APBC_RST; + writel_relaxed(data, apbc->base); + + if (apbc->lock) + spin_unlock_irqrestore(apbc->lock, flags); + } + + return 0; +} + +static void clk_apbc_unprepare(struct clk_hw *hw) +{ + struct clk_apbc *apbc = to_clk_apbc(hw); + unsigned long data; + unsigned long flags = 0; + + if (apbc->lock) + spin_lock_irqsave(apbc->lock, flags); + + data = readl_relaxed(apbc->base); + if (apbc->flags & APBC_POWER_CTRL) + data &= ~APBC_POWER; + data &= ~APBC_FNCLK; + writel_relaxed(data, apbc->base); + + if (apbc->lock) + spin_unlock_irqrestore(apbc->lock, flags); + + udelay(10); + + if (apbc->lock) + spin_lock_irqsave(apbc->lock, flags); + + data = readl_relaxed(apbc->base); + data &= ~APBC_APBCLK; + writel_relaxed(data, apbc->base); + + if (apbc->lock) + spin_unlock_irqrestore(apbc->lock, flags); +} + +struct clk_ops clk_apbc_ops = { + .prepare = clk_apbc_prepare, + .unprepare = clk_apbc_unprepare, +}; + +struct clk *mmp_clk_register_apbc(const char *name, const char *parent_name, + void __iomem *base, unsigned int delay, + unsigned int apbc_flags, spinlock_t *lock) +{ + struct clk_apbc *apbc; + struct clk *clk; + struct clk_init_data init; + + apbc = kzalloc(sizeof(*apbc), GFP_KERNEL); + if (!apbc) + return NULL; + + init.name = name; + init.ops = &clk_apbc_ops; + init.flags = CLK_SET_RATE_PARENT; + init.parent_names = (parent_name ? &parent_name : NULL); + init.num_parents = (parent_name ? 1 : 0); + + apbc->base = base; + apbc->delay = delay; + apbc->flags = apbc_flags; + apbc->lock = lock; + apbc->hw.init = &init; + + clk = clk_register(NULL, &apbc->hw); + if (IS_ERR(clk)) + kfree(apbc); + + return clk; +} diff --git a/drivers/clk/mmp/clk-apmu.c b/drivers/clk/mmp/clk-apmu.c new file mode 100644 index 000000000000..abe182b2377f --- /dev/null +++ b/drivers/clk/mmp/clk-apmu.c @@ -0,0 +1,97 @@ +/* + * mmp AXI peripharal clock operation source file + * + * Copyright (C) 2012 Marvell + * Chao Xie + * + * This file is licensed under the terms of the GNU General Public + * License version 2. This program is licensed "as is" without any + * warranty of any kind, whether express or implied. + */ + +#include +#include +#include +#include +#include +#include + +#include "clk.h" + +#define to_clk_apmu(clk) (container_of(clk, struct clk_apmu, clk)) +struct clk_apmu { + struct clk_hw hw; + void __iomem *base; + u32 rst_mask; + u32 enable_mask; + spinlock_t *lock; +}; + +static int clk_apmu_enable(struct clk_hw *hw) +{ + struct clk_apmu *apmu = to_clk_apmu(hw); + unsigned long data; + unsigned long flags = 0; + + if (apmu->lock) + spin_lock_irqsave(apmu->lock, flags); + + data = readl_relaxed(apmu->base) | apmu->enable_mask; + writel_relaxed(data, apmu->base); + + if (apmu->lock) + spin_unlock_irqrestore(apmu->lock, flags); + + return 0; +} + +static void clk_apmu_disable(struct clk_hw *hw) +{ + struct clk_apmu *apmu = to_clk_apmu(hw); + unsigned long data; + unsigned long flags = 0; + + if (apmu->lock) + spin_lock_irqsave(apmu->lock, flags); + + data = readl_relaxed(apmu->base) & ~apmu->enable_mask; + writel_relaxed(data, apmu->base); + + if (apmu->lock) + spin_unlock_irqrestore(apmu->lock, flags); +} + +struct clk_ops clk_apmu_ops = { + .enable = clk_apmu_enable, + .disable = clk_apmu_disable, +}; + +struct clk *mmp_clk_register_apmu(const char *name, const char *parent_name, + void __iomem *base, u32 enable_mask, spinlock_t *lock) +{ + struct clk_apmu *apmu; + struct clk *clk; + struct clk_init_data init; + + apmu = kzalloc(sizeof(*apmu), GFP_KERNEL); + if (!apmu) + return NULL; + + init.name = name; + init.ops = &clk_apmu_ops; + init.flags = CLK_SET_RATE_PARENT; + init.parent_names = (parent_name ? &parent_name : NULL); + init.num_parents = (parent_name ? 1 : 0); + + apmu->base = base; + apmu->enable_mask = enable_mask; + apmu->lock = lock; + apmu->hw.init = &init; + + clk = clk_register(NULL, &apmu->hw); + + if (IS_ERR(clk)) + kfree(apmu); + + return clk; +} diff --git a/drivers/clk/mmp/clk-frac.c b/drivers/clk/mmp/clk-frac.c new file mode 100644 index 000000000000..80c1dd15d15c --- /dev/null +++ b/drivers/clk/mmp/clk-frac.c @@ -0,0 +1,153 @@ +/* + * mmp factor clock operation source file + * + * Copyright (C) 2012 Marvell + * Chao Xie + * + * This file is licensed under the terms of the GNU General Public + * License version 2. This program is licensed "as is" without any + * warranty of any kind, whether express or implied. + */ + +#include +#include +#include +#include + +#include "clk.h" +/* + * It is M/N clock + * + * Fout from synthesizer can be given from two equations: + * numerator/denominator = Fin / (Fout * factor) + */ + +#define to_clk_factor(hw) container_of(hw, struct clk_factor, hw) +struct clk_factor { + struct clk_hw hw; + void __iomem *base; + struct clk_factor_masks *masks; + struct clk_factor_tbl *ftbl; + unsigned int ftbl_cnt; +}; + +static long clk_factor_round_rate(struct clk_hw *hw, unsigned long drate, + unsigned long *prate) +{ + struct clk_factor *factor = to_clk_factor(hw); + unsigned long rate = 0, prev_rate; + int i; + + for (i = 0; i < factor->ftbl_cnt; i++) { + prev_rate = rate; + rate = (((*prate / 10000) * factor->ftbl[i].num) / + (factor->ftbl[i].den * factor->masks->factor)) * 10000; + if (rate > drate) + break; + } + if (i == 0) + return rate; + else + return prev_rate; +} + +static unsigned long clk_factor_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) +{ + struct clk_factor *factor = to_clk_factor(hw); + struct clk_factor_masks *masks = factor->masks; + unsigned int val, num, den; + + val = readl_relaxed(factor->base); + + /* calculate numerator */ + num = (val >> masks->num_shift) & masks->num_mask; + + /* calculate denominator */ + den = (val >> masks->den_shift) & masks->num_mask; + + if (!den) + return 0; + + return (((parent_rate / 10000) * den) / + (num * factor->masks->factor)) * 10000; +} + +/* Configures new clock rate*/ +static int clk_factor_set_rate(struct clk_hw *hw, unsigned long drate, + unsigned long prate) +{ + struct clk_factor *factor = to_clk_factor(hw); + struct clk_factor_masks *masks = factor->masks; + int i; + unsigned long val; + unsigned long prev_rate, rate = 0; + + for (i = 0; i < factor->ftbl_cnt; i++) { + prev_rate = rate; + rate = (((prate / 10000) * factor->ftbl[i].num) / + (factor->ftbl[i].den * factor->masks->factor)) * 10000; + if (rate > drate) + break; + } + if (i > 0) + i--; + + val = readl_relaxed(factor->base); + + val &= ~(masks->num_mask << masks->num_shift); + val |= (factor->ftbl[i].num & masks->num_mask) << masks->num_shift; + + val &= ~(masks->den_mask << masks->den_shift); + val |= (factor->ftbl[i].den & masks->den_mask) << masks->den_shift; + + writel_relaxed(val, factor->base); + + return 0; +} + +static struct clk_ops clk_factor_ops = { + .recalc_rate = clk_factor_recalc_rate, + .round_rate = clk_factor_round_rate, + .set_rate = clk_factor_set_rate, +}; + +struct clk *mmp_clk_register_factor(const char *name, const char *parent_name, + unsigned long flags, void __iomem *base, + struct clk_factor_masks *masks, struct clk_factor_tbl *ftbl, + unsigned int ftbl_cnt) +{ + struct clk_factor *factor; + struct clk_init_data init; + struct clk *clk; + + if (!masks) { + pr_err("%s: must pass a clk_factor_mask\n", __func__); + return ERR_PTR(-EINVAL); + } + + factor = kzalloc(sizeof(*factor), GFP_KERNEL); + if (!factor) { + pr_err("%s: could not allocate factor clk\n", __func__); + return ERR_PTR(-ENOMEM); + } + + /* struct clk_aux assignments */ + factor->base = base; + factor->masks = masks; + factor->ftbl = ftbl; + factor->ftbl_cnt = ftbl_cnt; + factor->hw.init = &init; + + init.name = name; + init.ops = &clk_factor_ops; + init.flags = flags; + init.parent_names = &parent_name; + init.num_parents = 1; + + clk = clk_register(NULL, &factor->hw); + if (IS_ERR_OR_NULL(clk)) + kfree(factor); + + return clk; +} diff --git a/drivers/clk/mmp/clk.h b/drivers/clk/mmp/clk.h new file mode 100644 index 000000000000..ab86dd4a416a --- /dev/null +++ b/drivers/clk/mmp/clk.h @@ -0,0 +1,35 @@ +#ifndef __MACH_MMP_CLK_H +#define __MACH_MMP_CLK_H + +#include +#include + +#define APBC_NO_BUS_CTRL BIT(0) +#define APBC_POWER_CTRL BIT(1) + +struct clk_factor_masks { + unsigned int factor; + unsigned int num_mask; + unsigned int den_mask; + unsigned int num_shift; + unsigned int den_shift; +}; + +struct clk_factor_tbl { + unsigned int num; + unsigned int den; +}; + +extern struct clk *mmp_clk_register_pll2(const char *name, + const char *parent_name, unsigned long flags); +extern struct clk *mmp_clk_register_apbc(const char *name, + const char *parent_name, void __iomem *base, + unsigned int delay, unsigned int apbc_flags, spinlock_t *lock); +extern struct clk *mmp_clk_register_apmu(const char *name, + const char *parent_name, void __iomem *base, u32 enable_mask, + spinlock_t *lock); +extern struct clk *mmp_clk_register_factor(const char *name, + const char *parent_name, unsigned long flags, + void __iomem *base, struct clk_factor_masks *masks, + struct clk_factor_tbl *ftbl, unsigned int ftbl_cnt); +#endif -- cgit v1.2.3 From e1b53b3d0fba5f052d3306bfac01ee40dc3c0d37 Mon Sep 17 00:00:00 2001 From: Chao Xie Date: Mon, 20 Aug 2012 02:55:12 +0000 Subject: clk: mmp: add clock definition for pxa168 Initialize the clocks for pxa168 Signed-off-by: Chao Xie Reviewed-by: Arnd Bergmann Acked-by: Haojian Zhuang Signed-off-by: Mike Turquette --- drivers/clk/mmp/Makefile | 2 + drivers/clk/mmp/clk-pxa168.c | 346 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 348 insertions(+) create mode 100644 drivers/clk/mmp/clk-pxa168.c (limited to 'drivers') diff --git a/drivers/clk/mmp/Makefile b/drivers/clk/mmp/Makefile index b5bc88cc8967..a0e69ed88445 100644 --- a/drivers/clk/mmp/Makefile +++ b/drivers/clk/mmp/Makefile @@ -3,3 +3,5 @@ # obj-y += clk-apbc.o clk-apmu.o clk-frac.o + +obj-$(CONFIG_CPU_PXA168) += clk-pxa168.o diff --git a/drivers/clk/mmp/clk-pxa168.c b/drivers/clk/mmp/clk-pxa168.c new file mode 100644 index 000000000000..e8d036c12cbf --- /dev/null +++ b/drivers/clk/mmp/clk-pxa168.c @@ -0,0 +1,346 @@ +/* + * pxa168 clock framework source file + * + * Copyright (C) 2012 Marvell + * Chao Xie + * + * This file is licensed under the terms of the GNU General Public + * License version 2. This program is licensed "as is" without any + * warranty of any kind, whether express or implied. + */ + +#include +#include +#include +#include +#include +#include + +#include + +#include "clk.h" + +#define APBC_RTC 0x28 +#define APBC_TWSI0 0x2c +#define APBC_KPC 0x30 +#define APBC_UART0 0x0 +#define APBC_UART1 0x4 +#define APBC_GPIO 0x8 +#define APBC_PWM0 0xc +#define APBC_PWM1 0x10 +#define APBC_PWM2 0x14 +#define APBC_PWM3 0x18 +#define APBC_SSP0 0x81c +#define APBC_SSP1 0x820 +#define APBC_SSP2 0x84c +#define APBC_SSP3 0x858 +#define APBC_SSP4 0x85c +#define APBC_TWSI1 0x6c +#define APBC_UART2 0x70 +#define APMU_SDH0 0x54 +#define APMU_SDH1 0x58 +#define APMU_USB 0x5c +#define APMU_DISP0 0x4c +#define APMU_CCIC0 0x50 +#define APMU_DFC 0x60 +#define MPMU_UART_PLL 0x14 + +static DEFINE_SPINLOCK(clk_lock); + +static struct clk_factor_masks uart_factor_masks = { + .factor = 2, + .num_mask = 0x1fff, + .den_mask = 0x1fff, + .num_shift = 16, + .den_shift = 0, +}; + +static struct clk_factor_tbl uart_factor_tbl[] = { + {.num = 8125, .den = 1536}, /*14.745MHZ */ +}; + +static const char *uart_parent[] = {"pll1_3_16", "uart_pll"}; +static const char *ssp_parent[] = {"pll1_96", "pll1_48", "pll1_24", "pll1_12"}; +static const char *sdh_parent[] = {"pll1_12", "pll1_13"}; +static const char *disp_parent[] = {"pll1_2", "pll1_12"}; +static const char *ccic_parent[] = {"pll1_2", "pll1_12"}; +static const char *ccic_phy_parent[] = {"pll1_6", "pll1_12"}; + +void __init pxa168_clk_init(void) +{ + struct clk *clk; + struct clk *uart_pll; + void __iomem *mpmu_base; + void __iomem *apmu_base; + void __iomem *apbc_base; + + mpmu_base = ioremap(APB_PHYS_BASE + 0x50000, SZ_4K); + if (mpmu_base == NULL) { + pr_err("error to ioremap MPMU base\n"); + return; + } + + apmu_base = ioremap(AXI_PHYS_BASE + 0x82800, SZ_4K); + if (apmu_base == NULL) { + pr_err("error to ioremap APMU base\n"); + return; + } + + apbc_base = ioremap(APB_PHYS_BASE + 0x15000, SZ_4K); + if (apbc_base == NULL) { + pr_err("error to ioremap APBC base\n"); + return; + } + + clk = clk_register_fixed_rate(NULL, "clk32", NULL, CLK_IS_ROOT, 3200); + clk_register_clkdev(clk, "clk32", NULL); + + clk = clk_register_fixed_rate(NULL, "vctcxo", NULL, CLK_IS_ROOT, + 26000000); + clk_register_clkdev(clk, "vctcxo", NULL); + + clk = clk_register_fixed_rate(NULL, "pll1", NULL, CLK_IS_ROOT, + 624000000); + clk_register_clkdev(clk, "pll1", NULL); + + clk = clk_register_fixed_factor(NULL, "pll1_2", "pll1", + CLK_SET_RATE_PARENT, 1, 2); + clk_register_clkdev(clk, "pll1_2", NULL); + + clk = clk_register_fixed_factor(NULL, "pll1_4", "pll1_2", + CLK_SET_RATE_PARENT, 1, 2); + clk_register_clkdev(clk, "pll1_4", NULL); + + clk = clk_register_fixed_factor(NULL, "pll1_8", "pll1_4", + CLK_SET_RATE_PARENT, 1, 2); + clk_register_clkdev(clk, "pll1_8", NULL); + + clk = clk_register_fixed_factor(NULL, "pll1_16", "pll1_8", + CLK_SET_RATE_PARENT, 1, 2); + clk_register_clkdev(clk, "pll1_16", NULL); + + clk = clk_register_fixed_factor(NULL, "pll1_6", "pll1_2", + CLK_SET_RATE_PARENT, 1, 3); + clk_register_clkdev(clk, "pll1_6", NULL); + + clk = clk_register_fixed_factor(NULL, "pll1_12", "pll1_6", + CLK_SET_RATE_PARENT, 1, 2); + clk_register_clkdev(clk, "pll1_12", NULL); + + clk = clk_register_fixed_factor(NULL, "pll1_24", "pll1_12", + CLK_SET_RATE_PARENT, 1, 2); + clk_register_clkdev(clk, "pll1_24", NULL); + + clk = clk_register_fixed_factor(NULL, "pll1_48", "pll1_24", + CLK_SET_RATE_PARENT, 1, 2); + clk_register_clkdev(clk, "pll1_48", NULL); + + clk = clk_register_fixed_factor(NULL, "pll1_96", "pll1_48", + CLK_SET_RATE_PARENT, 1, 2); + clk_register_clkdev(clk, "pll1_96", NULL); + + clk = clk_register_fixed_factor(NULL, "pll1_13", "pll1", + CLK_SET_RATE_PARENT, 1, 13); + clk_register_clkdev(clk, "pll1_13", NULL); + + clk = clk_register_fixed_factor(NULL, "pll1_13_1_5", "pll1", + CLK_SET_RATE_PARENT, 2, 3); + clk_register_clkdev(clk, "pll1_13_1_5", NULL); + + clk = clk_register_fixed_factor(NULL, "pll1_2_1_5", "pll1", + CLK_SET_RATE_PARENT, 2, 3); + clk_register_clkdev(clk, "pll1_2_1_5", NULL); + + clk = clk_register_fixed_factor(NULL, "pll1_3_16", "pll1", + CLK_SET_RATE_PARENT, 3, 16); + clk_register_clkdev(clk, "pll1_3_16", NULL); + + uart_pll = mmp_clk_register_factor("uart_pll", "pll1_4", 0, + mpmu_base + MPMU_UART_PLL, + &uart_factor_masks, uart_factor_tbl, + ARRAY_SIZE(uart_factor_tbl)); + clk_set_rate(uart_pll, 14745600); + clk_register_clkdev(uart_pll, "uart_pll", NULL); + + clk = mmp_clk_register_apbc("twsi0", "pll1_13_1_5", + apbc_base + APBC_TWSI0, 10, 0, &clk_lock); + clk_register_clkdev(clk, NULL, "pxa2xx-i2c.0"); + + clk = mmp_clk_register_apbc("twsi1", "pll1_13_1_5", + apbc_base + APBC_TWSI1, 10, 0, &clk_lock); + clk_register_clkdev(clk, NULL, "pxa2xx-i2c.1"); + + clk = mmp_clk_register_apbc("gpio", "vctcxo", + apbc_base + APBC_GPIO, 10, 0, &clk_lock); + clk_register_clkdev(clk, NULL, "pxa-gpio"); + + clk = mmp_clk_register_apbc("kpc", "clk32", + apbc_base + APBC_KPC, 10, 0, &clk_lock); + clk_register_clkdev(clk, NULL, "pxa27x-keypad"); + + clk = mmp_clk_register_apbc("rtc", "clk32", + apbc_base + APBC_RTC, 10, 0, &clk_lock); + clk_register_clkdev(clk, NULL, "sa1100-rtc"); + + clk = mmp_clk_register_apbc("pwm0", "pll1_48", + apbc_base + APBC_PWM0, 10, 0, &clk_lock); + clk_register_clkdev(clk, NULL, "pxa168-pwm.0"); + + clk = mmp_clk_register_apbc("pwm1", "pll1_48", + apbc_base + APBC_PWM1, 10, 0, &clk_lock); + clk_register_clkdev(clk, NULL, "pxa168-pwm.1"); + + clk = mmp_clk_register_apbc("pwm2", "pll1_48", + apbc_base + APBC_PWM2, 10, 0, &clk_lock); + clk_register_clkdev(clk, NULL, "pxa168-pwm.2"); + + clk = mmp_clk_register_apbc("pwm3", "pll1_48", + apbc_base + APBC_PWM3, 10, 0, &clk_lock); + clk_register_clkdev(clk, NULL, "pxa168-pwm.3"); + + clk = clk_register_mux(NULL, "uart0_mux", uart_parent, + ARRAY_SIZE(uart_parent), CLK_SET_RATE_PARENT, + apbc_base + APBC_UART0, 4, 3, 0, &clk_lock); + clk_set_parent(clk, uart_pll); + clk_register_clkdev(clk, "uart_mux.0", NULL); + + clk = mmp_clk_register_apbc("uart0", "uart0_mux", + apbc_base + APBC_UART0, 10, 0, &clk_lock); + clk_register_clkdev(clk, NULL, "pxa2xx-uart.0"); + + clk = clk_register_mux(NULL, "uart1_mux", uart_parent, + ARRAY_SIZE(uart_parent), CLK_SET_RATE_PARENT, + apbc_base + APBC_UART1, 4, 3, 0, &clk_lock); + clk_set_parent(clk, uart_pll); + clk_register_clkdev(clk, "uart_mux.1", NULL); + + clk = mmp_clk_register_apbc("uart1", "uart1_mux", + apbc_base + APBC_UART1, 10, 0, &clk_lock); + clk_register_clkdev(clk, NULL, "pxa2xx-uart.1"); + + clk = clk_register_mux(NULL, "uart2_mux", uart_parent, + ARRAY_SIZE(uart_parent), CLK_SET_RATE_PARENT, + apbc_base + APBC_UART2, 4, 3, 0, &clk_lock); + clk_set_parent(clk, uart_pll); + clk_register_clkdev(clk, "uart_mux.2", NULL); + + clk = mmp_clk_register_apbc("uart2", "uart2_mux", + apbc_base + APBC_UART2, 10, 0, &clk_lock); + clk_register_clkdev(clk, NULL, "pxa2xx-uart.2"); + + clk = clk_register_mux(NULL, "ssp0_mux", ssp_parent, + ARRAY_SIZE(ssp_parent), CLK_SET_RATE_PARENT, + apbc_base + APBC_SSP0, 4, 3, 0, &clk_lock); + clk_register_clkdev(clk, "uart_mux.0", NULL); + + clk = mmp_clk_register_apbc("ssp0", "ssp0_mux", apbc_base + APBC_SSP0, + 10, 0, &clk_lock); + clk_register_clkdev(clk, NULL, "mmp-ssp.0"); + + clk = clk_register_mux(NULL, "ssp1_mux", ssp_parent, + ARRAY_SIZE(ssp_parent), CLK_SET_RATE_PARENT, + apbc_base + APBC_SSP1, 4, 3, 0, &clk_lock); + clk_register_clkdev(clk, "ssp_mux.1", NULL); + + clk = mmp_clk_register_apbc("ssp1", "ssp1_mux", apbc_base + APBC_SSP1, + 10, 0, &clk_lock); + clk_register_clkdev(clk, NULL, "mmp-ssp.1"); + + clk = clk_register_mux(NULL, "ssp2_mux", ssp_parent, + ARRAY_SIZE(ssp_parent), CLK_SET_RATE_PARENT, + apbc_base + APBC_SSP2, 4, 3, 0, &clk_lock); + clk_register_clkdev(clk, "ssp_mux.2", NULL); + + clk = mmp_clk_register_apbc("ssp2", "ssp1_mux", apbc_base + APBC_SSP2, + 10, 0, &clk_lock); + clk_register_clkdev(clk, NULL, "mmp-ssp.2"); + + clk = clk_register_mux(NULL, "ssp3_mux", ssp_parent, + ARRAY_SIZE(ssp_parent), CLK_SET_RATE_PARENT, + apbc_base + APBC_SSP3, 4, 3, 0, &clk_lock); + clk_register_clkdev(clk, "ssp_mux.3", NULL); + + clk = mmp_clk_register_apbc("ssp3", "ssp1_mux", apbc_base + APBC_SSP3, + 10, 0, &clk_lock); + clk_register_clkdev(clk, NULL, "mmp-ssp.3"); + + clk = clk_register_mux(NULL, "ssp4_mux", ssp_parent, + ARRAY_SIZE(ssp_parent), CLK_SET_RATE_PARENT, + apbc_base + APBC_SSP4, 4, 3, 0, &clk_lock); + clk_register_clkdev(clk, "ssp_mux.4", NULL); + + clk = mmp_clk_register_apbc("ssp4", "ssp1_mux", apbc_base + APBC_SSP4, + 10, 0, &clk_lock); + clk_register_clkdev(clk, NULL, "mmp-ssp.4"); + + clk = mmp_clk_register_apmu("dfc", "pll1_4", apmu_base + APMU_DFC, + 0x19b, &clk_lock); + clk_register_clkdev(clk, NULL, "pxa3xx-nand.0"); + + clk = clk_register_mux(NULL, "sdh0_mux", sdh_parent, + ARRAY_SIZE(sdh_parent), CLK_SET_RATE_PARENT, + apmu_base + APMU_SDH0, 6, 1, 0, &clk_lock); + clk_register_clkdev(clk, "sdh0_mux", NULL); + + clk = mmp_clk_register_apmu("sdh0", "sdh_mux", apmu_base + APMU_SDH0, + 0x1b, &clk_lock); + clk_register_clkdev(clk, NULL, "sdhci-pxa.0"); + + clk = clk_register_mux(NULL, "sdh1_mux", sdh_parent, + ARRAY_SIZE(sdh_parent), CLK_SET_RATE_PARENT, + apmu_base + APMU_SDH1, 6, 1, 0, &clk_lock); + clk_register_clkdev(clk, "sdh1_mux", NULL); + + clk = mmp_clk_register_apmu("sdh1", "sdh1_mux", apmu_base + APMU_SDH1, + 0x1b, &clk_lock); + clk_register_clkdev(clk, NULL, "sdhci-pxa.1"); + + clk = mmp_clk_register_apmu("usb", "usb_pll", apmu_base + APMU_USB, + 0x9, &clk_lock); + clk_register_clkdev(clk, "usb_clk", NULL); + + clk = mmp_clk_register_apmu("sph", "usb_pll", apmu_base + APMU_USB, + 0x12, &clk_lock); + clk_register_clkdev(clk, "sph_clk", NULL); + + clk = clk_register_mux(NULL, "disp0_mux", disp_parent, + ARRAY_SIZE(disp_parent), CLK_SET_RATE_PARENT, + apmu_base + APMU_DISP0, 6, 1, 0, &clk_lock); + clk_register_clkdev(clk, "disp_mux.0", NULL); + + clk = mmp_clk_register_apmu("disp0", "disp0_mux", + apmu_base + APMU_DISP0, 0x1b, &clk_lock); + clk_register_clkdev(clk, "fnclk", "mmp-disp.0"); + + clk = mmp_clk_register_apmu("disp0_hclk", "disp0_mux", + apmu_base + APMU_DISP0, 0x24, &clk_lock); + clk_register_clkdev(clk, "hclk", "mmp-disp.0"); + + clk = clk_register_mux(NULL, "ccic0_mux", ccic_parent, + ARRAY_SIZE(ccic_parent), CLK_SET_RATE_PARENT, + apmu_base + APMU_CCIC0, 6, 1, 0, &clk_lock); + clk_register_clkdev(clk, "ccic_mux.0", NULL); + + clk = mmp_clk_register_apmu("ccic0", "ccic0_mux", + apmu_base + APMU_CCIC0, 0x1b, &clk_lock); + clk_register_clkdev(clk, "fnclk", "mmp-ccic.0"); + + clk = clk_register_mux(NULL, "ccic0_phy_mux", ccic_phy_parent, + ARRAY_SIZE(ccic_phy_parent), + CLK_SET_RATE_PARENT, apmu_base + APMU_CCIC0, + 7, 1, 0, &clk_lock); + clk_register_clkdev(clk, "ccic_phy_mux.0", NULL); + + clk = mmp_clk_register_apmu("ccic0_phy", "ccic0_phy_mux", + apmu_base + APMU_CCIC0, 0x24, &clk_lock); + clk_register_clkdev(clk, "phyclk", "mmp-ccic.0"); + + clk = clk_register_divider(NULL, "ccic0_sphy_div", "ccic0_mux", + CLK_SET_RATE_PARENT, apmu_base + APMU_CCIC0, + 10, 5, 0, &clk_lock); + clk_register_clkdev(clk, "sphyclk_div", NULL); + + clk = mmp_clk_register_apmu("ccic0_sphy", "ccic0_sphy_div", + apmu_base + APMU_CCIC0, 0x300, &clk_lock); + clk_register_clkdev(clk, "sphyclk", "mmp-ccic.0"); +} -- cgit v1.2.3 From 84a62e6ed7efe769e359aebbeab58b20ea1beba9 Mon Sep 17 00:00:00 2001 From: Chao Xie Date: Mon, 20 Aug 2012 02:55:13 +0000 Subject: clk: mmp: add clock definition for pxa910 Initialize the clocks for pxa910 Signed-off-by: Chao Xie Reviewed-by: Arnd Bergmann Acked-by: Haojian Zhuang Signed-off-by: Mike Turquette --- drivers/clk/mmp/Makefile | 1 + drivers/clk/mmp/clk-pxa910.c | 320 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 321 insertions(+) create mode 100644 drivers/clk/mmp/clk-pxa910.c (limited to 'drivers') diff --git a/drivers/clk/mmp/Makefile b/drivers/clk/mmp/Makefile index a0e69ed88445..6160ac22e560 100644 --- a/drivers/clk/mmp/Makefile +++ b/drivers/clk/mmp/Makefile @@ -5,3 +5,4 @@ obj-y += clk-apbc.o clk-apmu.o clk-frac.o obj-$(CONFIG_CPU_PXA168) += clk-pxa168.o +obj-$(CONFIG_CPU_PXA910) += clk-pxa910.o diff --git a/drivers/clk/mmp/clk-pxa910.c b/drivers/clk/mmp/clk-pxa910.c new file mode 100644 index 000000000000..7048c31d6e7e --- /dev/null +++ b/drivers/clk/mmp/clk-pxa910.c @@ -0,0 +1,320 @@ +/* + * pxa910 clock framework source file + * + * Copyright (C) 2012 Marvell + * Chao Xie + * + * This file is licensed under the terms of the GNU General Public + * License version 2. This program is licensed "as is" without any + * warranty of any kind, whether express or implied. + */ + +#include +#include +#include +#include +#include +#include + +#include + +#include "clk.h" + +#define APBC_RTC 0x28 +#define APBC_TWSI0 0x2c +#define APBC_KPC 0x18 +#define APBC_UART0 0x0 +#define APBC_UART1 0x4 +#define APBC_GPIO 0x8 +#define APBC_PWM0 0xc +#define APBC_PWM1 0x10 +#define APBC_PWM2 0x14 +#define APBC_PWM3 0x18 +#define APBC_SSP0 0x1c +#define APBC_SSP1 0x20 +#define APBC_SSP2 0x4c +#define APBCP_TWSI1 0x28 +#define APBCP_UART2 0x1c +#define APMU_SDH0 0x54 +#define APMU_SDH1 0x58 +#define APMU_USB 0x5c +#define APMU_DISP0 0x4c +#define APMU_CCIC0 0x50 +#define APMU_DFC 0x60 +#define MPMU_UART_PLL 0x14 + +static DEFINE_SPINLOCK(clk_lock); + +static struct clk_factor_masks uart_factor_masks = { + .factor = 2, + .num_mask = 0x1fff, + .den_mask = 0x1fff, + .num_shift = 16, + .den_shift = 0, +}; + +static struct clk_factor_tbl uart_factor_tbl[] = { + {.num = 8125, .den = 1536}, /*14.745MHZ */ +}; + +static const char *uart_parent[] = {"pll1_3_16", "uart_pll"}; +static const char *ssp_parent[] = {"pll1_96", "pll1_48", "pll1_24", "pll1_12"}; +static const char *sdh_parent[] = {"pll1_12", "pll1_13"}; +static const char *disp_parent[] = {"pll1_2", "pll1_12"}; +static const char *ccic_parent[] = {"pll1_2", "pll1_12"}; +static const char *ccic_phy_parent[] = {"pll1_6", "pll1_12"}; + +void __init pxa910_clk_init(void) +{ + struct clk *clk; + struct clk *uart_pll; + void __iomem *mpmu_base; + void __iomem *apmu_base; + void __iomem *apbcp_base; + void __iomem *apbc_base; + + mpmu_base = ioremap(APB_PHYS_BASE + 0x50000, SZ_4K); + if (mpmu_base == NULL) { + pr_err("error to ioremap MPMU base\n"); + return; + } + + apmu_base = ioremap(AXI_PHYS_BASE + 0x82800, SZ_4K); + if (apmu_base == NULL) { + pr_err("error to ioremap APMU base\n"); + return; + } + + apbcp_base = ioremap(APB_PHYS_BASE + 0x3b000, SZ_4K); + if (apbcp_base == NULL) { + pr_err("error to ioremap APBC extension base\n"); + return; + } + + apbc_base = ioremap(APB_PHYS_BASE + 0x15000, SZ_4K); + if (apbc_base == NULL) { + pr_err("error to ioremap APBC base\n"); + return; + } + + clk = clk_register_fixed_rate(NULL, "clk32", NULL, CLK_IS_ROOT, 3200); + clk_register_clkdev(clk, "clk32", NULL); + + clk = clk_register_fixed_rate(NULL, "vctcxo", NULL, CLK_IS_ROOT, + 26000000); + clk_register_clkdev(clk, "vctcxo", NULL); + + clk = clk_register_fixed_rate(NULL, "pll1", NULL, CLK_IS_ROOT, + 624000000); + clk_register_clkdev(clk, "pll1", NULL); + + clk = clk_register_fixed_factor(NULL, "pll1_2", "pll1", + CLK_SET_RATE_PARENT, 1, 2); + clk_register_clkdev(clk, "pll1_2", NULL); + + clk = clk_register_fixed_factor(NULL, "pll1_4", "pll1_2", + CLK_SET_RATE_PARENT, 1, 2); + clk_register_clkdev(clk, "pll1_4", NULL); + + clk = clk_register_fixed_factor(NULL, "pll1_8", "pll1_4", + CLK_SET_RATE_PARENT, 1, 2); + clk_register_clkdev(clk, "pll1_8", NULL); + + clk = clk_register_fixed_factor(NULL, "pll1_16", "pll1_8", + CLK_SET_RATE_PARENT, 1, 2); + clk_register_clkdev(clk, "pll1_16", NULL); + + clk = clk_register_fixed_factor(NULL, "pll1_6", "pll1_2", + CLK_SET_RATE_PARENT, 1, 3); + clk_register_clkdev(clk, "pll1_6", NULL); + + clk = clk_register_fixed_factor(NULL, "pll1_12", "pll1_6", + CLK_SET_RATE_PARENT, 1, 2); + clk_register_clkdev(clk, "pll1_12", NULL); + + clk = clk_register_fixed_factor(NULL, "pll1_24", "pll1_12", + CLK_SET_RATE_PARENT, 1, 2); + clk_register_clkdev(clk, "pll1_24", NULL); + + clk = clk_register_fixed_factor(NULL, "pll1_48", "pll1_24", + CLK_SET_RATE_PARENT, 1, 2); + clk_register_clkdev(clk, "pll1_48", NULL); + + clk = clk_register_fixed_factor(NULL, "pll1_96", "pll1_48", + CLK_SET_RATE_PARENT, 1, 2); + clk_register_clkdev(clk, "pll1_96", NULL); + + clk = clk_register_fixed_factor(NULL, "pll1_13", "pll1", + CLK_SET_RATE_PARENT, 1, 13); + clk_register_clkdev(clk, "pll1_13", NULL); + + clk = clk_register_fixed_factor(NULL, "pll1_13_1_5", "pll1", + CLK_SET_RATE_PARENT, 2, 3); + clk_register_clkdev(clk, "pll1_13_1_5", NULL); + + clk = clk_register_fixed_factor(NULL, "pll1_2_1_5", "pll1", + CLK_SET_RATE_PARENT, 2, 3); + clk_register_clkdev(clk, "pll1_2_1_5", NULL); + + clk = clk_register_fixed_factor(NULL, "pll1_3_16", "pll1", + CLK_SET_RATE_PARENT, 3, 16); + clk_register_clkdev(clk, "pll1_3_16", NULL); + + uart_pll = mmp_clk_register_factor("uart_pll", "pll1_4", 0, + mpmu_base + MPMU_UART_PLL, + &uart_factor_masks, uart_factor_tbl, + ARRAY_SIZE(uart_factor_tbl)); + clk_set_rate(uart_pll, 14745600); + clk_register_clkdev(uart_pll, "uart_pll", NULL); + + clk = mmp_clk_register_apbc("twsi0", "pll1_13_1_5", + apbc_base + APBC_TWSI0, 10, 0, &clk_lock); + clk_register_clkdev(clk, NULL, "pxa2xx-i2c.0"); + + clk = mmp_clk_register_apbc("twsi1", "pll1_13_1_5", + apbcp_base + APBCP_TWSI1, 10, 0, &clk_lock); + clk_register_clkdev(clk, NULL, "pxa2xx-i2c.1"); + + clk = mmp_clk_register_apbc("gpio", "vctcxo", + apbc_base + APBC_GPIO, 10, 0, &clk_lock); + clk_register_clkdev(clk, NULL, "pxa-gpio"); + + clk = mmp_clk_register_apbc("kpc", "clk32", + apbc_base + APBC_KPC, 10, 0, &clk_lock); + clk_register_clkdev(clk, NULL, "pxa27x-keypad"); + + clk = mmp_clk_register_apbc("rtc", "clk32", + apbc_base + APBC_RTC, 10, 0, &clk_lock); + clk_register_clkdev(clk, NULL, "sa1100-rtc"); + + clk = mmp_clk_register_apbc("pwm0", "pll1_48", + apbc_base + APBC_PWM0, 10, 0, &clk_lock); + clk_register_clkdev(clk, NULL, "pxa910-pwm.0"); + + clk = mmp_clk_register_apbc("pwm1", "pll1_48", + apbc_base + APBC_PWM1, 10, 0, &clk_lock); + clk_register_clkdev(clk, NULL, "pxa910-pwm.1"); + + clk = mmp_clk_register_apbc("pwm2", "pll1_48", + apbc_base + APBC_PWM2, 10, 0, &clk_lock); + clk_register_clkdev(clk, NULL, "pxa910-pwm.2"); + + clk = mmp_clk_register_apbc("pwm3", "pll1_48", + apbc_base + APBC_PWM3, 10, 0, &clk_lock); + clk_register_clkdev(clk, NULL, "pxa910-pwm.3"); + + clk = clk_register_mux(NULL, "uart0_mux", uart_parent, + ARRAY_SIZE(uart_parent), CLK_SET_RATE_PARENT, + apbc_base + APBC_UART0, 4, 3, 0, &clk_lock); + clk_set_parent(clk, uart_pll); + clk_register_clkdev(clk, "uart_mux.0", NULL); + + clk = mmp_clk_register_apbc("uart0", "uart0_mux", + apbc_base + APBC_UART0, 10, 0, &clk_lock); + clk_register_clkdev(clk, NULL, "pxa2xx-uart.0"); + + clk = clk_register_mux(NULL, "uart1_mux", uart_parent, + ARRAY_SIZE(uart_parent), CLK_SET_RATE_PARENT, + apbc_base + APBC_UART1, 4, 3, 0, &clk_lock); + clk_set_parent(clk, uart_pll); + clk_register_clkdev(clk, "uart_mux.1", NULL); + + clk = mmp_clk_register_apbc("uart1", "uart1_mux", + apbc_base + APBC_UART1, 10, 0, &clk_lock); + clk_register_clkdev(clk, NULL, "pxa2xx-uart.1"); + + clk = clk_register_mux(NULL, "uart2_mux", uart_parent, + ARRAY_SIZE(uart_parent), CLK_SET_RATE_PARENT, + apbcp_base + APBCP_UART2, 4, 3, 0, &clk_lock); + clk_set_parent(clk, uart_pll); + clk_register_clkdev(clk, "uart_mux.2", NULL); + + clk = mmp_clk_register_apbc("uart2", "uart2_mux", + apbcp_base + APBCP_UART2, 10, 0, &clk_lock); + clk_register_clkdev(clk, NULL, "pxa2xx-uart.2"); + + clk = clk_register_mux(NULL, "ssp0_mux", ssp_parent, + ARRAY_SIZE(ssp_parent), CLK_SET_RATE_PARENT, + apbc_base + APBC_SSP0, 4, 3, 0, &clk_lock); + clk_register_clkdev(clk, "uart_mux.0", NULL); + + clk = mmp_clk_register_apbc("ssp0", "ssp0_mux", + apbc_base + APBC_SSP0, 10, 0, &clk_lock); + clk_register_clkdev(clk, NULL, "mmp-ssp.0"); + + clk = clk_register_mux(NULL, "ssp1_mux", ssp_parent, + ARRAY_SIZE(ssp_parent), CLK_SET_RATE_PARENT, + apbc_base + APBC_SSP1, 4, 3, 0, &clk_lock); + clk_register_clkdev(clk, "ssp_mux.1", NULL); + + clk = mmp_clk_register_apbc("ssp1", "ssp1_mux", + apbc_base + APBC_SSP1, 10, 0, &clk_lock); + clk_register_clkdev(clk, NULL, "mmp-ssp.1"); + + clk = mmp_clk_register_apmu("dfc", "pll1_4", + apmu_base + APMU_DFC, 0x19b, &clk_lock); + clk_register_clkdev(clk, NULL, "pxa3xx-nand.0"); + + clk = clk_register_mux(NULL, "sdh0_mux", sdh_parent, + ARRAY_SIZE(sdh_parent), CLK_SET_RATE_PARENT, + apmu_base + APMU_SDH0, 6, 1, 0, &clk_lock); + clk_register_clkdev(clk, "sdh0_mux", NULL); + + clk = mmp_clk_register_apmu("sdh0", "sdh_mux", + apmu_base + APMU_SDH0, 0x1b, &clk_lock); + clk_register_clkdev(clk, NULL, "sdhci-pxa.0"); + + clk = clk_register_mux(NULL, "sdh1_mux", sdh_parent, + ARRAY_SIZE(sdh_parent), CLK_SET_RATE_PARENT, + apmu_base + APMU_SDH1, 6, 1, 0, &clk_lock); + clk_register_clkdev(clk, "sdh1_mux", NULL); + + clk = mmp_clk_register_apmu("sdh1", "sdh1_mux", + apmu_base + APMU_SDH1, 0x1b, &clk_lock); + clk_register_clkdev(clk, NULL, "sdhci-pxa.1"); + + clk = mmp_clk_register_apmu("usb", "usb_pll", + apmu_base + APMU_USB, 0x9, &clk_lock); + clk_register_clkdev(clk, "usb_clk", NULL); + + clk = mmp_clk_register_apmu("sph", "usb_pll", + apmu_base + APMU_USB, 0x12, &clk_lock); + clk_register_clkdev(clk, "sph_clk", NULL); + + clk = clk_register_mux(NULL, "disp0_mux", disp_parent, + ARRAY_SIZE(disp_parent), CLK_SET_RATE_PARENT, + apmu_base + APMU_DISP0, 6, 1, 0, &clk_lock); + clk_register_clkdev(clk, "disp_mux.0", NULL); + + clk = mmp_clk_register_apmu("disp0", "disp0_mux", + apmu_base + APMU_DISP0, 0x1b, &clk_lock); + clk_register_clkdev(clk, NULL, "mmp-disp.0"); + + clk = clk_register_mux(NULL, "ccic0_mux", ccic_parent, + ARRAY_SIZE(ccic_parent), CLK_SET_RATE_PARENT, + apmu_base + APMU_CCIC0, 6, 1, 0, &clk_lock); + clk_register_clkdev(clk, "ccic_mux.0", NULL); + + clk = mmp_clk_register_apmu("ccic0", "ccic0_mux", + apmu_base + APMU_CCIC0, 0x1b, &clk_lock); + clk_register_clkdev(clk, "fnclk", "mmp-ccic.0"); + + clk = clk_register_mux(NULL, "ccic0_phy_mux", ccic_phy_parent, + ARRAY_SIZE(ccic_phy_parent), + CLK_SET_RATE_PARENT, apmu_base + APMU_CCIC0, + 7, 1, 0, &clk_lock); + clk_register_clkdev(clk, "ccic_phy_mux.0", NULL); + + clk = mmp_clk_register_apmu("ccic0_phy", "ccic0_phy_mux", + apmu_base + APMU_CCIC0, 0x24, &clk_lock); + clk_register_clkdev(clk, "phyclk", "mmp-ccic.0"); + + clk = clk_register_divider(NULL, "ccic0_sphy_div", "ccic0_mux", + CLK_SET_RATE_PARENT, apmu_base + APMU_CCIC0, + 10, 5, 0, &clk_lock); + clk_register_clkdev(clk, "sphyclk_div", NULL); + + clk = mmp_clk_register_apmu("ccic0_sphy", "ccic0_sphy_div", + apmu_base + APMU_CCIC0, 0x300, &clk_lock); + clk_register_clkdev(clk, "sphyclk", "mmp-ccic.0"); +} -- cgit v1.2.3 From 4c5bca3419527f5efde68771e791dd7bee5f19b9 Mon Sep 17 00:00:00 2001 From: Chao Xie Date: Mon, 20 Aug 2012 02:55:14 +0000 Subject: clk: mmp: add clock definition for mmp2 Initialize the clocks for mmp2 Signed-off-by: Chao Xie Reviewed-by: Arnd Bergmann Acked-by: Haojian Zhuang Signed-off-by: Mike Turquette --- drivers/clk/mmp/Makefile | 1 + drivers/clk/mmp/clk-mmp2.c | 449 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 450 insertions(+) create mode 100644 drivers/clk/mmp/clk-mmp2.c (limited to 'drivers') diff --git a/drivers/clk/mmp/Makefile b/drivers/clk/mmp/Makefile index 6160ac22e560..392d78044ce3 100644 --- a/drivers/clk/mmp/Makefile +++ b/drivers/clk/mmp/Makefile @@ -6,3 +6,4 @@ obj-y += clk-apbc.o clk-apmu.o clk-frac.o obj-$(CONFIG_CPU_PXA168) += clk-pxa168.o obj-$(CONFIG_CPU_PXA910) += clk-pxa910.o +obj-$(CONFIG_CPU_MMP2) += clk-mmp2.o diff --git a/drivers/clk/mmp/clk-mmp2.c b/drivers/clk/mmp/clk-mmp2.c new file mode 100644 index 000000000000..ade435820c7e --- /dev/null +++ b/drivers/clk/mmp/clk-mmp2.c @@ -0,0 +1,449 @@ +/* + * mmp2 clock framework source file + * + * Copyright (C) 2012 Marvell + * Chao Xie + * + * This file is licensed under the terms of the GNU General Public + * License version 2. This program is licensed "as is" without any + * warranty of any kind, whether express or implied. + */ + +#include +#include +#include +#include +#include +#include + +#include + +#include "clk.h" + +#define APBC_RTC 0x0 +#define APBC_TWSI0 0x4 +#define APBC_TWSI1 0x8 +#define APBC_TWSI2 0xc +#define APBC_TWSI3 0x10 +#define APBC_TWSI4 0x7c +#define APBC_TWSI5 0x80 +#define APBC_KPC 0x18 +#define APBC_UART0 0x2c +#define APBC_UART1 0x30 +#define APBC_UART2 0x34 +#define APBC_UART3 0x88 +#define APBC_GPIO 0x38 +#define APBC_PWM0 0x3c +#define APBC_PWM1 0x40 +#define APBC_PWM2 0x44 +#define APBC_PWM3 0x48 +#define APBC_SSP0 0x50 +#define APBC_SSP1 0x54 +#define APBC_SSP2 0x58 +#define APBC_SSP3 0x5c +#define APMU_SDH0 0x54 +#define APMU_SDH1 0x58 +#define APMU_SDH2 0xe8 +#define APMU_SDH3 0xec +#define APMU_USB 0x5c +#define APMU_DISP0 0x4c +#define APMU_DISP1 0x110 +#define APMU_CCIC0 0x50 +#define APMU_CCIC1 0xf4 +#define MPMU_UART_PLL 0x14 + +static DEFINE_SPINLOCK(clk_lock); + +static struct clk_factor_masks uart_factor_masks = { + .factor = 2, + .num_mask = 0x1fff, + .den_mask = 0x1fff, + .num_shift = 16, + .den_shift = 0, +}; + +static struct clk_factor_tbl uart_factor_tbl[] = { + {.num = 14634, .den = 2165}, /*14.745MHZ */ + {.num = 3521, .den = 689}, /*19.23MHZ */ + {.num = 9679, .den = 5728}, /*58.9824MHZ */ + {.num = 15850, .den = 9451}, /*59.429MHZ */ +}; + +static const char *uart_parent[] = {"uart_pll", "vctcxo"}; +static const char *ssp_parent[] = {"vctcxo_4", "vctcxo_2", "vctcxo", "pll1_16"}; +static const char *sdh_parent[] = {"pll1_4", "pll2", "usb_pll", "pll1"}; +static const char *disp_parent[] = {"pll1", "pll1_16", "pll2", "vctcxo"}; +static const char *ccic_parent[] = {"pll1_2", "pll1_16", "vctcxo"}; + +void __init mmp2_clk_init(void) +{ + struct clk *clk; + struct clk *vctcxo; + void __iomem *mpmu_base; + void __iomem *apmu_base; + void __iomem *apbc_base; + + mpmu_base = ioremap(APB_PHYS_BASE + 0x50000, SZ_4K); + if (mpmu_base == NULL) { + pr_err("error to ioremap MPMU base\n"); + return; + } + + apmu_base = ioremap(AXI_PHYS_BASE + 0x82800, SZ_4K); + if (apmu_base == NULL) { + pr_err("error to ioremap APMU base\n"); + return; + } + + apbc_base = ioremap(APB_PHYS_BASE + 0x15000, SZ_4K); + if (apbc_base == NULL) { + pr_err("error to ioremap APBC base\n"); + return; + } + + clk = clk_register_fixed_rate(NULL, "clk32", NULL, CLK_IS_ROOT, 3200); + clk_register_clkdev(clk, "clk32", NULL); + + vctcxo = clk_register_fixed_rate(NULL, "vctcxo", NULL, CLK_IS_ROOT, + 26000000); + clk_register_clkdev(vctcxo, "vctcxo", NULL); + + clk = clk_register_fixed_rate(NULL, "pll1", NULL, CLK_IS_ROOT, + 800000000); + clk_register_clkdev(clk, "pll1", NULL); + + clk = clk_register_fixed_rate(NULL, "usb_pll", NULL, CLK_IS_ROOT, + 480000000); + clk_register_clkdev(clk, "usb_pll", NULL); + + clk = clk_register_fixed_rate(NULL, "pll2", NULL, CLK_IS_ROOT, + 960000000); + clk_register_clkdev(clk, "pll2", NULL); + + clk = clk_register_fixed_factor(NULL, "pll1_2", "pll1", + CLK_SET_RATE_PARENT, 1, 2); + clk_register_clkdev(clk, "pll1_2", NULL); + + clk = clk_register_fixed_factor(NULL, "pll1_4", "pll1_2", + CLK_SET_RATE_PARENT, 1, 2); + clk_register_clkdev(clk, "pll1_4", NULL); + + clk = clk_register_fixed_factor(NULL, "pll1_8", "pll1_4", + CLK_SET_RATE_PARENT, 1, 2); + clk_register_clkdev(clk, "pll1_8", NULL); + + clk = clk_register_fixed_factor(NULL, "pll1_16", "pll1_8", + CLK_SET_RATE_PARENT, 1, 2); + clk_register_clkdev(clk, "pll1_16", NULL); + + clk = clk_register_fixed_factor(NULL, "pll1_20", "pll1_4", + CLK_SET_RATE_PARENT, 1, 5); + clk_register_clkdev(clk, "pll1_20", NULL); + + clk = clk_register_fixed_factor(NULL, "pll1_3", "pll1", + CLK_SET_RATE_PARENT, 1, 3); + clk_register_clkdev(clk, "pll1_3", NULL); + + clk = clk_register_fixed_factor(NULL, "pll1_6", "pll1_3", + CLK_SET_RATE_PARENT, 1, 2); + clk_register_clkdev(clk, "pll1_6", NULL); + + clk = clk_register_fixed_factor(NULL, "pll1_12", "pll1_6", + CLK_SET_RATE_PARENT, 1, 2); + clk_register_clkdev(clk, "pll1_12", NULL); + + clk = clk_register_fixed_factor(NULL, "pll2_2", "pll2", + CLK_SET_RATE_PARENT, 1, 2); + clk_register_clkdev(clk, "pll2_2", NULL); + + clk = clk_register_fixed_factor(NULL, "pll2_4", "pll2_2", + CLK_SET_RATE_PARENT, 1, 2); + clk_register_clkdev(clk, "pll2_4", NULL); + + clk = clk_register_fixed_factor(NULL, "pll2_8", "pll2_4", + CLK_SET_RATE_PARENT, 1, 2); + clk_register_clkdev(clk, "pll2_8", NULL); + + clk = clk_register_fixed_factor(NULL, "pll2_16", "pll2_8", + CLK_SET_RATE_PARENT, 1, 2); + clk_register_clkdev(clk, "pll2_16", NULL); + + clk = clk_register_fixed_factor(NULL, "pll2_3", "pll2", + CLK_SET_RATE_PARENT, 1, 3); + clk_register_clkdev(clk, "pll2_3", NULL); + + clk = clk_register_fixed_factor(NULL, "pll2_6", "pll2_3", + CLK_SET_RATE_PARENT, 1, 2); + clk_register_clkdev(clk, "pll2_6", NULL); + + clk = clk_register_fixed_factor(NULL, "pll2_12", "pll2_6", + CLK_SET_RATE_PARENT, 1, 2); + clk_register_clkdev(clk, "pll2_12", NULL); + + clk = clk_register_fixed_factor(NULL, "vctcxo_2", "vctcxo", + CLK_SET_RATE_PARENT, 1, 2); + clk_register_clkdev(clk, "vctcxo_2", NULL); + + clk = clk_register_fixed_factor(NULL, "vctcxo_4", "vctcxo_2", + CLK_SET_RATE_PARENT, 1, 2); + clk_register_clkdev(clk, "vctcxo_4", NULL); + + clk = mmp_clk_register_factor("uart_pll", "pll1_4", 0, + mpmu_base + MPMU_UART_PLL, + &uart_factor_masks, uart_factor_tbl, + ARRAY_SIZE(uart_factor_tbl)); + clk_set_rate(clk, 14745600); + clk_register_clkdev(clk, "uart_pll", NULL); + + clk = mmp_clk_register_apbc("twsi0", "vctcxo", + apbc_base + APBC_TWSI0, 10, 0, &clk_lock); + clk_register_clkdev(clk, NULL, "pxa2xx-i2c.0"); + + clk = mmp_clk_register_apbc("twsi1", "vctcxo", + apbc_base + APBC_TWSI1, 10, 0, &clk_lock); + clk_register_clkdev(clk, NULL, "pxa2xx-i2c.1"); + + clk = mmp_clk_register_apbc("twsi2", "vctcxo", + apbc_base + APBC_TWSI2, 10, 0, &clk_lock); + clk_register_clkdev(clk, NULL, "pxa2xx-i2c.2"); + + clk = mmp_clk_register_apbc("twsi3", "vctcxo", + apbc_base + APBC_TWSI3, 10, 0, &clk_lock); + clk_register_clkdev(clk, NULL, "pxa2xx-i2c.3"); + + clk = mmp_clk_register_apbc("twsi4", "vctcxo", + apbc_base + APBC_TWSI4, 10, 0, &clk_lock); + clk_register_clkdev(clk, NULL, "pxa2xx-i2c.4"); + + clk = mmp_clk_register_apbc("twsi5", "vctcxo", + apbc_base + APBC_TWSI5, 10, 0, &clk_lock); + clk_register_clkdev(clk, NULL, "pxa2xx-i2c.5"); + + clk = mmp_clk_register_apbc("gpio", "vctcxo", + apbc_base + APBC_GPIO, 10, 0, &clk_lock); + clk_register_clkdev(clk, NULL, "pxa-gpio"); + + clk = mmp_clk_register_apbc("kpc", "clk32", + apbc_base + APBC_KPC, 10, 0, &clk_lock); + clk_register_clkdev(clk, NULL, "pxa27x-keypad"); + + clk = mmp_clk_register_apbc("rtc", "clk32", + apbc_base + APBC_RTC, 10, 0, &clk_lock); + clk_register_clkdev(clk, NULL, "mmp-rtc"); + + clk = mmp_clk_register_apbc("pwm0", "vctcxo", + apbc_base + APBC_PWM0, 10, 0, &clk_lock); + clk_register_clkdev(clk, NULL, "mmp2-pwm.0"); + + clk = mmp_clk_register_apbc("pwm1", "vctcxo", + apbc_base + APBC_PWM1, 10, 0, &clk_lock); + clk_register_clkdev(clk, NULL, "mmp2-pwm.1"); + + clk = mmp_clk_register_apbc("pwm2", "vctcxo", + apbc_base + APBC_PWM2, 10, 0, &clk_lock); + clk_register_clkdev(clk, NULL, "mmp2-pwm.2"); + + clk = mmp_clk_register_apbc("pwm3", "vctcxo", + apbc_base + APBC_PWM3, 10, 0, &clk_lock); + clk_register_clkdev(clk, NULL, "mmp2-pwm.3"); + + clk = clk_register_mux(NULL, "uart0_mux", uart_parent, + ARRAY_SIZE(uart_parent), CLK_SET_RATE_PARENT, + apbc_base + APBC_UART0, 4, 3, 0, &clk_lock); + clk_set_parent(clk, vctcxo); + clk_register_clkdev(clk, "uart_mux.0", NULL); + + clk = mmp_clk_register_apbc("uart0", "uart0_mux", + apbc_base + APBC_UART0, 10, 0, &clk_lock); + clk_register_clkdev(clk, NULL, "pxa2xx-uart.0"); + + clk = clk_register_mux(NULL, "uart1_mux", uart_parent, + ARRAY_SIZE(uart_parent), CLK_SET_RATE_PARENT, + apbc_base + APBC_UART1, 4, 3, 0, &clk_lock); + clk_set_parent(clk, vctcxo); + clk_register_clkdev(clk, "uart_mux.1", NULL); + + clk = mmp_clk_register_apbc("uart1", "uart1_mux", + apbc_base + APBC_UART1, 10, 0, &clk_lock); + clk_register_clkdev(clk, NULL, "pxa2xx-uart.1"); + + clk = clk_register_mux(NULL, "uart2_mux", uart_parent, + ARRAY_SIZE(uart_parent), CLK_SET_RATE_PARENT, + apbc_base + APBC_UART2, 4, 3, 0, &clk_lock); + clk_set_parent(clk, vctcxo); + clk_register_clkdev(clk, "uart_mux.2", NULL); + + clk = mmp_clk_register_apbc("uart2", "uart2_mux", + apbc_base + APBC_UART2, 10, 0, &clk_lock); + clk_register_clkdev(clk, NULL, "pxa2xx-uart.2"); + + clk = clk_register_mux(NULL, "uart3_mux", uart_parent, + ARRAY_SIZE(uart_parent), CLK_SET_RATE_PARENT, + apbc_base + APBC_UART3, 4, 3, 0, &clk_lock); + clk_set_parent(clk, vctcxo); + clk_register_clkdev(clk, "uart_mux.3", NULL); + + clk = mmp_clk_register_apbc("uart3", "uart3_mux", + apbc_base + APBC_UART3, 10, 0, &clk_lock); + clk_register_clkdev(clk, NULL, "pxa2xx-uart.3"); + + clk = clk_register_mux(NULL, "ssp0_mux", ssp_parent, + ARRAY_SIZE(ssp_parent), CLK_SET_RATE_PARENT, + apbc_base + APBC_SSP0, 4, 3, 0, &clk_lock); + clk_register_clkdev(clk, "uart_mux.0", NULL); + + clk = mmp_clk_register_apbc("ssp0", "ssp0_mux", + apbc_base + APBC_SSP0, 10, 0, &clk_lock); + clk_register_clkdev(clk, NULL, "mmp-ssp.0"); + + clk = clk_register_mux(NULL, "ssp1_mux", ssp_parent, + ARRAY_SIZE(ssp_parent), CLK_SET_RATE_PARENT, + apbc_base + APBC_SSP1, 4, 3, 0, &clk_lock); + clk_register_clkdev(clk, "ssp_mux.1", NULL); + + clk = mmp_clk_register_apbc("ssp1", "ssp1_mux", + apbc_base + APBC_SSP1, 10, 0, &clk_lock); + clk_register_clkdev(clk, NULL, "mmp-ssp.1"); + + clk = clk_register_mux(NULL, "ssp2_mux", ssp_parent, + ARRAY_SIZE(ssp_parent), CLK_SET_RATE_PARENT, + apbc_base + APBC_SSP2, 4, 3, 0, &clk_lock); + clk_register_clkdev(clk, "ssp_mux.2", NULL); + + clk = mmp_clk_register_apbc("ssp2", "ssp2_mux", + apbc_base + APBC_SSP2, 10, 0, &clk_lock); + clk_register_clkdev(clk, NULL, "mmp-ssp.2"); + + clk = clk_register_mux(NULL, "ssp3_mux", ssp_parent, + ARRAY_SIZE(ssp_parent), CLK_SET_RATE_PARENT, + apbc_base + APBC_SSP3, 4, 3, 0, &clk_lock); + clk_register_clkdev(clk, "ssp_mux.3", NULL); + + clk = mmp_clk_register_apbc("ssp3", "ssp3_mux", + apbc_base + APBC_SSP3, 10, 0, &clk_lock); + clk_register_clkdev(clk, NULL, "mmp-ssp.3"); + + clk = clk_register_mux(NULL, "sdh_mux", sdh_parent, + ARRAY_SIZE(sdh_parent), CLK_SET_RATE_PARENT, + apmu_base + APMU_SDH0, 8, 2, 0, &clk_lock); + clk_register_clkdev(clk, "sdh_mux", NULL); + + clk = clk_register_divider(NULL, "sdh_div", "sdh_mux", + CLK_SET_RATE_PARENT, apmu_base + APMU_SDH0, + 10, 4, CLK_DIVIDER_ONE_BASED, &clk_lock); + clk_register_clkdev(clk, "sdh_div", NULL); + + clk = mmp_clk_register_apmu("sdh0", "sdh_div", apmu_base + APMU_SDH0, + 0x1b, &clk_lock); + clk_register_clkdev(clk, NULL, "sdhci-pxav3.0"); + + clk = mmp_clk_register_apmu("sdh1", "sdh_div", apmu_base + APMU_SDH1, + 0x1b, &clk_lock); + clk_register_clkdev(clk, NULL, "sdhci-pxav3.1"); + + clk = mmp_clk_register_apmu("sdh2", "sdh_div", apmu_base + APMU_SDH2, + 0x1b, &clk_lock); + clk_register_clkdev(clk, NULL, "sdhci-pxav3.2"); + + clk = mmp_clk_register_apmu("sdh3", "sdh_div", apmu_base + APMU_SDH3, + 0x1b, &clk_lock); + clk_register_clkdev(clk, NULL, "sdhci-pxav3.3"); + + clk = mmp_clk_register_apmu("usb", "usb_pll", apmu_base + APMU_USB, + 0x9, &clk_lock); + clk_register_clkdev(clk, "usb_clk", NULL); + + clk = clk_register_mux(NULL, "disp0_mux", disp_parent, + ARRAY_SIZE(disp_parent), CLK_SET_RATE_PARENT, + apmu_base + APMU_DISP0, 6, 2, 0, &clk_lock); + clk_register_clkdev(clk, "disp_mux.0", NULL); + + clk = clk_register_divider(NULL, "disp0_div", "disp0_mux", + CLK_SET_RATE_PARENT, apmu_base + APMU_DISP0, + 8, 4, CLK_DIVIDER_ONE_BASED, &clk_lock); + clk_register_clkdev(clk, "disp_div.0", NULL); + + clk = mmp_clk_register_apmu("disp0", "disp0_div", + apmu_base + APMU_DISP0, 0x1b, &clk_lock); + clk_register_clkdev(clk, NULL, "mmp-disp.0"); + + clk = clk_register_divider(NULL, "disp0_sphy_div", "disp0_mux", 0, + apmu_base + APMU_DISP0, 15, 5, 0, &clk_lock); + clk_register_clkdev(clk, "disp_sphy_div.0", NULL); + + clk = mmp_clk_register_apmu("disp0_sphy", "disp0_sphy_div", + apmu_base + APMU_DISP0, 0x1024, &clk_lock); + clk_register_clkdev(clk, "disp_sphy.0", NULL); + + clk = clk_register_mux(NULL, "disp1_mux", disp_parent, + ARRAY_SIZE(disp_parent), CLK_SET_RATE_PARENT, + apmu_base + APMU_DISP1, 6, 2, 0, &clk_lock); + clk_register_clkdev(clk, "disp_mux.1", NULL); + + clk = clk_register_divider(NULL, "disp1_div", "disp1_mux", + CLK_SET_RATE_PARENT, apmu_base + APMU_DISP1, + 8, 4, CLK_DIVIDER_ONE_BASED, &clk_lock); + clk_register_clkdev(clk, "disp_div.1", NULL); + + clk = mmp_clk_register_apmu("disp1", "disp1_div", + apmu_base + APMU_DISP1, 0x1b, &clk_lock); + clk_register_clkdev(clk, NULL, "mmp-disp.1"); + + clk = mmp_clk_register_apmu("ccic_arbiter", "vctcxo", + apmu_base + APMU_CCIC0, 0x1800, &clk_lock); + clk_register_clkdev(clk, "ccic_arbiter", NULL); + + clk = clk_register_mux(NULL, "ccic0_mux", ccic_parent, + ARRAY_SIZE(ccic_parent), CLK_SET_RATE_PARENT, + apmu_base + APMU_CCIC0, 6, 2, 0, &clk_lock); + clk_register_clkdev(clk, "ccic_mux.0", NULL); + + clk = clk_register_divider(NULL, "ccic0_div", "ccic0_mux", + CLK_SET_RATE_PARENT, apmu_base + APMU_CCIC0, + 17, 4, CLK_DIVIDER_ONE_BASED, &clk_lock); + clk_register_clkdev(clk, "ccic_div.0", NULL); + + clk = mmp_clk_register_apmu("ccic0", "ccic0_div", + apmu_base + APMU_CCIC0, 0x1b, &clk_lock); + clk_register_clkdev(clk, "fnclk", "mmp-ccic.0"); + + clk = mmp_clk_register_apmu("ccic0_phy", "ccic0_div", + apmu_base + APMU_CCIC0, 0x24, &clk_lock); + clk_register_clkdev(clk, "phyclk", "mmp-ccic.0"); + + clk = clk_register_divider(NULL, "ccic0_sphy_div", "ccic0_div", + CLK_SET_RATE_PARENT, apmu_base + APMU_CCIC0, + 10, 5, 0, &clk_lock); + clk_register_clkdev(clk, "sphyclk_div", "mmp-ccic.0"); + + clk = mmp_clk_register_apmu("ccic0_sphy", "ccic0_sphy_div", + apmu_base + APMU_CCIC0, 0x300, &clk_lock); + clk_register_clkdev(clk, "sphyclk", "mmp-ccic.0"); + + clk = clk_register_mux(NULL, "ccic1_mux", ccic_parent, + ARRAY_SIZE(ccic_parent), CLK_SET_RATE_PARENT, + apmu_base + APMU_CCIC1, 6, 2, 0, &clk_lock); + clk_register_clkdev(clk, "ccic_mux.1", NULL); + + clk = clk_register_divider(NULL, "ccic1_div", "ccic1_mux", + CLK_SET_RATE_PARENT, apmu_base + APMU_CCIC1, + 16, 4, CLK_DIVIDER_ONE_BASED, &clk_lock); + clk_register_clkdev(clk, "ccic_div.1", NULL); + + clk = mmp_clk_register_apmu("ccic1", "ccic1_div", + apmu_base + APMU_CCIC1, 0x1b, &clk_lock); + clk_register_clkdev(clk, "fnclk", "mmp-ccic.1"); + + clk = mmp_clk_register_apmu("ccic1_phy", "ccic1_div", + apmu_base + APMU_CCIC1, 0x24, &clk_lock); + clk_register_clkdev(clk, "phyclk", "mmp-ccic.1"); + + clk = clk_register_divider(NULL, "ccic1_sphy_div", "ccic1_div", + CLK_SET_RATE_PARENT, apmu_base + APMU_CCIC1, + 10, 5, 0, &clk_lock); + clk_register_clkdev(clk, "sphyclk_div", "mmp-ccic.1"); + + clk = mmp_clk_register_apmu("ccic1_sphy", "ccic1_sphy_div", + apmu_base + APMU_CCIC1, 0x300, &clk_lock); + clk_register_clkdev(clk, "sphyclk", "mmp-ccic.1"); +} -- cgit v1.2.3 From 5175cb5894d606f1756c07a685e6dcabd2d8745a Mon Sep 17 00:00:00 2001 From: Kelvin Cheung Date: Mon, 20 Aug 2012 18:05:35 +0800 Subject: clk: add Loongson1B clock support This adds clock support to Loongson1B SoC using the common clock infrastructure. Signed-off-by: Kelvin Cheung Signed-off-by: Mike Turquette --- drivers/clk/Makefile | 1 + drivers/clk/clk-ls1x.c | 111 +++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 112 insertions(+) create mode 100644 drivers/clk/clk-ls1x.c (limited to 'drivers') diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile index fa5e1d210b84..649265152bca 100644 --- a/drivers/clk/Makefile +++ b/drivers/clk/Makefile @@ -14,6 +14,7 @@ obj-$(CONFIG_ARCH_PRIMA2) += clk-prima2.o ifeq ($(CONFIG_COMMON_CLK), y) obj-$(CONFIG_ARCH_MMP) += mmp/ endif +obj-$(CONFIG_MACH_LOONGSON1) += clk-ls1x.o # Chip specific obj-$(CONFIG_COMMON_CLK_WM831X) += clk-wm831x.o diff --git a/drivers/clk/clk-ls1x.c b/drivers/clk/clk-ls1x.c new file mode 100644 index 000000000000..f20b750235f6 --- /dev/null +++ b/drivers/clk/clk-ls1x.c @@ -0,0 +1,111 @@ +/* + * Copyright (c) 2012 Zhang, Keguang + * + * 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 + +#define OSC 33 + +static DEFINE_SPINLOCK(_lock); + +static int ls1x_pll_clk_enable(struct clk_hw *hw) +{ + return 0; +} + +static void ls1x_pll_clk_disable(struct clk_hw *hw) +{ +} + +static unsigned long ls1x_pll_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) +{ + u32 pll, rate; + + pll = __raw_readl(LS1X_CLK_PLL_FREQ); + rate = ((12 + (pll & 0x3f)) * 1000000) + + ((((pll >> 8) & 0x3ff) * 1000000) >> 10); + rate *= OSC; + rate >>= 1; + + return rate; +} + +static const struct clk_ops ls1x_pll_clk_ops = { + .enable = ls1x_pll_clk_enable, + .disable = ls1x_pll_clk_disable, + .recalc_rate = ls1x_pll_recalc_rate, +}; + +static struct clk * __init clk_register_pll(struct device *dev, + const char *name, const char *parent_name, unsigned long flags) +{ + struct clk_hw *hw; + struct clk *clk; + struct clk_init_data init; + + /* allocate the divider */ + hw = kzalloc(sizeof(struct clk_hw), GFP_KERNEL); + if (!hw) { + pr_err("%s: could not allocate clk_hw\n", __func__); + return ERR_PTR(-ENOMEM); + } + + init.name = name; + init.ops = &ls1x_pll_clk_ops; + init.flags = flags | CLK_IS_BASIC; + init.parent_names = (parent_name ? &parent_name : NULL); + init.num_parents = (parent_name ? 1 : 0); + hw->init = &init; + + /* register the clock */ + clk = clk_register(dev, hw); + + if (IS_ERR(clk)) + kfree(hw); + + return clk; +} + +void __init ls1x_clk_init(void) +{ + struct clk *clk; + + clk = clk_register_pll(NULL, "pll_clk", NULL, CLK_IS_ROOT); + clk_prepare_enable(clk); + + clk = clk_register_divider(NULL, "cpu_clk", "pll_clk", + CLK_SET_RATE_PARENT, LS1X_CLK_PLL_DIV, DIV_CPU_SHIFT, + DIV_CPU_WIDTH, CLK_DIVIDER_ONE_BASED, &_lock); + clk_prepare_enable(clk); + clk_register_clkdev(clk, "cpu", NULL); + + clk = clk_register_divider(NULL, "dc_clk", "pll_clk", + CLK_SET_RATE_PARENT, LS1X_CLK_PLL_DIV, DIV_DC_SHIFT, + DIV_DC_WIDTH, CLK_DIVIDER_ONE_BASED, &_lock); + clk_prepare_enable(clk); + clk_register_clkdev(clk, "dc", NULL); + + clk = clk_register_divider(NULL, "ahb_clk", "pll_clk", + CLK_SET_RATE_PARENT, LS1X_CLK_PLL_DIV, DIV_DDR_SHIFT, + DIV_DDR_WIDTH, CLK_DIVIDER_ONE_BASED, &_lock); + clk_prepare_enable(clk); + clk_register_clkdev(clk, "ahb", NULL); + clk_register_clkdev(clk, "stmmaceth", NULL); + + clk = clk_register_fixed_factor(NULL, "apb_clk", "ahb_clk", 0, 1, 2); + clk_prepare_enable(clk); + clk_register_clkdev(clk, "apb", NULL); + clk_register_clkdev(clk, "serial8250", NULL); +} -- cgit v1.2.3 From 672575e1dea4c6fe6b0579b94aa1c3af08a1a812 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Thu, 30 Aug 2012 19:39:00 +0200 Subject: clk: versatile: make config option boolean There is no choice to have the RealView clocks as module for sure, so turn this config option into a boolean. Reported-by: Pawel Moll Signed-off-by: Linus Walleij Signed-off-by: Mike Turquette --- drivers/clk/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/clk/Kconfig b/drivers/clk/Kconfig index 89b726d1afe5..df33b8e2b5ad 100644 --- a/drivers/clk/Kconfig +++ b/drivers/clk/Kconfig @@ -41,7 +41,7 @@ config COMMON_CLK_WM831X PMICs from Wolfson Microlectronics. config COMMON_CLK_VERSATILE - tristate "Clock driver for ARM Reference designs" + bool "Clock driver for ARM Reference designs" depends on ARCH_INTEGRATOR || ARCH_REALVIEW ---help--- Supports clocking on ARM Reference designs Integrator/AP, -- cgit v1.2.3 From 056876f6c73406c06d530d16d020177f5ec4a0bd Mon Sep 17 00:00:00 2001 From: Barry Song Date: Thu, 23 Aug 2012 10:47:54 +0800 Subject: pinctrl: sirf: add DT-binding pinmux mapping support This makes us possible to define pinmux mapping in board-specific DTS. prima2.dtsi provides all possible (groups,functions) configuration, and device in .dts select configurations from dtsi files. Signed-off-by: Barry Song Acked-by: Linus Walleij --- arch/arm/boot/dts/prima2-evb.dts | 37 +++++++ arch/arm/boot/dts/prima2.dtsi | 221 ++++++++++++++++++++++++++++++++++++- arch/arm/mach-prima2/Makefile.boot | 2 + drivers/pinctrl/pinctrl-sirf.c | 58 +++++++++- 4 files changed, 315 insertions(+), 3 deletions(-) create mode 100644 arch/arm/boot/dts/prima2-evb.dts (limited to 'drivers') diff --git a/arch/arm/boot/dts/prima2-evb.dts b/arch/arm/boot/dts/prima2-evb.dts new file mode 100644 index 000000000000..57286b4e7b87 --- /dev/null +++ b/arch/arm/boot/dts/prima2-evb.dts @@ -0,0 +1,37 @@ +/* + * DTS file for CSR SiRFprimaII Evaluation Board + * + * Copyright (c) 2012 Cambridge Silicon Radio Limited, a CSR plc group company. + * + * Licensed under GPLv2 or later. + */ + +/dts-v1/; + +/include/ "prima2.dtsi" + +/ { + model = "CSR SiRFprimaII Evaluation Board"; + compatible = "sirf,prima2", "sirf,prima2-cb"; + + memory { + reg = <0x00000000 0x20000000>; + }; + + axi { + peri-iobg { + uart@b0060000 { + pinctrl-names = "default"; + pinctrl-0 = <&uart1_pins_a>; + }; + spi@b00d0000 { + pinctrl-names = "default"; + pinctrl-0 = <&spi0_pins_a>; + }; + spi@b0170000 { + pinctrl-names = "default"; + pinctrl-0 = <&spi1_pins_a>; + }; + }; + }; +}; diff --git a/arch/arm/boot/dts/prima2.dtsi b/arch/arm/boot/dts/prima2.dtsi index 1b716aae64f7..055fca542120 100644 --- a/arch/arm/boot/dts/prima2.dtsi +++ b/arch/arm/boot/dts/prima2.dtsi @@ -277,14 +277,231 @@ interrupts = <33>; }; - gpio: gpio-controller@b0120000 { + gpio: pinctrl@b0120000 { #gpio-cells = <2>; #interrupt-cells = <2>; - compatible = "sirf,prima2-gpio-pinmux"; + compatible = "sirf,prima2-pinctrl"; reg = <0xb0120000 0x10000>; interrupts = <43 44 45 46 47>; gpio-controller; interrupt-controller; + + lcd_16pins_a: lcd0@0 { + lcd { + sirf,pins = "lcd_16bitsgrp"; + sirf,function = "lcd_16bits"; + }; + }; + lcd_18pins_a: lcd0@1 { + lcd { + sirf,pins = "lcd_18bitsgrp"; + sirf,function = "lcd_18bits"; + }; + }; + lcd_24pins_a: lcd0@2 { + lcd { + sirf,pins = "lcd_24bitsgrp"; + sirf,function = "lcd_24bits"; + }; + }; + lcdrom_pins_a: lcdrom0@0 { + lcd { + sirf,pins = "lcdromgrp"; + sirf,function = "lcdrom"; + }; + }; + uart0_pins_a: uart0@0 { + uart { + sirf,pins = "uart0grp"; + sirf,function = "uart0"; + }; + }; + uart1_pins_a: uart1@0 { + uart { + sirf,pins = "uart1grp"; + sirf,function = "uart1"; + }; + }; + uart2_pins_a: uart2@0 { + uart { + sirf,pins = "uart2grp"; + sirf,function = "uart2"; + }; + }; + uart2_noflow_pins_a: uart2@1 { + uart { + sirf,pins = "uart2_nostreamctrlgrp"; + sirf,function = "uart2_nostreamctrl"; + }; + }; + spi0_pins_a: spi0@0 { + spi { + sirf,pins = "spi0grp"; + sirf,function = "spi0"; + }; + }; + spi1_pins_a: spi1@0 { + spi { + sirf,pins = "spi1grp"; + sirf,function = "spi1"; + }; + }; + i2c0_pins_a: i2c0@0 { + i2c { + sirf,pins = "i2c0grp"; + sirf,function = "i2c0"; + }; + }; + i2c1_pins_a: i2c1@0 { + i2c { + sirf,pins = "i2c1grp"; + sirf,function = "i2c1"; + }; + }; + pwm0_pins_a: pwm0@0 { + pwm { + sirf,pins = "pwm0grp"; + sirf,function = "pwm0"; + }; + }; + pwm1_pins_a: pwm1@0 { + pwm { + sirf,pins = "pwm1grp"; + sirf,function = "pwm1"; + }; + }; + pwm2_pins_a: pwm2@0 { + pwm { + sirf,pins = "pwm2grp"; + sirf,function = "pwm2"; + }; + }; + pwm3_pins_a: pwm3@0 { + pwm { + sirf,pins = "pwm3grp"; + sirf,function = "pwm3"; + }; + }; + gps_pins_a: gps@0 { + gps { + sirf,pins = "gpsgrp"; + sirf,function = "gps"; + }; + }; + vip_pins_a: vip@0 { + vip { + sirf,pins = "vipgrp"; + sirf,function = "vip"; + }; + }; + sdmmc0_pins_a: sdmmc0@0 { + sdmmc0 { + sirf,pins = "sdmmc0grp"; + sirf,function = "sdmmc0"; + }; + }; + sdmmc1_pins_a: sdmmc1@0 { + sdmmc1 { + sirf,pins = "sdmmc1grp"; + sirf,function = "sdmmc1"; + }; + }; + sdmmc2_pins_a: sdmmc2@0 { + sdmmc2 { + sirf,pins = "sdmmc2grp"; + sirf,function = "sdmmc2"; + }; + }; + sdmmc3_pins_a: sdmmc3@0 { + sdmmc3 { + sirf,pins = "sdmmc3grp"; + sirf,function = "sdmmc3"; + }; + }; + sdmmc4_pins_a: sdmmc4@0 { + sdmmc4 { + sirf,pins = "sdmmc4grp"; + sirf,function = "sdmmc4"; + }; + }; + sdmmc5_pins_a: sdmmc5@0 { + sdmmc5 { + sirf,pins = "sdmmc5grp"; + sirf,function = "sdmmc5"; + }; + }; + i2s_pins_a: i2s@0 { + i2s { + sirf,pins = "i2sgrp"; + sirf,function = "i2s"; + }; + }; + ac97_pins_a: ac97@0 { + ac97 { + sirf,pins = "ac97grp"; + sirf,function = "ac97"; + }; + }; + nand_pins_a: nand@0 { + nand { + sirf,pins = "nandgrp"; + sirf,function = "nand"; + }; + }; + usp0_pins_a: usp0@0 { + usp0 { + sirf,pins = "usp0grp"; + sirf,function = "usp0"; + }; + }; + usp1_pins_a: usp1@0 { + usp1 { + sirf,pins = "usp1grp"; + sirf,function = "usp1"; + }; + }; + usp2_pins_a: usp2@0 { + usp2 { + sirf,pins = "usp2grp"; + sirf,function = "usp2"; + }; + }; + usb0_utmi_drvbus_pins_a: usb0_utmi_drvbus@0 { + usb0_utmi_drvbus { + sirf,pins = "usb0_utmi_drvbusgrp"; + sirf,function = "usb0_utmi_drvbus"; + }; + }; + usb1_utmi_drvbus_pins_a: usb1_utmi_drvbus@0 { + usb1_utmi_drvbus { + sirf,pins = "usb1_utmi_drvbusgrp"; + sirf,function = "usb1_utmi_drvbus"; + }; + }; + warm_rst_pins_a: warm_rst@0 { + warm_rst { + sirf,pins = "warm_rstgrp"; + sirf,function = "warm_rst"; + }; + }; + pulse_count_pins_a: pulse_count@0 { + pulse_count { + sirf,pins = "pulse_countgrp"; + sirf,function = "pulse_count"; + }; + }; + cko0_rst_pins_a: cko0_rst@0 { + cko0_rst { + sirf,pins = "cko0_rstgrp"; + sirf,function = "cko0_rst"; + }; + }; + cko1_rst_pins_a: cko1_rst@0 { + cko1_rst { + sirf,pins = "cko1_rstgrp"; + sirf,function = "cko1_rst"; + }; + }; }; pwm@b0130000 { diff --git a/arch/arm/mach-prima2/Makefile.boot b/arch/arm/mach-prima2/Makefile.boot index c77a4883a4ee..98167da874c9 100644 --- a/arch/arm/mach-prima2/Makefile.boot +++ b/arch/arm/mach-prima2/Makefile.boot @@ -1,3 +1,5 @@ zreladdr-y += 0x00008000 params_phys-y := 0x00000100 initrd_phys-y := 0x00800000 + +dtb-$(CONFIG_ARCH_PRIMA2) += prima2-evb.dtb diff --git a/drivers/pinctrl/pinctrl-sirf.c b/drivers/pinctrl/pinctrl-sirf.c index 7fca6ce5952b..304360cd213e 100644 --- a/drivers/pinctrl/pinctrl-sirf.c +++ b/drivers/pinctrl/pinctrl-sirf.c @@ -17,6 +17,7 @@ #include #include #include +#include #include #include #include @@ -916,11 +917,66 @@ static void sirfsoc_pin_dbg_show(struct pinctrl_dev *pctldev, struct seq_file *s seq_printf(s, " " DRIVER_NAME); } +static int sirfsoc_dt_node_to_map(struct pinctrl_dev *pctldev, + struct device_node *np_config, + struct pinctrl_map **map, unsigned *num_maps) +{ + struct sirfsoc_pmx *spmx = pinctrl_dev_get_drvdata(pctldev); + struct device_node *np; + struct property *prop; + const char *function, *group; + int ret, index = 0, count = 0; + + /* calculate number of maps required */ + for_each_child_of_node(np_config, np) { + ret = of_property_read_string(np, "sirf,function", &function); + if (ret < 0) + return ret; + + ret = of_property_count_strings(np, "sirf,pins"); + if (ret < 0) + return ret; + + count += ret; + } + + if (!count) { + dev_err(spmx->dev, "No child nodes passed via DT\n"); + return -ENODEV; + } + + *map = kzalloc(sizeof(**map) * count, GFP_KERNEL); + if (!*map) + return -ENOMEM; + + for_each_child_of_node(np_config, np) { + of_property_read_string(np, "sirf,function", &function); + of_property_for_each_string(np, "sirf,pins", prop, group) { + (*map)[index].type = PIN_MAP_TYPE_MUX_GROUP; + (*map)[index].data.mux.group = group; + (*map)[index].data.mux.function = function; + index++; + } + } + + *num_maps = count; + + return 0; +} + +static void sirfsoc_dt_free_map(struct pinctrl_dev *pctldev, + struct pinctrl_map *map, unsigned num_maps) +{ + kfree(map); +} + static struct pinctrl_ops sirfsoc_pctrl_ops = { .get_groups_count = sirfsoc_get_groups_count, .get_group_name = sirfsoc_get_group_name, .get_group_pins = sirfsoc_get_group_pins, .pin_dbg_show = sirfsoc_pin_dbg_show, + .dt_node_to_map = sirfsoc_dt_node_to_map, + .dt_free_map = sirfsoc_dt_free_map, }; struct sirfsoc_pmx_func { @@ -1221,7 +1277,7 @@ out_no_gpio_remap: } static const struct of_device_id pinmux_ids[] __devinitconst = { - { .compatible = "sirf,prima2-gpio-pinmux" }, + { .compatible = "sirf,prima2-pinctrl" }, {} }; -- cgit v1.2.3 From 3b01f87be21ce6b45ff4bd7b9d044aa9233bcc38 Mon Sep 17 00:00:00 2001 From: Ulf Hansson Date: Mon, 27 Aug 2012 15:45:50 +0200 Subject: clk: ux500: Adapt PRCMU and PRCC clocks for common clk First version of common clock implementation of PRCMU clocks and PRCC clocks for ux500 platforms. Signed-off-by: Ulf Hansson Acked-by: Linus Walleij Signed-off-by: Mike Turquette --- drivers/clk/ux500/Makefile | 7 ++ drivers/clk/ux500/clk-prcc.c | 164 +++++++++++++++++++++++++++++ drivers/clk/ux500/clk-prcmu.c | 238 ++++++++++++++++++++++++++++++++++++++++++ drivers/clk/ux500/clk.h | 43 ++++++++ 4 files changed, 452 insertions(+) create mode 100644 drivers/clk/ux500/Makefile create mode 100644 drivers/clk/ux500/clk-prcc.c create mode 100644 drivers/clk/ux500/clk-prcmu.c create mode 100644 drivers/clk/ux500/clk.h (limited to 'drivers') diff --git a/drivers/clk/ux500/Makefile b/drivers/clk/ux500/Makefile new file mode 100644 index 000000000000..a3ccd1b4cfcd --- /dev/null +++ b/drivers/clk/ux500/Makefile @@ -0,0 +1,7 @@ +# +# Makefile for ux500 clocks +# + +# Clock types +obj-y += clk-prcc.o +obj-y += clk-prcmu.o diff --git a/drivers/clk/ux500/clk-prcc.c b/drivers/clk/ux500/clk-prcc.c new file mode 100644 index 000000000000..7eee7f768355 --- /dev/null +++ b/drivers/clk/ux500/clk-prcc.c @@ -0,0 +1,164 @@ +/* + * PRCC clock implementation for ux500 platform. + * + * Copyright (C) 2012 ST-Ericsson SA + * Author: Ulf Hansson + * + * License terms: GNU General Public License (GPL) version 2 + */ + +#include +#include +#include +#include +#include +#include +#include + +#include "clk.h" + +#define PRCC_PCKEN 0x000 +#define PRCC_PCKDIS 0x004 +#define PRCC_KCKEN 0x008 +#define PRCC_KCKDIS 0x00C +#define PRCC_PCKSR 0x010 +#define PRCC_KCKSR 0x014 + +#define to_clk_prcc(_hw) container_of(_hw, struct clk_prcc, hw) + +struct clk_prcc { + struct clk_hw hw; + void __iomem *base; + u32 cg_sel; + int is_enabled; +}; + +/* PRCC clock operations. */ + +static int clk_prcc_pclk_enable(struct clk_hw *hw) +{ + struct clk_prcc *clk = to_clk_prcc(hw); + + writel(clk->cg_sel, (clk->base + PRCC_PCKEN)); + while (!(readl(clk->base + PRCC_PCKSR) & clk->cg_sel)) + cpu_relax(); + + clk->is_enabled = 1; + return 0; +} + +static void clk_prcc_pclk_disable(struct clk_hw *hw) +{ + struct clk_prcc *clk = to_clk_prcc(hw); + + writel(clk->cg_sel, (clk->base + PRCC_PCKDIS)); + clk->is_enabled = 0; +} + +static int clk_prcc_kclk_enable(struct clk_hw *hw) +{ + struct clk_prcc *clk = to_clk_prcc(hw); + + writel(clk->cg_sel, (clk->base + PRCC_KCKEN)); + while (!(readl(clk->base + PRCC_KCKSR) & clk->cg_sel)) + cpu_relax(); + + clk->is_enabled = 1; + return 0; +} + +static void clk_prcc_kclk_disable(struct clk_hw *hw) +{ + struct clk_prcc *clk = to_clk_prcc(hw); + + writel(clk->cg_sel, (clk->base + PRCC_KCKDIS)); + clk->is_enabled = 0; +} + +static int clk_prcc_is_enabled(struct clk_hw *hw) +{ + struct clk_prcc *clk = to_clk_prcc(hw); + return clk->is_enabled; +} + +static struct clk_ops clk_prcc_pclk_ops = { + .enable = clk_prcc_pclk_enable, + .disable = clk_prcc_pclk_disable, + .is_enabled = clk_prcc_is_enabled, +}; + +static struct clk_ops clk_prcc_kclk_ops = { + .enable = clk_prcc_kclk_enable, + .disable = clk_prcc_kclk_disable, + .is_enabled = clk_prcc_is_enabled, +}; + +static struct clk *clk_reg_prcc(const char *name, + const char *parent_name, + resource_size_t phy_base, + u32 cg_sel, + unsigned long flags, + struct clk_ops *clk_prcc_ops) +{ + struct clk_prcc *clk; + struct clk_init_data clk_prcc_init; + struct clk *clk_reg; + + if (!name) { + pr_err("clk_prcc: %s invalid arguments passed\n", __func__); + return ERR_PTR(-EINVAL); + } + + clk = kzalloc(sizeof(struct clk_prcc), GFP_KERNEL); + if (!clk) { + pr_err("clk_prcc: %s could not allocate clk\n", __func__); + return ERR_PTR(-ENOMEM); + } + + clk->base = ioremap(phy_base, SZ_4K); + if (!clk->base) + goto free_clk; + + clk->cg_sel = cg_sel; + clk->is_enabled = 1; + + clk_prcc_init.name = name; + clk_prcc_init.ops = clk_prcc_ops; + clk_prcc_init.flags = flags; + clk_prcc_init.parent_names = (parent_name ? &parent_name : NULL); + clk_prcc_init.num_parents = (parent_name ? 1 : 0); + clk->hw.init = &clk_prcc_init; + + clk_reg = clk_register(NULL, &clk->hw); + if (IS_ERR_OR_NULL(clk_reg)) + goto unmap_clk; + + return clk_reg; + +unmap_clk: + iounmap(clk->base); +free_clk: + kfree(clk); + pr_err("clk_prcc: %s failed to register clk\n", __func__); + return ERR_PTR(-ENOMEM); +} + +struct clk *clk_reg_prcc_pclk(const char *name, + const char *parent_name, + resource_size_t phy_base, + u32 cg_sel, + unsigned long flags) +{ + return clk_reg_prcc(name, parent_name, phy_base, cg_sel, flags, + &clk_prcc_pclk_ops); +} + +struct clk *clk_reg_prcc_kclk(const char *name, + const char *parent_name, + resource_size_t phy_base, + u32 cg_sel, + unsigned long flags) +{ + return clk_reg_prcc(name, parent_name, phy_base, cg_sel, flags, + &clk_prcc_kclk_ops); +} diff --git a/drivers/clk/ux500/clk-prcmu.c b/drivers/clk/ux500/clk-prcmu.c new file mode 100644 index 000000000000..1d779ad12169 --- /dev/null +++ b/drivers/clk/ux500/clk-prcmu.c @@ -0,0 +1,238 @@ +/* + * PRCMU clock implementation for ux500 platform. + * + * Copyright (C) 2012 ST-Ericsson SA + * Author: Ulf Hansson + * + * License terms: GNU General Public License (GPL) version 2 + */ + +#include +#include +#include +#include +#include +#include +#include "clk.h" + +#define to_clk_prcmu(_hw) container_of(_hw, struct clk_prcmu, hw) + +struct clk_prcmu { + struct clk_hw hw; + u8 cg_sel; + int is_enabled; +}; + +/* PRCMU clock operations. */ + +static int clk_prcmu_prepare(struct clk_hw *hw) +{ + struct clk_prcmu *clk = to_clk_prcmu(hw); + return prcmu_request_clock(clk->cg_sel, true); +} + +static void clk_prcmu_unprepare(struct clk_hw *hw) +{ + struct clk_prcmu *clk = to_clk_prcmu(hw); + if (prcmu_request_clock(clk->cg_sel, false)) + pr_err("clk_prcmu: %s failed to disable %s.\n", __func__, + hw->init->name); +} + +static int clk_prcmu_enable(struct clk_hw *hw) +{ + struct clk_prcmu *clk = to_clk_prcmu(hw); + clk->is_enabled = 1; + return 0; +} + +static void clk_prcmu_disable(struct clk_hw *hw) +{ + struct clk_prcmu *clk = to_clk_prcmu(hw); + clk->is_enabled = 0; +} + +static int clk_prcmu_is_enabled(struct clk_hw *hw) +{ + struct clk_prcmu *clk = to_clk_prcmu(hw); + return clk->is_enabled; +} + +static unsigned long clk_prcmu_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) +{ + struct clk_prcmu *clk = to_clk_prcmu(hw); + return prcmu_clock_rate(clk->cg_sel); +} + +static long clk_prcmu_round_rate(struct clk_hw *hw, unsigned long rate, + unsigned long *parent_rate) +{ + struct clk_prcmu *clk = to_clk_prcmu(hw); + return prcmu_round_clock_rate(clk->cg_sel, rate); +} + +static int clk_prcmu_set_rate(struct clk_hw *hw, unsigned long rate, + unsigned long parent_rate) +{ + struct clk_prcmu *clk = to_clk_prcmu(hw); + return prcmu_set_clock_rate(clk->cg_sel, rate); +} + +static int request_ape_opp100(bool enable) +{ + static int reqs; + int err = 0; + + if (enable) { + if (!reqs) + err = prcmu_qos_add_requirement(PRCMU_QOS_APE_OPP, + "clock", 100); + if (!err) + reqs++; + } else { + reqs--; + if (!reqs) + prcmu_qos_remove_requirement(PRCMU_QOS_APE_OPP, + "clock"); + } + return err; +} + +static int clk_prcmu_opp_prepare(struct clk_hw *hw) +{ + int err; + struct clk_prcmu *clk = to_clk_prcmu(hw); + + err = request_ape_opp100(true); + if (err) { + pr_err("clk_prcmu: %s failed to request APE OPP100 for %s.\n", + __func__, hw->init->name); + return err; + } + + err = prcmu_request_clock(clk->cg_sel, true); + if (err) + request_ape_opp100(false); + + return err; +} + +static void clk_prcmu_opp_unprepare(struct clk_hw *hw) +{ + struct clk_prcmu *clk = to_clk_prcmu(hw); + + if (prcmu_request_clock(clk->cg_sel, false)) + goto out_error; + if (request_ape_opp100(false)) + goto out_error; + return; + +out_error: + pr_err("clk_prcmu: %s failed to disable %s.\n", __func__, + hw->init->name); +} + +static struct clk_ops clk_prcmu_scalable_ops = { + .prepare = clk_prcmu_prepare, + .unprepare = clk_prcmu_unprepare, + .enable = clk_prcmu_enable, + .disable = clk_prcmu_disable, + .is_enabled = clk_prcmu_is_enabled, + .recalc_rate = clk_prcmu_recalc_rate, + .round_rate = clk_prcmu_round_rate, + .set_rate = clk_prcmu_set_rate, +}; + +static struct clk_ops clk_prcmu_gate_ops = { + .prepare = clk_prcmu_prepare, + .unprepare = clk_prcmu_unprepare, + .enable = clk_prcmu_enable, + .disable = clk_prcmu_disable, + .is_enabled = clk_prcmu_is_enabled, + .recalc_rate = clk_prcmu_recalc_rate, +}; + +static struct clk_ops clk_prcmu_opp_gate_ops = { + .prepare = clk_prcmu_opp_prepare, + .unprepare = clk_prcmu_opp_unprepare, + .enable = clk_prcmu_enable, + .disable = clk_prcmu_disable, + .is_enabled = clk_prcmu_is_enabled, + .recalc_rate = clk_prcmu_recalc_rate, +}; + +static struct clk *clk_reg_prcmu(const char *name, + const char *parent_name, + u8 cg_sel, + unsigned long rate, + unsigned long flags, + struct clk_ops *clk_prcmu_ops) +{ + struct clk_prcmu *clk; + struct clk_init_data clk_prcmu_init; + struct clk *clk_reg; + + if (!name) { + pr_err("clk_prcmu: %s invalid arguments passed\n", __func__); + return ERR_PTR(-EINVAL); + } + + clk = kzalloc(sizeof(struct clk_prcmu), GFP_KERNEL); + if (!clk) { + pr_err("clk_prcmu: %s could not allocate clk\n", __func__); + return ERR_PTR(-ENOMEM); + } + + clk->cg_sel = cg_sel; + clk->is_enabled = 1; + /* "rate" can be used for changing the initial frequency */ + if (rate) + prcmu_set_clock_rate(cg_sel, rate); + + clk_prcmu_init.name = name; + clk_prcmu_init.ops = clk_prcmu_ops; + clk_prcmu_init.flags = flags; + clk_prcmu_init.parent_names = (parent_name ? &parent_name : NULL); + clk_prcmu_init.num_parents = (parent_name ? 1 : 0); + clk->hw.init = &clk_prcmu_init; + + clk_reg = clk_register(NULL, &clk->hw); + if (IS_ERR_OR_NULL(clk_reg)) + goto free_clk; + + return clk_reg; + +free_clk: + kfree(clk); + pr_err("clk_prcmu: %s failed to register clk\n", __func__); + return ERR_PTR(-ENOMEM); +} + +struct clk *clk_reg_prcmu_scalable(const char *name, + const char *parent_name, + u8 cg_sel, + unsigned long rate, + unsigned long flags) +{ + return clk_reg_prcmu(name, parent_name, cg_sel, rate, flags, + &clk_prcmu_scalable_ops); +} + +struct clk *clk_reg_prcmu_gate(const char *name, + const char *parent_name, + u8 cg_sel, + unsigned long flags) +{ + return clk_reg_prcmu(name, parent_name, cg_sel, 0, flags, + &clk_prcmu_gate_ops); +} + +struct clk *clk_reg_prcmu_opp_gate(const char *name, + const char *parent_name, + u8 cg_sel, + unsigned long flags) +{ + return clk_reg_prcmu(name, parent_name, cg_sel, 0, flags, + &clk_prcmu_opp_gate_ops); +} diff --git a/drivers/clk/ux500/clk.h b/drivers/clk/ux500/clk.h new file mode 100644 index 000000000000..32085aa98865 --- /dev/null +++ b/drivers/clk/ux500/clk.h @@ -0,0 +1,43 @@ +/* + * Clocks for ux500 platforms + * + * Copyright (C) 2012 ST-Ericsson SA + * Author: Ulf Hansson + * + * License terms: GNU General Public License (GPL) version 2 + */ + +#ifndef __UX500_CLK_H +#define __UX500_CLK_H + +#include + +struct clk *clk_reg_prcc_pclk(const char *name, + const char *parent_name, + unsigned int phy_base, + u32 cg_sel, + unsigned long flags); + +struct clk *clk_reg_prcc_kclk(const char *name, + const char *parent_name, + unsigned int phy_base, + u32 cg_sel, + unsigned long flags); + +struct clk *clk_reg_prcmu_scalable(const char *name, + const char *parent_name, + u8 cg_sel, + unsigned long rate, + unsigned long flags); + +struct clk *clk_reg_prcmu_gate(const char *name, + const char *parent_name, + u8 cg_sel, + unsigned long flags); + +struct clk *clk_reg_prcmu_opp_gate(const char *name, + const char *parent_name, + u8 cg_sel, + unsigned long flags); + +#endif /* __UX500_CLK_H */ -- cgit v1.2.3 From bce5afd8d960e78892669b68751547015646d5e4 Mon Sep 17 00:00:00 2001 From: Ulf Hansson Date: Mon, 27 Aug 2012 15:45:51 +0200 Subject: clk: ux500: First version of clock definitions for ux500 In this first version of the clock definitions, the structure for ux500 are set. Support for u8500, u9540 and u8540 are prepared. Signed-off-by: Ulf Hansson Acked-by: Linus Walleij Signed-off-by: Mike Turquette --- drivers/clk/ux500/Makefile | 5 +++++ drivers/clk/ux500/u8500_clk.c | 21 +++++++++++++++++++++ drivers/clk/ux500/u8540_clk.c | 21 +++++++++++++++++++++ drivers/clk/ux500/u9540_clk.c | 21 +++++++++++++++++++++ include/linux/platform_data/clk-ux500.h | 17 +++++++++++++++++ 5 files changed, 85 insertions(+) create mode 100644 drivers/clk/ux500/u8500_clk.c create mode 100644 drivers/clk/ux500/u8540_clk.c create mode 100644 drivers/clk/ux500/u9540_clk.c create mode 100644 include/linux/platform_data/clk-ux500.h (limited to 'drivers') diff --git a/drivers/clk/ux500/Makefile b/drivers/clk/ux500/Makefile index a3ccd1b4cfcd..858fbfe66281 100644 --- a/drivers/clk/ux500/Makefile +++ b/drivers/clk/ux500/Makefile @@ -5,3 +5,8 @@ # Clock types obj-y += clk-prcc.o obj-y += clk-prcmu.o + +# Clock definitions +obj-y += u8500_clk.o +obj-y += u9540_clk.o +obj-y += u8540_clk.o diff --git a/drivers/clk/ux500/u8500_clk.c b/drivers/clk/ux500/u8500_clk.c new file mode 100644 index 000000000000..2bc4901599ed --- /dev/null +++ b/drivers/clk/ux500/u8500_clk.c @@ -0,0 +1,21 @@ +/* + * Clock definitions for u8500 platform. + * + * Copyright (C) 2012 ST-Ericsson SA + * Author: Ulf Hansson + * + * License terms: GNU General Public License (GPL) version 2 + */ + +#include +#include +#include +#include +#include + +#include "clk.h" + +void u8500_clk_init(void) +{ + /* register clocks here */ +} diff --git a/drivers/clk/ux500/u8540_clk.c b/drivers/clk/ux500/u8540_clk.c new file mode 100644 index 000000000000..10adfd2ead21 --- /dev/null +++ b/drivers/clk/ux500/u8540_clk.c @@ -0,0 +1,21 @@ +/* + * Clock definitions for u8540 platform. + * + * Copyright (C) 2012 ST-Ericsson SA + * Author: Ulf Hansson + * + * License terms: GNU General Public License (GPL) version 2 + */ + +#include +#include +#include +#include +#include + +#include "clk.h" + +void u8540_clk_init(void) +{ + /* register clocks here */ +} diff --git a/drivers/clk/ux500/u9540_clk.c b/drivers/clk/ux500/u9540_clk.c new file mode 100644 index 000000000000..dbc0191e16c8 --- /dev/null +++ b/drivers/clk/ux500/u9540_clk.c @@ -0,0 +1,21 @@ +/* + * Clock definitions for u9540 platform. + * + * Copyright (C) 2012 ST-Ericsson SA + * Author: Ulf Hansson + * + * License terms: GNU General Public License (GPL) version 2 + */ + +#include +#include +#include +#include +#include + +#include "clk.h" + +void u9540_clk_init(void) +{ + /* register clocks here */ +} diff --git a/include/linux/platform_data/clk-ux500.h b/include/linux/platform_data/clk-ux500.h new file mode 100644 index 000000000000..3af0da1f3be5 --- /dev/null +++ b/include/linux/platform_data/clk-ux500.h @@ -0,0 +1,17 @@ +/* + * Clock definitions for ux500 platforms + * + * Copyright (C) 2012 ST-Ericsson SA + * Author: Ulf Hansson + * + * License terms: GNU General Public License (GPL) version 2 + */ + +#ifndef __CLK_UX500_H +#define __CLK_UX500_H + +void u8500_clk_init(void); +void u9540_clk_init(void); +void u8540_clk_init(void); + +#endif /* __CLK_UX500_H */ -- cgit v1.2.3 From 0e6dcde7288f1de8e2a5896349342de5d316d3cb Mon Sep 17 00:00:00 2001 From: Ulf Hansson Date: Mon, 27 Aug 2012 15:45:52 +0200 Subject: clk: ux500: Clock definitions for u8500 First version of clock definitions of PRCMU and PRCC clocks for the u8500 platform. Signed-off-by: Ulf Hansson Acked-by: Linus Walleij Signed-off-by: Mike Turquette --- drivers/clk/ux500/u8500_clk.c | 454 +++++++++++++++++++++++++++++++++++++++++- 1 file changed, 453 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/clk/ux500/u8500_clk.c b/drivers/clk/ux500/u8500_clk.c index 2bc4901599ed..5c1fca1f28de 100644 --- a/drivers/clk/ux500/u8500_clk.c +++ b/drivers/clk/ux500/u8500_clk.c @@ -17,5 +17,457 @@ void u8500_clk_init(void) { - /* register clocks here */ + struct prcmu_fw_version *fw_version; + const char *sgaclk_parent = NULL; + struct clk *clk; + + /* Clock sources */ + clk = clk_reg_prcmu_gate("soc0_pll", NULL, PRCMU_PLLSOC0, + CLK_IS_ROOT|CLK_IGNORE_UNUSED); + clk_register_clkdev(clk, "soc0_pll", NULL); + + clk = clk_reg_prcmu_gate("soc1_pll", NULL, PRCMU_PLLSOC1, + CLK_IS_ROOT|CLK_IGNORE_UNUSED); + clk_register_clkdev(clk, "soc1_pll", NULL); + + clk = clk_reg_prcmu_gate("ddr_pll", NULL, PRCMU_PLLDDR, + CLK_IS_ROOT|CLK_IGNORE_UNUSED); + clk_register_clkdev(clk, "ddr_pll", NULL); + + /* FIXME: Add sys, ulp and int clocks here. */ + + clk = clk_register_fixed_rate(NULL, "rtc32k", "NULL", + CLK_IS_ROOT|CLK_IGNORE_UNUSED, + 32768); + clk_register_clkdev(clk, "clk32k", NULL); + clk_register_clkdev(clk, NULL, "rtc-pl031"); + + /* PRCMU clocks */ + fw_version = prcmu_get_fw_version(); + if (fw_version != NULL) { + switch (fw_version->project) { + case PRCMU_FW_PROJECT_U8500_C2: + case PRCMU_FW_PROJECT_U8520: + case PRCMU_FW_PROJECT_U8420: + sgaclk_parent = "soc0_pll"; + break; + default: + break; + } + } + + if (sgaclk_parent) + clk = clk_reg_prcmu_gate("sgclk", sgaclk_parent, + PRCMU_SGACLK, 0); + else + clk = clk_reg_prcmu_gate("sgclk", NULL, + PRCMU_SGACLK, CLK_IS_ROOT); + clk_register_clkdev(clk, NULL, "mali"); + + clk = clk_reg_prcmu_gate("uartclk", NULL, PRCMU_UARTCLK, CLK_IS_ROOT); + clk_register_clkdev(clk, NULL, "UART"); + + clk = clk_reg_prcmu_gate("msp02clk", NULL, PRCMU_MSP02CLK, CLK_IS_ROOT); + clk_register_clkdev(clk, NULL, "MSP02"); + + clk = clk_reg_prcmu_gate("msp1clk", NULL, PRCMU_MSP1CLK, CLK_IS_ROOT); + clk_register_clkdev(clk, NULL, "MSP1"); + + clk = clk_reg_prcmu_gate("i2cclk", NULL, PRCMU_I2CCLK, CLK_IS_ROOT); + clk_register_clkdev(clk, NULL, "I2C"); + + clk = clk_reg_prcmu_gate("slimclk", NULL, PRCMU_SLIMCLK, CLK_IS_ROOT); + clk_register_clkdev(clk, NULL, "slim"); + + clk = clk_reg_prcmu_gate("per1clk", NULL, PRCMU_PER1CLK, CLK_IS_ROOT); + clk_register_clkdev(clk, NULL, "PERIPH1"); + + clk = clk_reg_prcmu_gate("per2clk", NULL, PRCMU_PER2CLK, CLK_IS_ROOT); + clk_register_clkdev(clk, NULL, "PERIPH2"); + + clk = clk_reg_prcmu_gate("per3clk", NULL, PRCMU_PER3CLK, CLK_IS_ROOT); + clk_register_clkdev(clk, NULL, "PERIPH3"); + + clk = clk_reg_prcmu_gate("per5clk", NULL, PRCMU_PER5CLK, CLK_IS_ROOT); + clk_register_clkdev(clk, NULL, "PERIPH5"); + + clk = clk_reg_prcmu_gate("per6clk", NULL, PRCMU_PER6CLK, CLK_IS_ROOT); + clk_register_clkdev(clk, NULL, "PERIPH6"); + + clk = clk_reg_prcmu_gate("per7clk", NULL, PRCMU_PER7CLK, CLK_IS_ROOT); + clk_register_clkdev(clk, NULL, "PERIPH7"); + + clk = clk_reg_prcmu_scalable("lcdclk", NULL, PRCMU_LCDCLK, 0, + CLK_IS_ROOT|CLK_SET_RATE_GATE); + clk_register_clkdev(clk, NULL, "lcd"); + clk_register_clkdev(clk, "lcd", "mcde"); + + clk = clk_reg_prcmu_opp_gate("bmlclk", NULL, PRCMU_BMLCLK, CLK_IS_ROOT); + clk_register_clkdev(clk, NULL, "bml"); + + clk = clk_reg_prcmu_scalable("hsitxclk", NULL, PRCMU_HSITXCLK, 0, + CLK_IS_ROOT|CLK_SET_RATE_GATE); + + clk = clk_reg_prcmu_scalable("hsirxclk", NULL, PRCMU_HSIRXCLK, 0, + CLK_IS_ROOT|CLK_SET_RATE_GATE); + + clk = clk_reg_prcmu_scalable("hdmiclk", NULL, PRCMU_HDMICLK, 0, + CLK_IS_ROOT|CLK_SET_RATE_GATE); + clk_register_clkdev(clk, NULL, "hdmi"); + clk_register_clkdev(clk, "hdmi", "mcde"); + + clk = clk_reg_prcmu_gate("apeatclk", NULL, PRCMU_APEATCLK, CLK_IS_ROOT); + clk_register_clkdev(clk, NULL, "apeat"); + + clk = clk_reg_prcmu_gate("apetraceclk", NULL, PRCMU_APETRACECLK, + CLK_IS_ROOT); + clk_register_clkdev(clk, NULL, "apetrace"); + + clk = clk_reg_prcmu_gate("mcdeclk", NULL, PRCMU_MCDECLK, CLK_IS_ROOT); + clk_register_clkdev(clk, NULL, "mcde"); + clk_register_clkdev(clk, "mcde", "mcde"); + clk_register_clkdev(clk, "dsisys", "dsilink.0"); + clk_register_clkdev(clk, "dsisys", "dsilink.1"); + clk_register_clkdev(clk, "dsisys", "dsilink.2"); + + clk = clk_reg_prcmu_opp_gate("ipi2cclk", NULL, PRCMU_IPI2CCLK, + CLK_IS_ROOT); + clk_register_clkdev(clk, NULL, "ipi2"); + + clk = clk_reg_prcmu_gate("dsialtclk", NULL, PRCMU_DSIALTCLK, + CLK_IS_ROOT); + clk_register_clkdev(clk, NULL, "dsialt"); + + clk = clk_reg_prcmu_gate("dmaclk", NULL, PRCMU_DMACLK, CLK_IS_ROOT); + clk_register_clkdev(clk, NULL, "dma40.0"); + + clk = clk_reg_prcmu_gate("b2r2clk", NULL, PRCMU_B2R2CLK, CLK_IS_ROOT); + clk_register_clkdev(clk, NULL, "b2r2"); + clk_register_clkdev(clk, NULL, "b2r2_core"); + clk_register_clkdev(clk, NULL, "U8500-B2R2.0"); + + clk = clk_reg_prcmu_scalable("tvclk", NULL, PRCMU_TVCLK, 0, + CLK_IS_ROOT|CLK_SET_RATE_GATE); + clk_register_clkdev(clk, NULL, "tv"); + clk_register_clkdev(clk, "tv", "mcde"); + + clk = clk_reg_prcmu_gate("sspclk", NULL, PRCMU_SSPCLK, CLK_IS_ROOT); + clk_register_clkdev(clk, NULL, "SSP"); + + clk = clk_reg_prcmu_gate("rngclk", NULL, PRCMU_RNGCLK, CLK_IS_ROOT); + clk_register_clkdev(clk, NULL, "rngclk"); + + clk = clk_reg_prcmu_gate("uiccclk", NULL, PRCMU_UICCCLK, CLK_IS_ROOT); + clk_register_clkdev(clk, NULL, "uicc"); + + /* + * FIXME: The MTU clocks might need some kind of "parent muxed join" + * and these have no K-clocks. For now, we ignore the missing + * connection to the corresponding P-clocks, p6_mtu0_clk and + * p6_mtu1_clk. Instead timclk is used which is the valid parent. + */ + clk = clk_reg_prcmu_gate("timclk", NULL, PRCMU_TIMCLK, CLK_IS_ROOT); + clk_register_clkdev(clk, NULL, "mtu0"); + clk_register_clkdev(clk, NULL, "mtu1"); + + clk = clk_reg_prcmu_gate("sdmmcclk", NULL, PRCMU_SDMMCCLK, CLK_IS_ROOT); + clk_register_clkdev(clk, NULL, "sdmmc"); + + + clk = clk_reg_prcmu_scalable("dsi_pll", "hdmiclk", + PRCMU_PLLDSI, 0, CLK_SET_RATE_GATE); + clk_register_clkdev(clk, "dsihs2", "mcde"); + clk_register_clkdev(clk, "dsihs2", "dsilink.2"); + + + clk = clk_reg_prcmu_scalable("dsi0clk", "dsi_pll", + PRCMU_DSI0CLK, 0, CLK_SET_RATE_GATE); + clk_register_clkdev(clk, "dsihs0", "mcde"); + clk_register_clkdev(clk, "dsihs0", "dsilink.0"); + + clk = clk_reg_prcmu_scalable("dsi1clk", "dsi_pll", + PRCMU_DSI1CLK, 0, CLK_SET_RATE_GATE); + clk_register_clkdev(clk, "dsihs1", "mcde"); + clk_register_clkdev(clk, "dsihs1", "dsilink.1"); + + clk = clk_reg_prcmu_scalable("dsi0escclk", "tvclk", + PRCMU_DSI0ESCCLK, 0, CLK_SET_RATE_GATE); + clk_register_clkdev(clk, "dsilp0", "dsilink.0"); + clk_register_clkdev(clk, "dsilp0", "mcde"); + + clk = clk_reg_prcmu_scalable("dsi1escclk", "tvclk", + PRCMU_DSI1ESCCLK, 0, CLK_SET_RATE_GATE); + clk_register_clkdev(clk, "dsilp1", "dsilink.1"); + clk_register_clkdev(clk, "dsilp1", "mcde"); + + clk = clk_reg_prcmu_scalable("dsi2escclk", "tvclk", + PRCMU_DSI2ESCCLK, 0, CLK_SET_RATE_GATE); + clk_register_clkdev(clk, "dsilp2", "dsilink.2"); + clk_register_clkdev(clk, "dsilp2", "mcde"); + + /* + * FIXME: Add special handled PRCMU clocks here: + * 1. smp_twd, use PRCMU_ARMSS. + * 2. clk_arm, use PRCMU_ARMCLK. + * 3. clkout0yuv, use PRCMU as parent + need regulator + pinctrl. + * 4. ab9540_clkout1yuv, see clkout0yuv + */ + + /* PRCC P-clocks */ + clk = clk_reg_prcc_pclk("p1_pclk0", "per1clk", U8500_CLKRST1_BASE, + BIT(0), 0); + clk_register_clkdev(clk, "apb_pclk", "uart0"); + + clk = clk_reg_prcc_pclk("p1_pclk1", "per1clk", U8500_CLKRST1_BASE, + BIT(1), 0); + clk_register_clkdev(clk, "apb_pclk", "uart1"); + + clk = clk_reg_prcc_pclk("p1_pclk2", "per1clk", U8500_CLKRST1_BASE, + BIT(2), 0); + clk = clk_reg_prcc_pclk("p1_pclk3", "per1clk", U8500_CLKRST1_BASE, + BIT(3), 0); + clk = clk_reg_prcc_pclk("p1_pclk4", "per1clk", U8500_CLKRST1_BASE, + BIT(4), 0); + + clk = clk_reg_prcc_pclk("p1_pclk5", "per1clk", U8500_CLKRST1_BASE, + BIT(5), 0); + clk_register_clkdev(clk, "apb_pclk", "sdi0"); + + clk = clk_reg_prcc_pclk("p1_pclk6", "per1clk", U8500_CLKRST1_BASE, + BIT(6), 0); + + clk = clk_reg_prcc_pclk("p1_pclk7", "per1clk", U8500_CLKRST1_BASE, + BIT(7), 0); + clk_register_clkdev(clk, NULL, "spi3"); + + clk = clk_reg_prcc_pclk("p1_pclk8", "per1clk", U8500_CLKRST1_BASE, + BIT(8), 0); + + clk = clk_reg_prcc_pclk("p1_pclk9", "per1clk", U8500_CLKRST1_BASE, + BIT(9), 0); + clk_register_clkdev(clk, NULL, "gpio.0"); + clk_register_clkdev(clk, NULL, "gpio.1"); + clk_register_clkdev(clk, NULL, "gpioblock0"); + + clk = clk_reg_prcc_pclk("p1_pclk10", "per1clk", U8500_CLKRST1_BASE, + BIT(10), 0); + clk = clk_reg_prcc_pclk("p1_pclk11", "per1clk", U8500_CLKRST1_BASE, + BIT(11), 0); + + clk = clk_reg_prcc_pclk("p2_pclk0", "per2clk", U8500_CLKRST2_BASE, + BIT(0), 0); + + clk = clk_reg_prcc_pclk("p2_pclk1", "per2clk", U8500_CLKRST2_BASE, + BIT(1), 0); + clk_register_clkdev(clk, NULL, "spi2"); + + clk = clk_reg_prcc_pclk("p2_pclk2", "per2clk", U8500_CLKRST2_BASE, + BIT(2), 0); + clk_register_clkdev(clk, NULL, "spi1"); + + clk = clk_reg_prcc_pclk("p2_pclk3", "per2clk", U8500_CLKRST2_BASE, + BIT(3), 0); + clk_register_clkdev(clk, NULL, "pwl"); + + clk = clk_reg_prcc_pclk("p2_pclk4", "per2clk", U8500_CLKRST2_BASE, + BIT(4), 0); + clk_register_clkdev(clk, "apb_pclk", "sdi4"); + + clk = clk_reg_prcc_pclk("p2_pclk5", "per2clk", U8500_CLKRST2_BASE, + BIT(5), 0); + + clk = clk_reg_prcc_pclk("p2_pclk6", "per2clk", U8500_CLKRST2_BASE, + BIT(6), 0); + clk_register_clkdev(clk, "apb_pclk", "sdi1"); + + + clk = clk_reg_prcc_pclk("p2_pclk7", "per2clk", U8500_CLKRST2_BASE, + BIT(7), 0); + clk_register_clkdev(clk, "apb_pclk", "sdi3"); + + clk = clk_reg_prcc_pclk("p2_pclk8", "per2clk", U8500_CLKRST2_BASE, + BIT(8), 0); + clk_register_clkdev(clk, NULL, "spi0"); + + clk = clk_reg_prcc_pclk("p2_pclk9", "per2clk", U8500_CLKRST2_BASE, + BIT(9), 0); + clk_register_clkdev(clk, "hsir_hclk", "ste_hsi.0"); + + clk = clk_reg_prcc_pclk("p2_pclk10", "per2clk", U8500_CLKRST2_BASE, + BIT(10), 0); + clk_register_clkdev(clk, "hsit_hclk", "ste_hsi.0"); + + clk = clk_reg_prcc_pclk("p2_pclk11", "per2clk", U8500_CLKRST2_BASE, + BIT(11), 0); + clk_register_clkdev(clk, NULL, "gpio.6"); + clk_register_clkdev(clk, NULL, "gpio.7"); + clk_register_clkdev(clk, NULL, "gpioblock1"); + + clk = clk_reg_prcc_pclk("p2_pclk12", "per2clk", U8500_CLKRST2_BASE, + BIT(11), 0); + + clk = clk_reg_prcc_pclk("p3_pclk0", "per3clk", U8500_CLKRST3_BASE, + BIT(0), 0); + clk_register_clkdev(clk, NULL, "fsmc"); + + clk = clk_reg_prcc_pclk("p3_pclk1", "per3clk", U8500_CLKRST3_BASE, + BIT(1), 0); + clk = clk_reg_prcc_pclk("p3_pclk2", "per3clk", U8500_CLKRST3_BASE, + BIT(2), 0); + clk = clk_reg_prcc_pclk("p3_pclk3", "per3clk", U8500_CLKRST3_BASE, + BIT(3), 0); + + clk = clk_reg_prcc_pclk("p3_pclk4", "per3clk", U8500_CLKRST3_BASE, + BIT(4), 0); + clk_register_clkdev(clk, "apb_pclk", "sdi2"); + + clk = clk_reg_prcc_pclk("p3_pclk5", "per3clk", U8500_CLKRST3_BASE, + BIT(5), 0); + + clk = clk_reg_prcc_pclk("p3_pclk6", "per3clk", U8500_CLKRST3_BASE, + BIT(6), 0); + clk_register_clkdev(clk, "apb_pclk", "uart2"); + + clk = clk_reg_prcc_pclk("p3_pclk7", "per3clk", U8500_CLKRST3_BASE, + BIT(7), 0); + clk_register_clkdev(clk, "apb_pclk", "sdi5"); + + clk = clk_reg_prcc_pclk("p3_pclk8", "per3clk", U8500_CLKRST3_BASE, + BIT(8), 0); + clk_register_clkdev(clk, NULL, "gpio.2"); + clk_register_clkdev(clk, NULL, "gpio.3"); + clk_register_clkdev(clk, NULL, "gpio.4"); + clk_register_clkdev(clk, NULL, "gpio.5"); + clk_register_clkdev(clk, NULL, "gpioblock2"); + + clk = clk_reg_prcc_pclk("p5_pclk0", "per5clk", U8500_CLKRST5_BASE, + BIT(0), 0); + clk_register_clkdev(clk, "usb", "musb-ux500.0"); + + clk = clk_reg_prcc_pclk("p5_pclk1", "per5clk", U8500_CLKRST5_BASE, + BIT(1), 0); + clk_register_clkdev(clk, NULL, "gpio.8"); + clk_register_clkdev(clk, NULL, "gpioblock3"); + + clk = clk_reg_prcc_pclk("p6_pclk0", "per6clk", U8500_CLKRST6_BASE, + BIT(0), 0); + + clk = clk_reg_prcc_pclk("p6_pclk1", "per6clk", U8500_CLKRST6_BASE, + BIT(1), 0); + clk_register_clkdev(clk, NULL, "cryp0"); + clk_register_clkdev(clk, NULL, "cryp1"); + + clk = clk_reg_prcc_pclk("p6_pclk2", "per6clk", U8500_CLKRST6_BASE, + BIT(2), 0); + clk_register_clkdev(clk, NULL, "hash0"); + + clk = clk_reg_prcc_pclk("p6_pclk3", "per6clk", U8500_CLKRST6_BASE, + BIT(3), 0); + clk_register_clkdev(clk, NULL, "pka"); + + clk = clk_reg_prcc_pclk("p6_pclk4", "per6clk", U8500_CLKRST6_BASE, + BIT(4), 0); + clk_register_clkdev(clk, NULL, "hash1"); + + clk = clk_reg_prcc_pclk("p6_pclk5", "per6clk", U8500_CLKRST6_BASE, + BIT(5), 0); + clk_register_clkdev(clk, NULL, "cfgreg"); + + clk = clk_reg_prcc_pclk("p6_pclk6", "per6clk", U8500_CLKRST6_BASE, + BIT(6), 0); + clk = clk_reg_prcc_pclk("p6_pclk7", "per6clk", U8500_CLKRST6_BASE, + BIT(7), 0); + + /* PRCC K-clocks + * + * FIXME: Some drivers requires PERPIH[n| to be automatically enabled + * by enabling just the K-clock, even if it is not a valid parent to + * the K-clock. Until drivers get fixed we might need some kind of + * "parent muxed join". + */ + + /* Periph1 */ + clk = clk_reg_prcc_kclk("p1_uart0_kclk", "uartclk", + U8500_CLKRST1_BASE, BIT(0), CLK_SET_RATE_GATE); + clk_register_clkdev(clk, NULL, "uart0"); + + clk = clk_reg_prcc_kclk("p1_uart1_kclk", "uartclk", + U8500_CLKRST1_BASE, BIT(1), CLK_SET_RATE_GATE); + clk_register_clkdev(clk, NULL, "uart1"); + + clk = clk_reg_prcc_kclk("p1_i2c1_kclk", "i2cclk", + U8500_CLKRST1_BASE, BIT(2), CLK_SET_RATE_GATE); + clk = clk_reg_prcc_kclk("p1_msp0_kclk", "msp02clk", + U8500_CLKRST1_BASE, BIT(3), CLK_SET_RATE_GATE); + clk = clk_reg_prcc_kclk("p1_msp1_kclk", "msp1clk", + U8500_CLKRST1_BASE, BIT(4), CLK_SET_RATE_GATE); + + clk = clk_reg_prcc_kclk("p1_sdi0_kclk", "sdmmcclk", + U8500_CLKRST1_BASE, BIT(5), CLK_SET_RATE_GATE); + clk_register_clkdev(clk, NULL, "sdi0"); + + clk = clk_reg_prcc_kclk("p1_i2c2_kclk", "i2cclk", + U8500_CLKRST1_BASE, BIT(6), CLK_SET_RATE_GATE); + clk = clk_reg_prcc_kclk("p1_slimbus0_kclk", "slimclk", + U8500_CLKRST1_BASE, BIT(3), CLK_SET_RATE_GATE); + /* FIXME: Redefinition of BIT(3). */ + clk = clk_reg_prcc_kclk("p1_i2c4_kclk", "i2cclk", + U8500_CLKRST1_BASE, BIT(9), CLK_SET_RATE_GATE); + clk = clk_reg_prcc_kclk("p1_msp3_kclk", "msp1clk", + U8500_CLKRST1_BASE, BIT(10), CLK_SET_RATE_GATE); + + /* Periph2 */ + clk = clk_reg_prcc_kclk("p2_i2c3_kclk", "i2cclk", + U8500_CLKRST2_BASE, BIT(0), CLK_SET_RATE_GATE); + + clk = clk_reg_prcc_kclk("p2_sdi4_kclk", "sdmmcclk", + U8500_CLKRST2_BASE, BIT(2), CLK_SET_RATE_GATE); + clk_register_clkdev(clk, NULL, "sdi4"); + + clk = clk_reg_prcc_kclk("p2_msp2_kclk", "msp02clk", + U8500_CLKRST2_BASE, BIT(3), CLK_SET_RATE_GATE); + + clk = clk_reg_prcc_kclk("p2_sdi1_kclk", "sdmmcclk", + U8500_CLKRST2_BASE, BIT(4), CLK_SET_RATE_GATE); + clk_register_clkdev(clk, NULL, "sdi1"); + + clk = clk_reg_prcc_kclk("p2_sdi3_kclk", "sdmmcclk", + U8500_CLKRST2_BASE, BIT(5), CLK_SET_RATE_GATE); + clk_register_clkdev(clk, NULL, "sdi3"); + + /* Note that rate is received from parent. */ + clk = clk_reg_prcc_kclk("p2_ssirx_kclk", "hsirxclk", + U8500_CLKRST2_BASE, BIT(6), + CLK_SET_RATE_GATE|CLK_SET_RATE_PARENT); + clk = clk_reg_prcc_kclk("p2_ssitx_kclk", "hsitxclk", + U8500_CLKRST2_BASE, BIT(7), + CLK_SET_RATE_GATE|CLK_SET_RATE_PARENT); + + /* Periph3 */ + clk = clk_reg_prcc_kclk("p3_ssp0_kclk", "sspclk", + U8500_CLKRST3_BASE, BIT(1), CLK_SET_RATE_GATE); + clk = clk_reg_prcc_kclk("p3_ssp1_kclk", "sspclk", + U8500_CLKRST3_BASE, BIT(2), CLK_SET_RATE_GATE); + clk = clk_reg_prcc_kclk("p3_i2c0_kclk", "i2cclk", + U8500_CLKRST3_BASE, BIT(3), CLK_SET_RATE_GATE); + + clk = clk_reg_prcc_kclk("p3_sdi2_kclk", "sdmmcclk", + U8500_CLKRST3_BASE, BIT(4), CLK_SET_RATE_GATE); + clk_register_clkdev(clk, NULL, "sdi2"); + + clk = clk_reg_prcc_kclk("p3_ske_kclk", "rtc32k", + U8500_CLKRST3_BASE, BIT(5), CLK_SET_RATE_GATE); + + clk = clk_reg_prcc_kclk("p3_uart2_kclk", "uartclk", + U8500_CLKRST3_BASE, BIT(6), CLK_SET_RATE_GATE); + clk_register_clkdev(clk, NULL, "uart2"); + + clk = clk_reg_prcc_kclk("p3_sdi5_kclk", "sdmmcclk", + U8500_CLKRST3_BASE, BIT(7), CLK_SET_RATE_GATE); + clk_register_clkdev(clk, NULL, "sdi5"); + + /* Periph6 */ + clk = clk_reg_prcc_kclk("p3_rng_kclk", "rngclk", + U8500_CLKRST6_BASE, BIT(0), CLK_SET_RATE_GATE); + } -- cgit v1.2.3 From ebc96db7632f987e0b9bffcb782cf5cfb8afb0dd Mon Sep 17 00:00:00 2001 From: Ulf Hansson Date: Mon, 27 Aug 2012 15:45:53 +0200 Subject: ARM: ux500: Switch to use common clock framework Remove machine specific clock implementation and switch to use new common clock framework. Signed-off-by: Ulf Hansson Acked-by: Linus Walleij Signed-off-by: Mike Turquette --- arch/arm/mach-ux500/Kconfig | 1 + arch/arm/mach-ux500/Makefile | 2 +- arch/arm/mach-ux500/clock.c | 715 ------------------------------------------- arch/arm/mach-ux500/clock.h | 164 ---------- arch/arm/mach-ux500/cpu.c | 14 +- drivers/clk/Makefile | 1 + 6 files changed, 11 insertions(+), 886 deletions(-) delete mode 100644 arch/arm/mach-ux500/clock.c delete mode 100644 arch/arm/mach-ux500/clock.h (limited to 'drivers') diff --git a/arch/arm/mach-ux500/Kconfig b/arch/arm/mach-ux500/Kconfig index c013bbf79cac..2d76e4f9c97e 100644 --- a/arch/arm/mach-ux500/Kconfig +++ b/arch/arm/mach-ux500/Kconfig @@ -11,6 +11,7 @@ config UX500_SOC_COMMON select CACHE_L2X0 select PINCTRL select PINCTRL_NOMADIK + select COMMON_CLK config UX500_SOC_DB8500 bool diff --git a/arch/arm/mach-ux500/Makefile b/arch/arm/mach-ux500/Makefile index 026086ff9e6c..5691ef679d01 100644 --- a/arch/arm/mach-ux500/Makefile +++ b/arch/arm/mach-ux500/Makefile @@ -2,7 +2,7 @@ # Makefile for the linux kernel, U8500 machine. # -obj-y := clock.o cpu.o devices.o devices-common.o \ +obj-y := cpu.o devices.o devices-common.o \ id.o usb.o timer.o obj-$(CONFIG_CPU_IDLE) += cpuidle.o obj-$(CONFIG_CACHE_L2X0) += cache-l2x0.o diff --git a/arch/arm/mach-ux500/clock.c b/arch/arm/mach-ux500/clock.c deleted file mode 100644 index 8d73b066a18d..000000000000 --- a/arch/arm/mach-ux500/clock.c +++ /dev/null @@ -1,715 +0,0 @@ -/* - * Copyright (C) 2009 ST-Ericsson - * Copyright (C) 2009 STMicroelectronics - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include "clock.h" - -#ifdef CONFIG_DEBUG_FS -#include -#include /* for copy_from_user */ -static LIST_HEAD(clk_list); -#endif - -#define PRCC_PCKEN 0x00 -#define PRCC_PCKDIS 0x04 -#define PRCC_KCKEN 0x08 -#define PRCC_KCKDIS 0x0C - -#define PRCM_YYCLKEN0_MGT_SET 0x510 -#define PRCM_YYCLKEN1_MGT_SET 0x514 -#define PRCM_YYCLKEN0_MGT_CLR 0x518 -#define PRCM_YYCLKEN1_MGT_CLR 0x51C -#define PRCM_YYCLKEN0_MGT_VAL 0x520 -#define PRCM_YYCLKEN1_MGT_VAL 0x524 - -#define PRCM_SVAMMDSPCLK_MGT 0x008 -#define PRCM_SIAMMDSPCLK_MGT 0x00C -#define PRCM_SGACLK_MGT 0x014 -#define PRCM_UARTCLK_MGT 0x018 -#define PRCM_MSP02CLK_MGT 0x01C -#define PRCM_MSP1CLK_MGT 0x288 -#define PRCM_I2CCLK_MGT 0x020 -#define PRCM_SDMMCCLK_MGT 0x024 -#define PRCM_SLIMCLK_MGT 0x028 -#define PRCM_PER1CLK_MGT 0x02C -#define PRCM_PER2CLK_MGT 0x030 -#define PRCM_PER3CLK_MGT 0x034 -#define PRCM_PER5CLK_MGT 0x038 -#define PRCM_PER6CLK_MGT 0x03C -#define PRCM_PER7CLK_MGT 0x040 -#define PRCM_LCDCLK_MGT 0x044 -#define PRCM_BMLCLK_MGT 0x04C -#define PRCM_HSITXCLK_MGT 0x050 -#define PRCM_HSIRXCLK_MGT 0x054 -#define PRCM_HDMICLK_MGT 0x058 -#define PRCM_APEATCLK_MGT 0x05C -#define PRCM_APETRACECLK_MGT 0x060 -#define PRCM_MCDECLK_MGT 0x064 -#define PRCM_IPI2CCLK_MGT 0x068 -#define PRCM_DSIALTCLK_MGT 0x06C -#define PRCM_DMACLK_MGT 0x074 -#define PRCM_B2R2CLK_MGT 0x078 -#define PRCM_TVCLK_MGT 0x07C -#define PRCM_TCR 0x1C8 -#define PRCM_TCR_STOPPED (1 << 16) -#define PRCM_TCR_DOZE_MODE (1 << 17) -#define PRCM_UNIPROCLK_MGT 0x278 -#define PRCM_SSPCLK_MGT 0x280 -#define PRCM_RNGCLK_MGT 0x284 -#define PRCM_UICCCLK_MGT 0x27C - -#define PRCM_MGT_ENABLE (1 << 8) - -static DEFINE_SPINLOCK(clocks_lock); - -static void __clk_enable(struct clk *clk) -{ - if (clk->enabled++ == 0) { - if (clk->parent_cluster) - __clk_enable(clk->parent_cluster); - - if (clk->parent_periph) - __clk_enable(clk->parent_periph); - - if (clk->ops && clk->ops->enable) - clk->ops->enable(clk); - } -} - -int clk_enable(struct clk *clk) -{ - unsigned long flags; - - spin_lock_irqsave(&clocks_lock, flags); - __clk_enable(clk); - spin_unlock_irqrestore(&clocks_lock, flags); - - return 0; -} -EXPORT_SYMBOL(clk_enable); - -static void __clk_disable(struct clk *clk) -{ - if (--clk->enabled == 0) { - if (clk->ops && clk->ops->disable) - clk->ops->disable(clk); - - if (clk->parent_periph) - __clk_disable(clk->parent_periph); - - if (clk->parent_cluster) - __clk_disable(clk->parent_cluster); - } -} - -void clk_disable(struct clk *clk) -{ - unsigned long flags; - - WARN_ON(!clk->enabled); - - spin_lock_irqsave(&clocks_lock, flags); - __clk_disable(clk); - spin_unlock_irqrestore(&clocks_lock, flags); -} -EXPORT_SYMBOL(clk_disable); - -/* - * The MTU has a separate, rather complex muxing setup - * with alternative parents (peripheral cluster or - * ULP or fixed 32768 Hz) depending on settings - */ -static unsigned long clk_mtu_get_rate(struct clk *clk) -{ - void __iomem *addr; - u32 tcr; - int mtu = (int) clk->data; - /* - * One of these is selected eventually - * TODO: Replace the constant with a reference - * to the ULP source once this is modeled. - */ - unsigned long clk32k = 32768; - unsigned long mturate; - unsigned long retclk; - - if (cpu_is_u8500_family()) - addr = __io_address(U8500_PRCMU_BASE); - else - ux500_unknown_soc(); - - /* - * On a startup, always conifgure the TCR to the doze mode; - * bootloaders do it for us. Do this in the kernel too. - */ - writel(PRCM_TCR_DOZE_MODE, addr + PRCM_TCR); - - tcr = readl(addr + PRCM_TCR); - - /* Get the rate from the parent as a default */ - if (clk->parent_periph) - mturate = clk_get_rate(clk->parent_periph); - else if (clk->parent_cluster) - mturate = clk_get_rate(clk->parent_cluster); - else - /* We need to be connected SOMEWHERE */ - BUG(); - - /* Return the clock selected for this MTU */ - if (tcr & (1 << mtu)) - retclk = clk32k; - else - retclk = mturate; - - pr_info("MTU%d clock rate: %lu Hz\n", mtu, retclk); - return retclk; -} - -unsigned long clk_get_rate(struct clk *clk) -{ - unsigned long rate; - - /* - * If there is a custom getrate callback for this clock, - * it will take precedence. - */ - if (clk->get_rate) - return clk->get_rate(clk); - - if (clk->ops && clk->ops->get_rate) - return clk->ops->get_rate(clk); - - rate = clk->rate; - if (!rate) { - if (clk->parent_periph) - rate = clk_get_rate(clk->parent_periph); - else if (clk->parent_cluster) - rate = clk_get_rate(clk->parent_cluster); - } - - return rate; -} -EXPORT_SYMBOL(clk_get_rate); - -long clk_round_rate(struct clk *clk, unsigned long rate) -{ - /*TODO*/ - return rate; -} -EXPORT_SYMBOL(clk_round_rate); - -int clk_set_rate(struct clk *clk, unsigned long rate) -{ - clk->rate = rate; - return 0; -} -EXPORT_SYMBOL(clk_set_rate); - -int clk_set_parent(struct clk *clk, struct clk *parent) -{ - /*TODO*/ - return -ENOSYS; -} -EXPORT_SYMBOL(clk_set_parent); - -static void clk_prcmu_enable(struct clk *clk) -{ - void __iomem *cg_set_reg = __io_address(U8500_PRCMU_BASE) - + PRCM_YYCLKEN0_MGT_SET + clk->prcmu_cg_off; - - writel(1 << clk->prcmu_cg_bit, cg_set_reg); -} - -static void clk_prcmu_disable(struct clk *clk) -{ - void __iomem *cg_clr_reg = __io_address(U8500_PRCMU_BASE) - + PRCM_YYCLKEN0_MGT_CLR + clk->prcmu_cg_off; - - writel(1 << clk->prcmu_cg_bit, cg_clr_reg); -} - -static struct clkops clk_prcmu_ops = { - .enable = clk_prcmu_enable, - .disable = clk_prcmu_disable, -}; - -static unsigned int clkrst_base[] = { - [1] = U8500_CLKRST1_BASE, - [2] = U8500_CLKRST2_BASE, - [3] = U8500_CLKRST3_BASE, - [5] = U8500_CLKRST5_BASE, - [6] = U8500_CLKRST6_BASE, -}; - -static void clk_prcc_enable(struct clk *clk) -{ - void __iomem *addr = __io_address(clkrst_base[clk->cluster]); - - if (clk->prcc_kernel != -1) - writel(1 << clk->prcc_kernel, addr + PRCC_KCKEN); - - if (clk->prcc_bus != -1) - writel(1 << clk->prcc_bus, addr + PRCC_PCKEN); -} - -static void clk_prcc_disable(struct clk *clk) -{ - void __iomem *addr = __io_address(clkrst_base[clk->cluster]); - - if (clk->prcc_bus != -1) - writel(1 << clk->prcc_bus, addr + PRCC_PCKDIS); - - if (clk->prcc_kernel != -1) - writel(1 << clk->prcc_kernel, addr + PRCC_KCKDIS); -} - -static struct clkops clk_prcc_ops = { - .enable = clk_prcc_enable, - .disable = clk_prcc_disable, -}; - -static struct clk clk_32khz = { - .name = "clk_32khz", - .rate = 32000, -}; - -/* - * PRCMU level clock gating - */ - -/* Bank 0 */ -static DEFINE_PRCMU_CLK(svaclk, 0x0, 2, SVAMMDSPCLK); -static DEFINE_PRCMU_CLK(siaclk, 0x0, 3, SIAMMDSPCLK); -static DEFINE_PRCMU_CLK(sgaclk, 0x0, 4, SGACLK); -static DEFINE_PRCMU_CLK_RATE(uartclk, 0x0, 5, UARTCLK, 38400000); -static DEFINE_PRCMU_CLK(msp02clk, 0x0, 6, MSP02CLK); -static DEFINE_PRCMU_CLK(msp1clk, 0x0, 7, MSP1CLK); /* v1 */ -static DEFINE_PRCMU_CLK_RATE(i2cclk, 0x0, 8, I2CCLK, 48000000); -static DEFINE_PRCMU_CLK_RATE(sdmmcclk, 0x0, 9, SDMMCCLK, 100000000); -static DEFINE_PRCMU_CLK(slimclk, 0x0, 10, SLIMCLK); -static DEFINE_PRCMU_CLK(per1clk, 0x0, 11, PER1CLK); -static DEFINE_PRCMU_CLK(per2clk, 0x0, 12, PER2CLK); -static DEFINE_PRCMU_CLK(per3clk, 0x0, 13, PER3CLK); -static DEFINE_PRCMU_CLK(per5clk, 0x0, 14, PER5CLK); -static DEFINE_PRCMU_CLK_RATE(per6clk, 0x0, 15, PER6CLK, 133330000); -static DEFINE_PRCMU_CLK(lcdclk, 0x0, 17, LCDCLK); -static DEFINE_PRCMU_CLK(bmlclk, 0x0, 18, BMLCLK); -static DEFINE_PRCMU_CLK(hsitxclk, 0x0, 19, HSITXCLK); -static DEFINE_PRCMU_CLK(hsirxclk, 0x0, 20, HSIRXCLK); -static DEFINE_PRCMU_CLK(hdmiclk, 0x0, 21, HDMICLK); -static DEFINE_PRCMU_CLK(apeatclk, 0x0, 22, APEATCLK); -static DEFINE_PRCMU_CLK(apetraceclk, 0x0, 23, APETRACECLK); -static DEFINE_PRCMU_CLK(mcdeclk, 0x0, 24, MCDECLK); -static DEFINE_PRCMU_CLK(ipi2clk, 0x0, 25, IPI2CCLK); -static DEFINE_PRCMU_CLK(dsialtclk, 0x0, 26, DSIALTCLK); /* v1 */ -static DEFINE_PRCMU_CLK(dmaclk, 0x0, 27, DMACLK); -static DEFINE_PRCMU_CLK(b2r2clk, 0x0, 28, B2R2CLK); -static DEFINE_PRCMU_CLK(tvclk, 0x0, 29, TVCLK); -static DEFINE_PRCMU_CLK(uniproclk, 0x0, 30, UNIPROCLK); /* v1 */ -static DEFINE_PRCMU_CLK_RATE(sspclk, 0x0, 31, SSPCLK, 48000000); /* v1 */ - -/* Bank 1 */ -static DEFINE_PRCMU_CLK(rngclk, 0x4, 0, RNGCLK); /* v1 */ -static DEFINE_PRCMU_CLK(uiccclk, 0x4, 1, UICCCLK); /* v1 */ - -/* - * PRCC level clock gating - * Format: per#, clk, PCKEN bit, KCKEN bit, parent - */ - -/* Peripheral Cluster #1 */ -static DEFINE_PRCC_CLK(1, msp3, 11, 10, &clk_msp1clk); -static DEFINE_PRCC_CLK(1, i2c4, 10, 9, &clk_i2cclk); -static DEFINE_PRCC_CLK(1, gpio0, 9, -1, NULL); -static DEFINE_PRCC_CLK(1, slimbus0, 8, 8, &clk_slimclk); -static DEFINE_PRCC_CLK(1, spi3, 7, -1, NULL); -static DEFINE_PRCC_CLK(1, i2c2, 6, 6, &clk_i2cclk); -static DEFINE_PRCC_CLK(1, sdi0, 5, 5, &clk_sdmmcclk); -static DEFINE_PRCC_CLK(1, msp1, 4, 4, &clk_msp1clk); -static DEFINE_PRCC_CLK(1, msp0, 3, 3, &clk_msp02clk); -static DEFINE_PRCC_CLK(1, i2c1, 2, 2, &clk_i2cclk); -static DEFINE_PRCC_CLK(1, uart1, 1, 1, &clk_uartclk); -static DEFINE_PRCC_CLK(1, uart0, 0, 0, &clk_uartclk); - -/* Peripheral Cluster #2 */ -static DEFINE_PRCC_CLK(2, gpio1, 11, -1, NULL); -static DEFINE_PRCC_CLK(2, ssitx, 10, 7, NULL); -static DEFINE_PRCC_CLK(2, ssirx, 9, 6, NULL); -static DEFINE_PRCC_CLK(2, spi0, 8, -1, NULL); -static DEFINE_PRCC_CLK(2, sdi3, 7, 5, &clk_sdmmcclk); -static DEFINE_PRCC_CLK(2, sdi1, 6, 4, &clk_sdmmcclk); -static DEFINE_PRCC_CLK(2, msp2, 5, 3, &clk_msp02clk); -static DEFINE_PRCC_CLK(2, sdi4, 4, 2, &clk_sdmmcclk); -static DEFINE_PRCC_CLK(2, pwl, 3, 1, NULL); -static DEFINE_PRCC_CLK(2, spi1, 2, -1, NULL); -static DEFINE_PRCC_CLK(2, spi2, 1, -1, NULL); -static DEFINE_PRCC_CLK(2, i2c3, 0, 0, &clk_i2cclk); - -/* Peripheral Cluster #3 */ -static DEFINE_PRCC_CLK(3, gpio2, 8, -1, NULL); -static DEFINE_PRCC_CLK(3, sdi5, 7, 7, &clk_sdmmcclk); -static DEFINE_PRCC_CLK(3, uart2, 6, 6, &clk_uartclk); -static DEFINE_PRCC_CLK(3, ske, 5, 5, &clk_32khz); -static DEFINE_PRCC_CLK(3, sdi2, 4, 4, &clk_sdmmcclk); -static DEFINE_PRCC_CLK(3, i2c0, 3, 3, &clk_i2cclk); -static DEFINE_PRCC_CLK(3, ssp1, 2, 2, &clk_sspclk); -static DEFINE_PRCC_CLK(3, ssp0, 1, 1, &clk_sspclk); -static DEFINE_PRCC_CLK(3, fsmc, 0, -1, NULL); - -/* Peripheral Cluster #4 is in the always on domain */ - -/* Peripheral Cluster #5 */ -static DEFINE_PRCC_CLK(5, gpio3, 1, -1, NULL); -static DEFINE_PRCC_CLK(5, usb, 0, 0, NULL); - -/* Peripheral Cluster #6 */ - -/* MTU ID in data */ -static DEFINE_PRCC_CLK_CUSTOM(6, mtu1, 9, -1, NULL, clk_mtu_get_rate, 1); -static DEFINE_PRCC_CLK_CUSTOM(6, mtu0, 8, -1, NULL, clk_mtu_get_rate, 0); -static DEFINE_PRCC_CLK(6, cfgreg, 7, 7, NULL); -static DEFINE_PRCC_CLK(6, hash1, 6, -1, NULL); -static DEFINE_PRCC_CLK(6, unipro, 5, 1, &clk_uniproclk); -static DEFINE_PRCC_CLK(6, pka, 4, -1, NULL); -static DEFINE_PRCC_CLK(6, hash0, 3, -1, NULL); -static DEFINE_PRCC_CLK(6, cryp0, 2, -1, NULL); -static DEFINE_PRCC_CLK(6, cryp1, 1, -1, NULL); -static DEFINE_PRCC_CLK(6, rng, 0, 0, &clk_rngclk); - -static struct clk clk_dummy_apb_pclk = { - .name = "apb_pclk", -}; - -static struct clk_lookup u8500_clks[] = { - CLK(dummy_apb_pclk, NULL, "apb_pclk"), - - /* Peripheral Cluster #1 */ - CLK(gpio0, "gpio.0", NULL), - CLK(gpio0, "gpio.1", NULL), - CLK(slimbus0, "slimbus0", NULL), - CLK(i2c2, "nmk-i2c.2", NULL), - CLK(sdi0, "sdi0", NULL), - CLK(msp0, "ux500-msp-i2s.0", NULL), - CLK(i2c1, "nmk-i2c.1", NULL), - CLK(uart1, "uart1", NULL), - CLK(uart0, "uart0", NULL), - - /* Peripheral Cluster #3 */ - CLK(gpio2, "gpio.2", NULL), - CLK(gpio2, "gpio.3", NULL), - CLK(gpio2, "gpio.4", NULL), - CLK(gpio2, "gpio.5", NULL), - CLK(sdi5, "sdi5", NULL), - CLK(uart2, "uart2", NULL), - CLK(ske, "ske", NULL), - CLK(ske, "nmk-ske-keypad", NULL), - CLK(sdi2, "sdi2", NULL), - CLK(i2c0, "nmk-i2c.0", NULL), - CLK(fsmc, "fsmc", NULL), - - /* Peripheral Cluster #5 */ - CLK(gpio3, "gpio.8", NULL), - - /* Peripheral Cluster #6 */ - CLK(hash1, "hash1", NULL), - CLK(pka, "pka", NULL), - CLK(hash0, "hash0", NULL), - CLK(cryp0, "cryp0", NULL), - CLK(cryp1, "cryp1", NULL), - - /* PRCMU level clock gating */ - - /* Bank 0 */ - CLK(svaclk, "sva", NULL), - CLK(siaclk, "sia", NULL), - CLK(sgaclk, "sga", NULL), - CLK(slimclk, "slim", NULL), - CLK(lcdclk, "lcd", NULL), - CLK(bmlclk, "bml", NULL), - CLK(hsitxclk, "stm-hsi.0", NULL), - CLK(hsirxclk, "stm-hsi.1", NULL), - CLK(hdmiclk, "hdmi", NULL), - CLK(apeatclk, "apeat", NULL), - CLK(apetraceclk, "apetrace", NULL), - CLK(mcdeclk, "mcde", NULL), - CLK(ipi2clk, "ipi2", NULL), - CLK(dmaclk, "dma40.0", NULL), - CLK(b2r2clk, "b2r2", NULL), - CLK(tvclk, "tv", NULL), - - /* Peripheral Cluster #1 */ - CLK(i2c4, "nmk-i2c.4", NULL), - CLK(spi3, "spi3", NULL), - CLK(msp1, "ux500-msp-i2s.1", NULL), - CLK(msp3, "ux500-msp-i2s.3", NULL), - - /* Peripheral Cluster #2 */ - CLK(gpio1, "gpio.6", NULL), - CLK(gpio1, "gpio.7", NULL), - CLK(ssitx, "ssitx", NULL), - CLK(ssirx, "ssirx", NULL), - CLK(spi0, "spi0", NULL), - CLK(sdi3, "sdi3", NULL), - CLK(sdi1, "sdi1", NULL), - CLK(msp2, "ux500-msp-i2s.2", NULL), - CLK(sdi4, "sdi4", NULL), - CLK(pwl, "pwl", NULL), - CLK(spi1, "spi1", NULL), - CLK(spi2, "spi2", NULL), - CLK(i2c3, "nmk-i2c.3", NULL), - - /* Peripheral Cluster #3 */ - CLK(ssp1, "ssp1", NULL), - CLK(ssp0, "ssp0", NULL), - - /* Peripheral Cluster #5 */ - CLK(usb, "musb-ux500.0", "usb"), - - /* Peripheral Cluster #6 */ - CLK(mtu1, "mtu1", NULL), - CLK(mtu0, "mtu0", NULL), - CLK(cfgreg, "cfgreg", NULL), - CLK(hash1, "hash1", NULL), - CLK(unipro, "unipro", NULL), - CLK(rng, "rng", NULL), - - /* PRCMU level clock gating */ - - /* Bank 0 */ - CLK(uniproclk, "uniproclk", NULL), - CLK(dsialtclk, "dsialt", NULL), - - /* Bank 1 */ - CLK(rngclk, "rng", NULL), - CLK(uiccclk, "uicc", NULL), -}; - -#ifdef CONFIG_DEBUG_FS -/* - * debugfs support to trace clock tree hierarchy and attributes with - * powerdebug - */ -static struct dentry *clk_debugfs_root; - -void __init clk_debugfs_add_table(struct clk_lookup *cl, size_t num) -{ - while (num--) { - /* Check that the clock has not been already registered */ - if (!(cl->clk->list.prev != cl->clk->list.next)) - list_add_tail(&cl->clk->list, &clk_list); - - cl++; - } -} - -static ssize_t usecount_dbg_read(struct file *file, char __user *buf, - size_t size, loff_t *off) -{ - struct clk *clk = file->f_dentry->d_inode->i_private; - char cusecount[128]; - unsigned int len; - - len = sprintf(cusecount, "%u\n", clk->enabled); - return simple_read_from_buffer(buf, size, off, cusecount, len); -} - -static ssize_t rate_dbg_read(struct file *file, char __user *buf, - size_t size, loff_t *off) -{ - struct clk *clk = file->f_dentry->d_inode->i_private; - char crate[128]; - unsigned int rate; - unsigned int len; - - rate = clk_get_rate(clk); - len = sprintf(crate, "%u\n", rate); - return simple_read_from_buffer(buf, size, off, crate, len); -} - -static const struct file_operations usecount_fops = { - .read = usecount_dbg_read, -}; - -static const struct file_operations set_rate_fops = { - .read = rate_dbg_read, -}; - -static struct dentry *clk_debugfs_register_dir(struct clk *c, - struct dentry *p_dentry) -{ - struct dentry *d, *clk_d; - const char *p = c->name; - - if (!p) - p = "BUG"; - - clk_d = debugfs_create_dir(p, p_dentry); - if (!clk_d) - return NULL; - - d = debugfs_create_file("usecount", S_IRUGO, - clk_d, c, &usecount_fops); - if (!d) - goto err_out; - d = debugfs_create_file("rate", S_IRUGO, - clk_d, c, &set_rate_fops); - if (!d) - goto err_out; - /* - * TODO : not currently available in ux500 - * d = debugfs_create_x32("flags", S_IRUGO, clk_d, (u32 *)&c->flags); - * if (!d) - * goto err_out; - */ - - return clk_d; - -err_out: - debugfs_remove_recursive(clk_d); - return NULL; -} - -static int clk_debugfs_register_one(struct clk *c) -{ - struct clk *pa = c->parent_periph; - struct clk *bpa = c->parent_cluster; - - if (!(bpa && !pa)) { - c->dent = clk_debugfs_register_dir(c, - pa ? pa->dent : clk_debugfs_root); - if (!c->dent) - return -ENOMEM; - } - - if (bpa) { - c->dent_bus = clk_debugfs_register_dir(c, - bpa->dent_bus ? bpa->dent_bus : bpa->dent); - if ((!c->dent_bus) && (c->dent)) { - debugfs_remove_recursive(c->dent); - c->dent = NULL; - return -ENOMEM; - } - } - return 0; -} - -static int clk_debugfs_register(struct clk *c) -{ - int err; - struct clk *pa = c->parent_periph; - struct clk *bpa = c->parent_cluster; - - if (pa && (!pa->dent && !pa->dent_bus)) { - err = clk_debugfs_register(pa); - if (err) - return err; - } - - if (bpa && (!bpa->dent && !bpa->dent_bus)) { - err = clk_debugfs_register(bpa); - if (err) - return err; - } - - if ((!c->dent) && (!c->dent_bus)) { - err = clk_debugfs_register_one(c); - if (err) - return err; - } - return 0; -} - -int __init clk_debugfs_init(void) -{ - struct clk *c; - struct dentry *d; - int err; - - d = debugfs_create_dir("clock", NULL); - if (!d) - return -ENOMEM; - clk_debugfs_root = d; - - list_for_each_entry(c, &clk_list, list) { - err = clk_debugfs_register(c); - if (err) - goto err_out; - } - return 0; -err_out: - debugfs_remove_recursive(clk_debugfs_root); - return err; -} - -#endif /* defined(CONFIG_DEBUG_FS) */ - -unsigned long clk_smp_twd_rate = 500000000; - -unsigned long clk_smp_twd_get_rate(struct clk *clk) -{ - return clk_smp_twd_rate; -} - -static struct clk clk_smp_twd = { - .get_rate = clk_smp_twd_get_rate, - .name = "smp_twd", -}; - -static struct clk_lookup clk_smp_twd_lookup = { - .dev_id = "smp_twd", - .clk = &clk_smp_twd, -}; - -#ifdef CONFIG_CPU_FREQ - -static int clk_twd_cpufreq_transition(struct notifier_block *nb, - unsigned long state, void *data) -{ - struct cpufreq_freqs *f = data; - - if (state == CPUFREQ_PRECHANGE) { - /* Save frequency in simple Hz */ - clk_smp_twd_rate = (f->new * 1000) / 2; - } - - return NOTIFY_OK; -} - -static struct notifier_block clk_twd_cpufreq_nb = { - .notifier_call = clk_twd_cpufreq_transition, -}; - -int clk_init_smp_twd_cpufreq(void) -{ - return cpufreq_register_notifier(&clk_twd_cpufreq_nb, - CPUFREQ_TRANSITION_NOTIFIER); -} - -#endif - -int __init clk_init(void) -{ - clkdev_add_table(u8500_clks, ARRAY_SIZE(u8500_clks)); - clkdev_add(&clk_smp_twd_lookup); - -#ifdef CONFIG_DEBUG_FS - clk_debugfs_add_table(u8500_clks, ARRAY_SIZE(u8500_clks)); -#endif - return 0; -} diff --git a/arch/arm/mach-ux500/clock.h b/arch/arm/mach-ux500/clock.h deleted file mode 100644 index 65d27a13f46d..000000000000 --- a/arch/arm/mach-ux500/clock.h +++ /dev/null @@ -1,164 +0,0 @@ -/* - * Copyright (C) 2010 ST-Ericsson - * Copyright (C) 2009 STMicroelectronics - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ - -/** - * struct clkops - ux500 clock operations - * @enable: function to enable the clock - * @disable: function to disable the clock - * @get_rate: function to get the current clock rate - * - * This structure contains function pointers to functions that will be used to - * control the clock. All of these functions are optional. If get_rate is - * NULL, the rate in the struct clk will be used. - */ -struct clkops { - void (*enable) (struct clk *); - void (*disable) (struct clk *); - unsigned long (*get_rate) (struct clk *); - int (*set_parent)(struct clk *, struct clk *); -}; - -/** - * struct clk - ux500 clock structure - * @ops: pointer to clkops struct used to control this clock - * @name: name, for debugging - * @enabled: refcount. positive if enabled, zero if disabled - * @get_rate: custom callback for getting the clock rate - * @data: custom per-clock data for example for the get_rate - * callback - * @rate: fixed rate for clocks which don't implement - * ops->getrate - * @prcmu_cg_off: address offset of the combined enable/disable register - * (used on u8500v1) - * @prcmu_cg_bit: bit in the combined enable/disable register (used on - * u8500v1) - * @prcmu_cg_mgt: address of the enable/disable register (used on - * u8500ed) - * @cluster: peripheral cluster number - * @prcc_bus: bit for the bus clock in the peripheral's CLKRST - * @prcc_kernel: bit for the kernel clock in the peripheral's CLKRST. - * -1 if no kernel clock exists. - * @parent_cluster: pointer to parent's cluster clk struct - * @parent_periph: pointer to parent's peripheral clk struct - * - * Peripherals are organised into clusters, and each cluster has an associated - * bus clock. Some peripherals also have a parent peripheral clock. - * - * In order to enable a clock for a peripheral, we need to enable: - * (1) the parent cluster (bus) clock at the PRCMU level - * (2) the parent peripheral clock (if any) at the PRCMU level - * (3) the peripheral's bus & kernel clock at the PRCC level - * - * (1) and (2) are handled by defining clk structs (DEFINE_PRCMU_CLK) for each - * of the cluster and peripheral clocks, and hooking these as the parents of - * the individual peripheral clocks. - * - * (3) is handled by specifying the bits in the PRCC control registers required - * to enable these clocks and modifying them in the ->enable and - * ->disable callbacks of the peripheral clocks (DEFINE_PRCC_CLK). - * - * This structure describes both the PRCMU-level clocks and PRCC-level clocks. - * The prcmu_* fields are only used for the PRCMU clocks, and the cluster, - * prcc, and parent pointers are only used for the PRCC-level clocks. - */ -struct clk { - const struct clkops *ops; - const char *name; - unsigned int enabled; - unsigned long (*get_rate)(struct clk *); - void *data; - - unsigned long rate; - struct list_head list; - - /* These three are only for PRCMU clks */ - - unsigned int prcmu_cg_off; - unsigned int prcmu_cg_bit; - unsigned int prcmu_cg_mgt; - - /* The rest are only for PRCC clks */ - - int cluster; - unsigned int prcc_bus; - unsigned int prcc_kernel; - - struct clk *parent_cluster; - struct clk *parent_periph; -#if defined(CONFIG_DEBUG_FS) - struct dentry *dent; /* For visible tree hierarchy */ - struct dentry *dent_bus; /* For visible tree hierarchy */ -#endif -}; - -#define DEFINE_PRCMU_CLK(_name, _cg_off, _cg_bit, _reg) \ -struct clk clk_##_name = { \ - .name = #_name, \ - .ops = &clk_prcmu_ops, \ - .prcmu_cg_off = _cg_off, \ - .prcmu_cg_bit = _cg_bit, \ - .prcmu_cg_mgt = PRCM_##_reg##_MGT \ - } - -#define DEFINE_PRCMU_CLK_RATE(_name, _cg_off, _cg_bit, _reg, _rate) \ -struct clk clk_##_name = { \ - .name = #_name, \ - .ops = &clk_prcmu_ops, \ - .prcmu_cg_off = _cg_off, \ - .prcmu_cg_bit = _cg_bit, \ - .rate = _rate, \ - .prcmu_cg_mgt = PRCM_##_reg##_MGT \ - } - -#define DEFINE_PRCC_CLK(_pclust, _name, _bus_en, _kernel_en, _kernclk) \ -struct clk clk_##_name = { \ - .name = #_name, \ - .ops = &clk_prcc_ops, \ - .cluster = _pclust, \ - .prcc_bus = _bus_en, \ - .prcc_kernel = _kernel_en, \ - .parent_cluster = &clk_per##_pclust##clk, \ - .parent_periph = _kernclk \ - } - -#define DEFINE_PRCC_CLK_CUSTOM(_pclust, _name, _bus_en, _kernel_en, _kernclk, _callback, _data) \ -struct clk clk_##_name = { \ - .name = #_name, \ - .ops = &clk_prcc_ops, \ - .cluster = _pclust, \ - .prcc_bus = _bus_en, \ - .prcc_kernel = _kernel_en, \ - .parent_cluster = &clk_per##_pclust##clk, \ - .parent_periph = _kernclk, \ - .get_rate = _callback, \ - .data = (void *) _data \ - } - - -#define CLK(_clk, _devname, _conname) \ - { \ - .clk = &clk_##_clk, \ - .dev_id = _devname, \ - .con_id = _conname, \ - } - -int __init clk_db8500_ed_fixup(void); -int __init clk_init(void); - -#ifdef CONFIG_DEBUG_FS -int clk_debugfs_init(void); -#else -static inline int clk_debugfs_init(void) { return 0; } -#endif - -#ifdef CONFIG_CPU_FREQ -int clk_init_smp_twd_cpufreq(void); -#else -static inline int clk_init_smp_twd_cpufreq(void) { return 0; } -#endif diff --git a/arch/arm/mach-ux500/cpu.c b/arch/arm/mach-ux500/cpu.c index e2360e7c770d..17a78ec516ff 100644 --- a/arch/arm/mach-ux500/cpu.c +++ b/arch/arm/mach-ux500/cpu.c @@ -8,7 +8,6 @@ #include #include -#include #include #include #include @@ -17,6 +16,7 @@ #include #include #include +#include #include #include @@ -25,8 +25,6 @@ #include #include -#include "clock.h" - void __iomem *_PRCMU_BASE; /* @@ -70,13 +68,17 @@ void __init ux500_init_irq(void) */ if (cpu_is_u8500_family()) db8500_prcmu_early_init(); - clk_init(); + + if (cpu_is_u8500_family()) + u8500_clk_init(); + else if (cpu_is_u9540()) + u9540_clk_init(); + else if (cpu_is_u8540()) + u8540_clk_init(); } void __init ux500_init_late(void) { - clk_debugfs_init(); - clk_init_smp_twd_cpufreq(); } static const char * __init ux500_get_machine(void) diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile index 649265152bca..d561825a87fc 100644 --- a/drivers/clk/Makefile +++ b/drivers/clk/Makefile @@ -15,6 +15,7 @@ ifeq ($(CONFIG_COMMON_CLK), y) obj-$(CONFIG_ARCH_MMP) += mmp/ endif obj-$(CONFIG_MACH_LOONGSON1) += clk-ls1x.o +obj-$(CONFIG_ARCH_U8500) += ux500/ # Chip specific obj-$(CONFIG_COMMON_CLK_WM831X) += clk-wm831x.o -- cgit v1.2.3 From 73118e6188c23719eeec3560b7fd1ca76f1a0919 Mon Sep 17 00:00:00 2001 From: Jonghwa Lee Date: Tue, 28 Aug 2012 17:54:28 +0900 Subject: clock: max77686: Add driver for Maxim 77686 32Khz crystal oscillator. This patch supports max77686 mfd's clock driver using common clock frame work. max77686 has 3 clock ouputs which all are generated from crystal oscillator and SOC can enable/disable them via I2C bus. All clocks are fixed-rate clock sources so that it doesn't supply interface for changing clock rate. Driver uses regmap API to communicate with internal register. Signed-off-by: Jonghwa Lee Signed-off-by: Mike Turquette --- drivers/clk/Kconfig | 6 ++ drivers/clk/Makefile | 1 + drivers/clk/clk-max77686.c | 244 +++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 251 insertions(+) create mode 100644 drivers/clk/clk-max77686.c (limited to 'drivers') diff --git a/drivers/clk/Kconfig b/drivers/clk/Kconfig index df33b8e2b5ad..bace9e98f75d 100644 --- a/drivers/clk/Kconfig +++ b/drivers/clk/Kconfig @@ -47,4 +47,10 @@ config COMMON_CLK_VERSATILE Supports clocking on ARM Reference designs Integrator/AP, Integrator/CP, RealView PB1176, EB, PB11MP and PBX. +config COMMON_CLK_MAX77686 + tristate "Clock driver for Maxim 77686 MFD" + depends on MFD_MAX77686 + ---help--- + This driver supports Maxim 77686 crystal oscillator clock. + endmenu diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile index d561825a87fc..6327536b4900 100644 --- a/drivers/clk/Makefile +++ b/drivers/clk/Makefile @@ -19,3 +19,4 @@ obj-$(CONFIG_ARCH_U8500) += ux500/ # Chip specific obj-$(CONFIG_COMMON_CLK_WM831X) += clk-wm831x.o +obj-$(CONFIG_COMMON_CLK_MAX77686) += clk-max77686.o diff --git a/drivers/clk/clk-max77686.c b/drivers/clk/clk-max77686.c new file mode 100644 index 000000000000..ac5f5434cb9a --- /dev/null +++ b/drivers/clk/clk-max77686.c @@ -0,0 +1,244 @@ +/* + * clk-max77686.c - Clock driver for Maxim 77686 + * + * Copyright (C) 2012 Samsung Electornics + * Jonghwa Lee + * + * 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. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +enum { + MAX77686_CLK_AP = 0, + MAX77686_CLK_CP, + MAX77686_CLK_PMIC, + MAX77686_CLKS_NUM, +}; + +struct max77686_clk { + struct max77686_dev *iodev; + u32 mask; + struct clk_hw hw; + struct clk_lookup *lookup; +}; + +static struct max77686_clk *get_max77686_clk(struct clk_hw *hw) +{ + return container_of(hw, struct max77686_clk, hw); +} + +static int max77686_clk_prepare(struct clk_hw *hw) +{ + struct max77686_clk *max77686; + int ret; + + max77686 = get_max77686_clk(hw); + if (!max77686) + return -ENOMEM; + + ret = regmap_update_bits(max77686->iodev->regmap, + MAX77686_REG_32KHZ, max77686->mask, max77686->mask); + + return ret; +} + +static void max77686_clk_unprepare(struct clk_hw *hw) +{ + struct max77686_clk *max77686; + + max77686 = get_max77686_clk(hw); + if (!max77686) + return; + + regmap_update_bits(max77686->iodev->regmap, + MAX77686_REG_32KHZ, max77686->mask, ~max77686->mask); +} + +static int max77686_clk_is_enabled(struct clk_hw *hw) +{ + struct max77686_clk *max77686; + int ret; + u32 val; + + max77686 = get_max77686_clk(hw); + if (!max77686) + return -ENOMEM; + + ret = regmap_read(max77686->iodev->regmap, + MAX77686_REG_32KHZ, &val); + + if (ret < 0) + return -EINVAL; + + return val & max77686->mask; +} + +static struct clk_ops max77686_clk_ops = { + .prepare = max77686_clk_prepare, + .unprepare = max77686_clk_unprepare, + .is_enabled = max77686_clk_is_enabled, +}; + +static struct clk_init_data max77686_clks_init[MAX77686_CLKS_NUM] = { + [MAX77686_CLK_AP] = { + .name = "32khz_ap", + .ops = &max77686_clk_ops, + .flags = CLK_IS_ROOT, + }, + [MAX77686_CLK_CP] = { + .name = "32khz_cp", + .ops = &max77686_clk_ops, + .flags = CLK_IS_ROOT, + }, + [MAX77686_CLK_PMIC] = { + .name = "32khz_pmic", + .ops = &max77686_clk_ops, + .flags = CLK_IS_ROOT, + }, +}; + +static int max77686_clk_register(struct device *dev, + struct max77686_clk *max77686) +{ + struct clk *clk; + struct clk_hw *hw = &max77686->hw; + + clk = clk_register(dev, hw); + + if (IS_ERR(clk)) + return -ENOMEM; + + max77686->lookup = devm_kzalloc(dev, sizeof(struct clk_lookup), + GFP_KERNEL); + if (IS_ERR(max77686->lookup)) + return -ENOMEM; + + max77686->lookup->con_id = hw->init->name; + max77686->lookup->clk = clk; + + clkdev_add(max77686->lookup); + + return 0; +} + +static __devinit int max77686_clk_probe(struct platform_device *pdev) +{ + struct max77686_dev *iodev = dev_get_drvdata(pdev->dev.parent); + struct max77686_clk **max77686_clks; + int i, ret; + + max77686_clks = devm_kzalloc(&pdev->dev, sizeof(struct max77686_clk *) + * MAX77686_CLKS_NUM, GFP_KERNEL); + if (IS_ERR(max77686_clks)) + return -ENOMEM; + + for (i = 0; i < MAX77686_CLKS_NUM; i++) { + max77686_clks[i] = devm_kzalloc(&pdev->dev, + sizeof(struct max77686_clk), GFP_KERNEL); + if (IS_ERR(max77686_clks[i])) + return -ENOMEM; + } + + for (i = 0; i < MAX77686_CLKS_NUM; i++) { + max77686_clks[i]->iodev = iodev; + max77686_clks[i]->mask = 1 << i; + max77686_clks[i]->hw.init = &max77686_clks_init[i]; + + ret = max77686_clk_register(&pdev->dev, max77686_clks[i]); + if (ret) { + switch (i) { + case MAX77686_CLK_AP: + dev_err(&pdev->dev, "Fail to register CLK_AP\n"); + goto err_clk_ap; + break; + case MAX77686_CLK_CP: + dev_err(&pdev->dev, "Fail to register CLK_CP\n"); + goto err_clk_cp; + break; + case MAX77686_CLK_PMIC: + dev_err(&pdev->dev, "Fail to register CLK_PMIC\n"); + goto err_clk_pmic; + } + } + } + + platform_set_drvdata(pdev, max77686_clks); + + goto out; + +err_clk_pmic: + clkdev_drop(max77686_clks[MAX77686_CLK_CP]->lookup); + kfree(max77686_clks[MAX77686_CLK_CP]->hw.clk); +err_clk_cp: + clkdev_drop(max77686_clks[MAX77686_CLK_AP]->lookup); + kfree(max77686_clks[MAX77686_CLK_AP]->hw.clk); +err_clk_ap: +out: + return ret; +} + +static int __devexit max77686_clk_remove(struct platform_device *pdev) +{ + struct max77686_clk **max77686_clks = platform_get_drvdata(pdev); + int i; + + for (i = 0; i < MAX77686_CLKS_NUM; i++) { + clkdev_drop(max77686_clks[i]->lookup); + kfree(max77686_clks[i]->hw.clk); + } + return 0; +} + +static const struct platform_device_id max77686_clk_id[] = { + { "max77686-clk", 0}, + { }, +}; +MODULE_DEVICE_TABLE(platform, max77686_clk_id); + +static struct platform_driver max77686_clk_driver = { + .driver = { + .name = "max77686-clk", + .owner = THIS_MODULE, + }, + .probe = max77686_clk_probe, + .remove = __devexit_p(max77686_clk_remove), + .id_table = max77686_clk_id, +}; + +static int __init max77686_clk_init(void) +{ + return platform_driver_register(&max77686_clk_driver); +} +subsys_initcall(max77686_clk_init); + +static void __init max77686_clk_cleanup(void) +{ + platform_driver_unregister(&max77686_clk_driver); +} +module_exit(max77686_clk_cleanup); + +MODULE_DESCRIPTION("MAXIM 77686 Clock Driver"); +MODULE_AUTHOR("Jonghwa Lee "); +MODULE_LICENSE("GPL"); -- cgit v1.2.3 From a093bde2b45a0a745f12c018e2d13c027d58641f Mon Sep 17 00:00:00 2001 From: Ulf Hansson Date: Fri, 31 Aug 2012 14:21:28 +0200 Subject: clk: Provide option for clk_get_rate to issue hw for new rate By using CLK_GET_RATE_NOCACHE flag, we tell the clk_get_rate API to issue the hw for an updated clock rate. This can be used for a clock which rate may be updated without a client necessary modifying it. Signed-off-by: Ulf Hansson Signed-off-by: Mike Turquette --- drivers/clk/clk.c | 43 ++++++++++++++++++++++++------------------- include/linux/clk-provider.h | 1 + 2 files changed, 25 insertions(+), 19 deletions(-) (limited to 'drivers') diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c index efdfd009c270..d9cbae06549f 100644 --- a/drivers/clk/clk.c +++ b/drivers/clk/clk.c @@ -557,25 +557,6 @@ int clk_enable(struct clk *clk) } EXPORT_SYMBOL_GPL(clk_enable); -/** - * clk_get_rate - return the rate of clk - * @clk: the clk whose rate is being returned - * - * Simply returns the cached rate of the clk. Does not query the hardware. If - * clk is NULL then returns 0. - */ -unsigned long clk_get_rate(struct clk *clk) -{ - unsigned long rate; - - mutex_lock(&prepare_lock); - rate = __clk_get_rate(clk); - mutex_unlock(&prepare_lock); - - return rate; -} -EXPORT_SYMBOL_GPL(clk_get_rate); - /** * __clk_round_rate - round the given rate for a clk * @clk: round the rate of this clock @@ -701,6 +682,30 @@ static void __clk_recalc_rates(struct clk *clk, unsigned long msg) __clk_recalc_rates(child, msg); } +/** + * clk_get_rate - return the rate of clk + * @clk: the clk whose rate is being returned + * + * Simply returns the cached rate of the clk, unless CLK_GET_RATE_NOCACHE flag + * is set, which means a recalc_rate will be issued. + * If clk is NULL then returns 0. + */ +unsigned long clk_get_rate(struct clk *clk) +{ + unsigned long rate; + + mutex_lock(&prepare_lock); + + if (clk && (clk->flags & CLK_GET_RATE_NOCACHE)) + __clk_recalc_rates(clk, 0); + + rate = __clk_get_rate(clk); + mutex_unlock(&prepare_lock); + + return rate; +} +EXPORT_SYMBOL_GPL(clk_get_rate); + /** * __clk_speculate_rates * @clk: first clk in the subtree diff --git a/include/linux/clk-provider.h b/include/linux/clk-provider.h index 77335fac943e..1b15307cd466 100644 --- a/include/linux/clk-provider.h +++ b/include/linux/clk-provider.h @@ -26,6 +26,7 @@ #define CLK_IGNORE_UNUSED BIT(3) /* do not gate even if unused */ #define CLK_IS_ROOT BIT(4) /* root clk, has no parent */ #define CLK_IS_BASIC BIT(5) /* Basic clk, can't do a to_clk_foo() */ +#define CLK_GET_RATE_NOCACHE BIT(6) /* do not use the cached clk rate */ struct clk_hw; -- cgit v1.2.3 From 70b1fce2ec3a89e68a35d99e5e9c6c90338b3dd1 Mon Sep 17 00:00:00 2001 From: Ulf Hansson Date: Fri, 31 Aug 2012 14:21:29 +0200 Subject: clk: ux500: Support for prmcu_rate clock The prmcu_rate clock is not gateable and has a rate which only can be fetched. Signed-off-by: Ulf Hansson Acked-by: Linus Walleij Signed-off-by: Mike Turquette --- drivers/clk/ux500/clk-prcmu.c | 14 ++++++++++++++ drivers/clk/ux500/clk.h | 5 +++++ 2 files changed, 19 insertions(+) (limited to 'drivers') diff --git a/drivers/clk/ux500/clk-prcmu.c b/drivers/clk/ux500/clk-prcmu.c index 1d779ad12169..930cdfeb47ab 100644 --- a/drivers/clk/ux500/clk-prcmu.c +++ b/drivers/clk/ux500/clk-prcmu.c @@ -153,6 +153,11 @@ static struct clk_ops clk_prcmu_gate_ops = { .recalc_rate = clk_prcmu_recalc_rate, }; +static struct clk_ops clk_prcmu_rate_ops = { + .is_enabled = clk_prcmu_is_enabled, + .recalc_rate = clk_prcmu_recalc_rate, +}; + static struct clk_ops clk_prcmu_opp_gate_ops = { .prepare = clk_prcmu_opp_prepare, .unprepare = clk_prcmu_opp_unprepare, @@ -228,6 +233,15 @@ struct clk *clk_reg_prcmu_gate(const char *name, &clk_prcmu_gate_ops); } +struct clk *clk_reg_prcmu_rate(const char *name, + const char *parent_name, + u8 cg_sel, + unsigned long flags) +{ + return clk_reg_prcmu(name, parent_name, cg_sel, 0, flags, + &clk_prcmu_rate_ops); +} + struct clk *clk_reg_prcmu_opp_gate(const char *name, const char *parent_name, u8 cg_sel, diff --git a/drivers/clk/ux500/clk.h b/drivers/clk/ux500/clk.h index 32085aa98865..836d7d16751e 100644 --- a/drivers/clk/ux500/clk.h +++ b/drivers/clk/ux500/clk.h @@ -35,6 +35,11 @@ struct clk *clk_reg_prcmu_gate(const char *name, u8 cg_sel, unsigned long flags); +struct clk *clk_reg_prcmu_rate(const char *name, + const char *parent_name, + u8 cg_sel, + unsigned long flags); + struct clk *clk_reg_prcmu_opp_gate(const char *name, const char *parent_name, u8 cg_sel, -- cgit v1.2.3 From 20aee5b6d7738206bfd37b352a97c75627d6fa6d Mon Sep 17 00:00:00 2001 From: Michel Jaouen Date: Fri, 31 Aug 2012 14:21:30 +0200 Subject: mfd: dbx500: Provide a more accurate smp_twd clock The local timer clock is based on ARM subsystem clock. This patch obtains a more exact value of that clock by reading PRCMU registers. Using this increases the accuracy of the local timer events. Signed-off-by: Ulf Hansson Signed-off-by: Rickard Andersson Signed-off-by: Michel Jaouen Acked-by: Linus Walleij Signed-off-by: Mike Turquette --- drivers/mfd/db8500-prcmu.c | 42 ++++++++++++++++++++++++++++++++++++++++ drivers/mfd/dbx500-prcmu-regs.h | 4 +++- include/linux/mfd/dbx500-prcmu.h | 1 + 3 files changed, 46 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/mfd/db8500-prcmu.c b/drivers/mfd/db8500-prcmu.c index 7040a0081130..6b37e2d6ed8f 100644 --- a/drivers/mfd/db8500-prcmu.c +++ b/drivers/mfd/db8500-prcmu.c @@ -418,6 +418,9 @@ static struct { static atomic_t ac_wake_req_state = ATOMIC_INIT(0); +/* Functions definition */ +static void compute_armss_rate(void); + /* Spinlocks */ static DEFINE_SPINLOCK(prcmu_lock); static DEFINE_SPINLOCK(clkout_lock); @@ -517,6 +520,7 @@ static struct dsiescclk dsiescclk[3] = { } }; + /* * Used by MCDE to setup all necessary PRCMU registers */ @@ -1013,6 +1017,7 @@ int db8500_prcmu_set_arm_opp(u8 opp) (mb1_transfer.ack.arm_opp != opp)) r = -EIO; + compute_armss_rate(); mutex_unlock(&mb1_transfer.lock); return r; @@ -1612,6 +1617,7 @@ static unsigned long pll_rate(void __iomem *reg, unsigned long src_rate, if ((branch == PLL_FIX) || ((branch == PLL_DIV) && (val & PRCM_PLL_FREQ_DIV2EN) && ((reg == PRCM_PLLSOC0_FREQ) || + (reg == PRCM_PLLARM_FREQ) || (reg == PRCM_PLLDDR_FREQ)))) div *= 2; @@ -1661,6 +1667,39 @@ static unsigned long clock_rate(u8 clock) else return 0; } +static unsigned long latest_armss_rate; +static unsigned long armss_rate(void) +{ + return latest_armss_rate; +} + +static void compute_armss_rate(void) +{ + u32 r; + unsigned long rate; + + r = readl(PRCM_ARM_CHGCLKREQ); + + if (r & PRCM_ARM_CHGCLKREQ_PRCM_ARM_CHGCLKREQ) { + /* External ARMCLKFIX clock */ + + rate = pll_rate(PRCM_PLLDDR_FREQ, ROOT_CLOCK_RATE, PLL_FIX); + + /* Check PRCM_ARM_CHGCLKREQ divider */ + if (!(r & PRCM_ARM_CHGCLKREQ_PRCM_ARM_DIVSEL)) + rate /= 2; + + /* Check PRCM_ARMCLKFIX_MGT divider */ + r = readl(PRCM_ARMCLKFIX_MGT); + r &= PRCM_CLK_MGT_CLKPLLDIV_MASK; + rate /= r; + + } else {/* ARM PLL */ + rate = pll_rate(PRCM_PLLARM_FREQ, ROOT_CLOCK_RATE, PLL_DIV); + } + + latest_armss_rate = rate; +} static unsigned long dsiclk_rate(u8 n) { @@ -1707,6 +1746,8 @@ unsigned long prcmu_clock_rate(u8 clock) return pll_rate(PRCM_PLLSOC0_FREQ, ROOT_CLOCK_RATE, PLL_RAW); else if (clock == PRCMU_PLLSOC1) return pll_rate(PRCM_PLLSOC1_FREQ, ROOT_CLOCK_RATE, PLL_RAW); + else if (clock == PRCMU_ARMSS) + return armss_rate(); else if (clock == PRCMU_PLLDDR) return pll_rate(PRCM_PLLDDR_FREQ, ROOT_CLOCK_RATE, PLL_RAW); else if (clock == PRCMU_PLLDSI) @@ -2693,6 +2734,7 @@ void __init db8500_prcmu_early_init(void) handle_simple_irq); set_irq_flags(irq, IRQF_VALID); } + compute_armss_rate(); } static void __init init_prcm_registers(void) diff --git a/drivers/mfd/dbx500-prcmu-regs.h b/drivers/mfd/dbx500-prcmu-regs.h index 23108a6e3167..79c76ebdba52 100644 --- a/drivers/mfd/dbx500-prcmu-regs.h +++ b/drivers/mfd/dbx500-prcmu-regs.h @@ -61,7 +61,8 @@ #define PRCM_PLLARM_LOCKP_PRCM_PLLARM_LOCKP3 0x2 #define PRCM_ARM_CHGCLKREQ (_PRCMU_BASE + 0x114) -#define PRCM_ARM_CHGCLKREQ_PRCM_ARM_CHGCLKREQ 0x1 +#define PRCM_ARM_CHGCLKREQ_PRCM_ARM_CHGCLKREQ BIT(0) +#define PRCM_ARM_CHGCLKREQ_PRCM_ARM_DIVSEL BIT(16) #define PRCM_PLLARM_ENABLE (_PRCMU_BASE + 0x98) #define PRCM_PLLARM_ENABLE_PRCM_PLLARM_ENABLE 0x1 @@ -140,6 +141,7 @@ /* PRCMU clock/PLL/reset registers */ #define PRCM_PLLSOC0_FREQ (_PRCMU_BASE + 0x080) #define PRCM_PLLSOC1_FREQ (_PRCMU_BASE + 0x084) +#define PRCM_PLLARM_FREQ (_PRCMU_BASE + 0x088) #define PRCM_PLLDDR_FREQ (_PRCMU_BASE + 0x08C) #define PRCM_PLL_FREQ_D_SHIFT 0 #define PRCM_PLL_FREQ_D_MASK BITS(0, 7) diff --git a/include/linux/mfd/dbx500-prcmu.h b/include/linux/mfd/dbx500-prcmu.h index 5b90e94399e1..c410d99bd667 100644 --- a/include/linux/mfd/dbx500-prcmu.h +++ b/include/linux/mfd/dbx500-prcmu.h @@ -136,6 +136,7 @@ enum prcmu_clock { PRCMU_TIMCLK, PRCMU_PLLSOC0, PRCMU_PLLSOC1, + PRCMU_ARMSS, PRCMU_PLLDDR, PRCMU_PLLDSI, PRCMU_DSI0CLK, -- cgit v1.2.3 From 09b9b2b204751fc23d245d57d420f4973db22a67 Mon Sep 17 00:00:00 2001 From: Ulf Hansson Date: Fri, 31 Aug 2012 14:21:31 +0200 Subject: clk: ux500: Define smp_twd clock for u8500 The smp_twd clock is based upon a prcmu_rate clock type for the PRCMU_ARMSS clock. Signed-off-by: Ulf Hansson Acked-by: Linus Walleij Signed-off-by: Mike Turquette --- drivers/clk/ux500/u8500_clk.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/clk/ux500/u8500_clk.c b/drivers/clk/ux500/u8500_clk.c index 5c1fca1f28de..ca4a25ed844c 100644 --- a/drivers/clk/ux500/u8500_clk.c +++ b/drivers/clk/ux500/u8500_clk.c @@ -205,12 +205,16 @@ void u8500_clk_init(void) clk_register_clkdev(clk, "dsilp2", "dsilink.2"); clk_register_clkdev(clk, "dsilp2", "mcde"); + clk = clk_reg_prcmu_rate("smp_twd", NULL, PRCMU_ARMSS, + CLK_IS_ROOT|CLK_GET_RATE_NOCACHE| + CLK_IGNORE_UNUSED); + clk_register_clkdev(clk, NULL, "smp_twd"); + /* * FIXME: Add special handled PRCMU clocks here: - * 1. smp_twd, use PRCMU_ARMSS. - * 2. clk_arm, use PRCMU_ARMCLK. - * 3. clkout0yuv, use PRCMU as parent + need regulator + pinctrl. - * 4. ab9540_clkout1yuv, see clkout0yuv + * 1. clk_arm, use PRCMU_ARMCLK. + * 2. clkout0yuv, use PRCMU as parent + need regulator + pinctrl. + * 3. ab9540_clkout1yuv, see clkout0yuv */ /* PRCC P-clocks */ -- cgit v1.2.3 From 172c6a13653ac8cd6a231293b87c93821e90c1d6 Mon Sep 17 00:00:00 2001 From: Heiko Stuebner Date: Fri, 7 Sep 2012 06:49:47 +0900 Subject: gpio: samsung: add devicetree init for s3c24xx arches Until now the EXYNOS-SoC was the only Samsung-SoC supporting the GPIOs via the device tree. This patch implements dt-support for the s3c24xx arches. The controllers contain only 3 cells, as the underlying gpio controller does not support controlling the drive strength on a gpio level. Tested with the gpio-keys driver on a s3c2416 based machine. Signed-off-by: Heiko Stuebner Reviewed-by: Thomas Abraham Acked-by: Linus Walleij [kgene.kim@samsung.com: fixed build error] Signed-off-by: Kukjin Kim --- .../devicetree/bindings/gpio/gpio-samsung.txt | 43 +++++++++++++++ drivers/gpio/gpio-samsung.c | 63 ++++++++++++++++++++++ 2 files changed, 106 insertions(+) (limited to 'drivers') diff --git a/Documentation/devicetree/bindings/gpio/gpio-samsung.txt b/Documentation/devicetree/bindings/gpio/gpio-samsung.txt index 5375625e8cd2..f1e5dfecf55d 100644 --- a/Documentation/devicetree/bindings/gpio/gpio-samsung.txt +++ b/Documentation/devicetree/bindings/gpio/gpio-samsung.txt @@ -39,3 +39,46 @@ Example: #gpio-cells = <4>; gpio-controller; }; + + +Samsung S3C24XX GPIO Controller + +Required properties: +- compatible: Compatible property value should be "samsung,s3c24xx-gpio". + +- reg: Physical base address of the controller and length of memory mapped + region. + +- #gpio-cells: Should be 3. The syntax of the gpio specifier used by client nodes + should be the following with values derived from the SoC user manual. + <[phandle of the gpio controller node] + [pin number within the gpio controller] + [mux function] + [flags and pull up/down] + + Values for gpio specifier: + - Pin number: depending on the controller a number from 0 up to 15. + - Mux function: Depending on the SoC and the gpio bank the gpio can be set + as input, output or a special function + - Flags and Pull Up/Down: the values to use differ for the individual SoCs + example S3C2416/S3C2450: + 0 - Pull Up/Down Disabled. + 1 - Pull Down Enabled. + 2 - Pull Up Enabled. + Bit 16 (0x00010000) - Input is active low. + Consult the user manual for the correct values of Mux and Pull Up/Down. + +- gpio-controller: Specifies that the node is a gpio controller. +- #address-cells: should be 1. +- #size-cells: should be 1. + +Example: + + gpa: gpio-controller@56000000 { + #address-cells = <1>; + #size-cells = <1>; + compatible = "samsung,s3c24xx-gpio"; + reg = <0x56000000 0x10>; + #gpio-cells = <3>; + gpio-controller; + }; diff --git a/drivers/gpio/gpio-samsung.c b/drivers/gpio/gpio-samsung.c index ba126cc04073..f4814a889a5b 100644 --- a/drivers/gpio/gpio-samsung.c +++ b/drivers/gpio/gpio-samsung.c @@ -938,6 +938,67 @@ static void __init samsung_gpiolib_add(struct samsung_gpio_chip *chip) s3c_gpiolib_track(chip); } +#if defined(CONFIG_PLAT_S3C24XX) && defined(CONFIG_OF) +static int s3c24xx_gpio_xlate(struct gpio_chip *gc, + const struct of_phandle_args *gpiospec, u32 *flags) +{ + unsigned int pin; + + if (WARN_ON(gc->of_gpio_n_cells < 3)) + return -EINVAL; + + if (WARN_ON(gpiospec->args_count < gc->of_gpio_n_cells)) + return -EINVAL; + + if (gpiospec->args[0] > gc->ngpio) + return -EINVAL; + + pin = gc->base + gpiospec->args[0]; + + if (s3c_gpio_cfgpin(pin, S3C_GPIO_SFN(gpiospec->args[1]))) + pr_warn("gpio_xlate: failed to set pin function\n"); + if (s3c_gpio_setpull(pin, gpiospec->args[2] & 0xffff)) + pr_warn("gpio_xlate: failed to set pin pull up/down\n"); + + if (flags) + *flags = gpiospec->args[2] >> 16; + + return gpiospec->args[0]; +} + +static const struct of_device_id s3c24xx_gpio_dt_match[] __initdata = { + { .compatible = "samsung,s3c24xx-gpio", }, + {} +}; + +static __init void s3c24xx_gpiolib_attach_ofnode(struct samsung_gpio_chip *chip, + u64 base, u64 offset) +{ + struct gpio_chip *gc = &chip->chip; + u64 address; + + if (!of_have_populated_dt()) + return; + + address = chip->base ? base + ((u32)chip->base & 0xfff) : base + offset; + gc->of_node = of_find_matching_node_by_address(NULL, + s3c24xx_gpio_dt_match, address); + if (!gc->of_node) { + pr_info("gpio: device tree node not found for gpio controller" + " with base address %08llx\n", address); + return; + } + gc->of_gpio_n_cells = 3; + gc->of_xlate = s3c24xx_gpio_xlate; +} +#else +static __init void s3c24xx_gpiolib_attach_ofnode(struct samsung_gpio_chip *chip, + u64 base, u64 offset) +{ + return; +} +#endif /* defined(CONFIG_PLAT_S3C24XX) && defined(CONFIG_OF) */ + static void __init s3c24xx_gpiolib_add_chips(struct samsung_gpio_chip *chip, int nr_chips, void __iomem *base) { @@ -962,6 +1023,8 @@ static void __init s3c24xx_gpiolib_add_chips(struct samsung_gpio_chip *chip, gc->direction_output = samsung_gpiolib_2bit_output; samsung_gpiolib_add(chip); + + s3c24xx_gpiolib_attach_ofnode(chip, S3C24XX_PA_GPIO, i * 0x10); } } -- cgit v1.2.3 From f74ce8fb849e9f9c54a494cff5fc30d53ca4e963 Mon Sep 17 00:00:00 2001 From: Florian Vaussard Date: Wed, 5 Sep 2012 09:46:25 +0200 Subject: gpio/twl4030: get platform data from device tree Adds a number of missing device tree properties for twl4030/gpio, and update bindings: - "ti,use-leds" -> .use_leds - "ti,debounce" -> .debounce - "ti,mmc-cd" -> .mmc_cd - "ti,pullups" -> .pullups - "ti,pulldowns" -> .pulldowns Signed-off-by: Florian Vaussard Acked-by: Linus Walleij Acked-by: Vaibhav Hiremath [b-cousson@ti.com: Fix some checkpatch CHECK issues] Signed-off-by: Benoit Cousson --- .../devicetree/bindings/gpio/gpio-twl4030.txt | 6 ++ drivers/gpio/gpio-twl4030.c | 82 +++++++++++++++------- 2 files changed, 61 insertions(+), 27 deletions(-) (limited to 'drivers') diff --git a/Documentation/devicetree/bindings/gpio/gpio-twl4030.txt b/Documentation/devicetree/bindings/gpio/gpio-twl4030.txt index 16695d9cf1e8..66788fda1db3 100644 --- a/Documentation/devicetree/bindings/gpio/gpio-twl4030.txt +++ b/Documentation/devicetree/bindings/gpio/gpio-twl4030.txt @@ -11,6 +11,11 @@ Required properties: - interrupt-controller: Mark the device node as an interrupt controller The first cell is the GPIO number. The second cell is not used. +- ti,use-leds : Enables LEDA and LEDB outputs if set +- ti,debounce : if n-th bit is set, debounces GPIO-n +- ti,mmc-cd : if n-th bit is set, GPIO-n controls VMMC(n+1) +- ti,pullups : if n-th bit is set, set a pullup on GPIO-n +- ti,pulldowns : if n-th bit is set, set a pulldown on GPIO-n Example: @@ -20,4 +25,5 @@ twl_gpio: gpio { gpio-controller; #interrupt-cells = <2>; interrupt-controller; + ti,use-leds; }; diff --git a/drivers/gpio/gpio-twl4030.c b/drivers/gpio/gpio-twl4030.c index 94256fe7bf36..f923252da839 100644 --- a/drivers/gpio/gpio-twl4030.c +++ b/drivers/gpio/gpio-twl4030.c @@ -395,6 +395,31 @@ static int __devinit gpio_twl4030_debounce(u32 debounce, u8 mmc_cd) static int gpio_twl4030_remove(struct platform_device *pdev); +static struct twl4030_gpio_platform_data *of_gpio_twl4030(struct device *dev) +{ + struct twl4030_gpio_platform_data *omap_twl_info; + + omap_twl_info = devm_kzalloc(dev, sizeof(*omap_twl_info), GFP_KERNEL); + if (!omap_twl_info) + return NULL; + + omap_twl_info->gpio_base = -1; + + omap_twl_info->use_leds = of_property_read_bool(dev->of_node, + "ti,use-leds"); + + of_property_read_u32(dev->of_node, "ti,debounce", + &omap_twl_info->debounce); + of_property_read_u32(dev->of_node, "ti,mmc-cd", + (u32 *)&omap_twl_info->mmc_cd); + of_property_read_u32(dev->of_node, "ti,pullups", + &omap_twl_info->pullups); + of_property_read_u32(dev->of_node, "ti,pulldowns", + &omap_twl_info->pulldowns); + + return omap_twl_info; +} + static int __devinit gpio_twl4030_probe(struct platform_device *pdev) { struct twl4030_gpio_platform_data *pdata = pdev->dev.platform_data; @@ -423,39 +448,42 @@ static int __devinit gpio_twl4030_probe(struct platform_device *pdev) twl4030_gpio_irq_base = irq_base; no_irqs: - twl_gpiochip.base = -1; twl_gpiochip.ngpio = TWL4030_GPIO_MAX; twl_gpiochip.dev = &pdev->dev; - if (pdata) { - twl_gpiochip.base = pdata->gpio_base; + if (node) + pdata = of_gpio_twl4030(&pdev->dev); - /* - * NOTE: boards may waste power if they don't set pullups - * and pulldowns correctly ... default for non-ULPI pins is - * pulldown, and some other pins may have external pullups - * or pulldowns. Careful! - */ - ret = gpio_twl4030_pulls(pdata->pullups, pdata->pulldowns); - if (ret) - dev_dbg(&pdev->dev, "pullups %.05x %.05x --> %d\n", - pdata->pullups, pdata->pulldowns, - ret); - - ret = gpio_twl4030_debounce(pdata->debounce, pdata->mmc_cd); - if (ret) - dev_dbg(&pdev->dev, "debounce %.03x %.01x --> %d\n", - pdata->debounce, pdata->mmc_cd, - ret); - - /* - * NOTE: we assume VIBRA_CTL.VIBRA_EN, in MODULE_AUDIO_VOICE, - * is (still) clear if use_leds is set. - */ - if (pdata->use_leds) - twl_gpiochip.ngpio += 2; + if (pdata == NULL) { + dev_err(&pdev->dev, "Platform data is missing\n"); + return -ENXIO; } + twl_gpiochip.base = pdata->gpio_base; + + /* + * NOTE: boards may waste power if they don't set pullups + * and pulldowns correctly ... default for non-ULPI pins is + * pulldown, and some other pins may have external pullups + * or pulldowns. Careful! + */ + ret = gpio_twl4030_pulls(pdata->pullups, pdata->pulldowns); + if (ret) + dev_dbg(&pdev->dev, "pullups %.05x %.05x --> %d\n", + pdata->pullups, pdata->pulldowns, ret); + + ret = gpio_twl4030_debounce(pdata->debounce, pdata->mmc_cd); + if (ret) + dev_dbg(&pdev->dev, "debounce %.03x %.01x --> %d\n", + pdata->debounce, pdata->mmc_cd, ret); + + /* + * NOTE: we assume VIBRA_CTL.VIBRA_EN, in MODULE_AUDIO_VOICE, + * is (still) clear if use_leds is set. + */ + if (pdata->use_leds) + twl_gpiochip.ngpio += 2; + ret = gpiochip_add(&twl_gpiochip); if (ret < 0) { dev_err(&pdev->dev, "could not register gpiochip, %d\n", ret); -- cgit v1.2.3 From 494bfec99922d54054d2d0873f1017680cfc3f13 Mon Sep 17 00:00:00 2001 From: Shawn Guo Date: Wed, 22 Aug 2012 21:36:27 +0800 Subject: clk: add of_clk_src_onecell_get() support For those SoCs that have hundreds of clock outputs, their clock DT bindings could reasonably define #clock-cells as 1 and require the client device specify the index of the clock it consumes in the cell of its "clocks" phandle. Add a generic of_clk_src_onecell_get() function for this purpose. Signed-off-by: Shawn Guo Reviewed-by: Rob Herring Signed-off-by: Mike Turquette --- drivers/clk/clk.c | 14 ++++++++++++++ include/linux/clk-provider.h | 5 +++++ 2 files changed, 19 insertions(+) (limited to 'drivers') diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c index d9cbae06549f..56e4495ebeb1 100644 --- a/drivers/clk/clk.c +++ b/drivers/clk/clk.c @@ -1587,6 +1587,20 @@ struct clk *of_clk_src_simple_get(struct of_phandle_args *clkspec, } EXPORT_SYMBOL_GPL(of_clk_src_simple_get); +struct clk *of_clk_src_onecell_get(struct of_phandle_args *clkspec, void *data) +{ + struct clk_onecell_data *clk_data = data; + unsigned int idx = clkspec->args[0]; + + if (idx >= clk_data->clk_num) { + pr_err("%s: invalid clock index %d\n", __func__, idx); + return ERR_PTR(-EINVAL); + } + + return clk_data->clks[idx]; +} +EXPORT_SYMBOL_GPL(of_clk_src_onecell_get); + /** * of_clk_add_provider() - Register a clock provider for a node * @np: Device node pointer associated with clock provider diff --git a/include/linux/clk-provider.h b/include/linux/clk-provider.h index 1b15307cd466..c12731582920 100644 --- a/include/linux/clk-provider.h +++ b/include/linux/clk-provider.h @@ -361,6 +361,11 @@ int of_clk_add_provider(struct device_node *np, void of_clk_del_provider(struct device_node *np); struct clk *of_clk_src_simple_get(struct of_phandle_args *clkspec, void *data); +struct clk_onecell_data { + struct clk **clks; + unsigned int clk_num; +}; +struct clk *of_clk_src_onecell_get(struct of_phandle_args *clkspec, void *data); const char *of_clk_get_parent_name(struct device_node *np, int index); void of_clk_init(const struct of_device_id *matches); -- cgit v1.2.3 From b598b9f311a604ca533033baa5afcf45beb037d9 Mon Sep 17 00:00:00 2001 From: Shawn Guo Date: Wed, 22 Aug 2012 21:36:29 +0800 Subject: clk: mxs: replace imx28 clk_register_clkdev with clock DT lookup It really becomes a maintenance issue that every time a device needs to look up (clk_get) a clock we have to patch kernel clock file to call clk_register_clkdev for that clock. Since clock DT support which is meant to resolve clock lookup in device tree is in place, the patch moves imx28 client devices' clock lookup over to device tree, so that any new lookup to be added at later time can just get done in DT instead of kernel. Signed-off-by: Shawn Guo --- .../devicetree/bindings/clock/imx28-clock.txt | 99 ++++++++++++++++++ arch/arm/boot/dts/imx28.dtsi | 35 ++++++- drivers/clk/mxs/clk-imx28.c | 113 ++------------------- 3 files changed, 142 insertions(+), 105 deletions(-) create mode 100644 Documentation/devicetree/bindings/clock/imx28-clock.txt (limited to 'drivers') diff --git a/Documentation/devicetree/bindings/clock/imx28-clock.txt b/Documentation/devicetree/bindings/clock/imx28-clock.txt new file mode 100644 index 000000000000..aa2af2866fe8 --- /dev/null +++ b/Documentation/devicetree/bindings/clock/imx28-clock.txt @@ -0,0 +1,99 @@ +* Clock bindings for Freescale i.MX28 + +Required properties: +- compatible: Should be "fsl,imx28-clkctrl" +- reg: Address and length of the register set +- #clock-cells: Should be <1> + +The clock consumer should specify the desired clock by having the clock +ID in its "clocks" phandle cell. The following is a full list of i.MX28 +clocks and IDs. + + Clock ID + ------------------ + ref_xtal 0 + pll0 1 + pll1 2 + pll2 3 + ref_cpu 4 + ref_emi 5 + ref_io0 6 + ref_io1 7 + ref_pix 8 + ref_hsadc 9 + ref_gpmi 10 + saif0_sel 11 + saif1_sel 12 + gpmi_sel 13 + ssp0_sel 14 + ssp1_sel 15 + ssp2_sel 16 + ssp3_sel 17 + emi_sel 18 + etm_sel 19 + lcdif_sel 20 + cpu 21 + ptp_sel 22 + cpu_pll 23 + cpu_xtal 24 + hbus 25 + xbus 26 + ssp0_div 27 + ssp1_div 28 + ssp2_div 29 + ssp3_div 30 + gpmi_div 31 + emi_pll 32 + emi_xtal 33 + lcdif_div 34 + etm_div 35 + ptp 36 + saif0_div 37 + saif1_div 38 + clk32k_div 39 + rtc 40 + lradc 41 + spdif_div 42 + clk32k 43 + pwm 44 + uart 45 + ssp0 46 + ssp1 47 + ssp2 48 + ssp3 49 + gpmi 50 + spdif 51 + emi 52 + saif0 53 + saif1 54 + lcdif 55 + etm 56 + fec 57 + can0 58 + can1 59 + usb0 60 + usb1 61 + usb0_pwr 62 + usb1_pwr 63 + enet_out 64 + +Examples: + +clks: clkctrl@80040000 { + compatible = "fsl,imx28-clkctrl"; + reg = <0x80040000 0x2000>; + #clock-cells = <1>; + clock-output-names = + ... + "uart", /* 45 */ + ... + "end_of_list"; +}; + +auart0: serial@8006a000 { + compatible = "fsl,imx28-auart", "fsl,imx23-auart"; + reg = <0x8006a000 0x2000>; + interrupts = <112 70 71>; + clocks = <&clks 45>; + status = "disabled"; +}; diff --git a/arch/arm/boot/dts/imx28.dtsi b/arch/arm/boot/dts/imx28.dtsi index 96fe74e4935c..03e0fef8e7a7 100644 --- a/arch/arm/boot/dts/imx28.dtsi +++ b/arch/arm/boot/dts/imx28.dtsi @@ -65,6 +65,7 @@ dma-apbh@80004000 { compatible = "fsl,imx28-dma-apbh"; reg = <0x80004000 0x2000>; + clocks = <&clks 25>; }; perfmon@80006000 { @@ -81,6 +82,7 @@ reg-names = "gpmi-nand", "bch"; interrupts = <88>, <41>; interrupt-names = "gpmi-dma", "bch"; + clocks = <&clks 50>; fsl,gpmi-dma-channel = <4>; status = "disabled"; }; @@ -90,6 +92,7 @@ #size-cells = <0>; reg = <0x80010000 0x2000>; interrupts = <96 82>; + clocks = <&clks 46>; fsl,ssp-dma-channel = <0>; status = "disabled"; }; @@ -99,6 +102,7 @@ #size-cells = <0>; reg = <0x80012000 0x2000>; interrupts = <97 83>; + clocks = <&clks 47>; fsl,ssp-dma-channel = <1>; status = "disabled"; }; @@ -108,6 +112,7 @@ #size-cells = <0>; reg = <0x80014000 0x2000>; interrupts = <98 84>; + clocks = <&clks 48>; fsl,ssp-dma-channel = <2>; status = "disabled"; }; @@ -117,6 +122,7 @@ #size-cells = <0>; reg = <0x80016000 0x2000>; interrupts = <99 85>; + clocks = <&clks 49>; fsl,ssp-dma-channel = <3>; status = "disabled"; }; @@ -606,6 +612,7 @@ dma-apbx@80024000 { compatible = "fsl,imx28-dma-apbx"; reg = <0x80024000 0x2000>; + clocks = <&clks 26>; }; dcp@80028000 { @@ -634,6 +641,7 @@ compatible = "fsl,imx28-lcdif"; reg = <0x80030000 0x2000>; interrupts = <38 86>; + clocks = <&clks 55>; status = "disabled"; }; @@ -641,6 +649,8 @@ compatible = "fsl,imx28-flexcan", "fsl,p1010-flexcan"; reg = <0x80032000 0x2000>; interrupts = <8>; + clocks = <&clks 58>, <&clks 58>; + clock-names = "ipg", "per"; status = "disabled"; }; @@ -648,6 +658,8 @@ compatible = "fsl,imx28-flexcan", "fsl,p1010-flexcan"; reg = <0x80034000 0x2000>; interrupts = <9>; + clocks = <&clks 59>, <&clks 59>; + clock-names = "ipg", "per"; status = "disabled"; }; @@ -694,15 +706,17 @@ reg = <0x80040000 0x40000>; ranges; - clkctl@80040000 { + clks: clkctrl@80040000 { + compatible = "fsl,imx28-clkctrl"; reg = <0x80040000 0x2000>; - status = "disabled"; + #clock-cells = <1>; }; saif0: saif@80042000 { compatible = "fsl,imx28-saif"; reg = <0x80042000 0x2000>; interrupts = <59 80>; + clocks = <&clks 53>; fsl,saif-dma-channel = <4>; status = "disabled"; }; @@ -716,6 +730,7 @@ compatible = "fsl,imx28-saif"; reg = <0x80046000 0x2000>; interrupts = <58 81>; + clocks = <&clks 54>; fsl,saif-dma-channel = <5>; status = "disabled"; }; @@ -763,6 +778,7 @@ pwm: pwm@80064000 { compatible = "fsl,imx28-pwm", "fsl,imx23-pwm"; reg = <0x80064000 0x2000>; + clocks = <&clks 44>; #pwm-cells = <2>; fsl,pwm-number = <8>; status = "disabled"; @@ -777,6 +793,7 @@ compatible = "fsl,imx28-auart", "fsl,imx23-auart"; reg = <0x8006a000 0x2000>; interrupts = <112 70 71>; + clocks = <&clks 45>; status = "disabled"; }; @@ -784,6 +801,7 @@ compatible = "fsl,imx28-auart", "fsl,imx23-auart"; reg = <0x8006c000 0x2000>; interrupts = <113 72 73>; + clocks = <&clks 45>; status = "disabled"; }; @@ -791,6 +809,7 @@ compatible = "fsl,imx28-auart", "fsl,imx23-auart"; reg = <0x8006e000 0x2000>; interrupts = <114 74 75>; + clocks = <&clks 45>; status = "disabled"; }; @@ -798,6 +817,7 @@ compatible = "fsl,imx28-auart", "fsl,imx23-auart"; reg = <0x80070000 0x2000>; interrupts = <115 76 77>; + clocks = <&clks 45>; status = "disabled"; }; @@ -805,6 +825,7 @@ compatible = "fsl,imx28-auart", "fsl,imx23-auart"; reg = <0x80072000 0x2000>; interrupts = <116 78 79>; + clocks = <&clks 45>; status = "disabled"; }; @@ -812,18 +833,22 @@ compatible = "arm,pl011", "arm,primecell"; reg = <0x80074000 0x1000>; interrupts = <47>; + clocks = <&clks 45>, <&clks 26>; + clock-names = "uart", "apb_pclk"; status = "disabled"; }; usbphy0: usbphy@8007c000 { compatible = "fsl,imx28-usbphy", "fsl,imx23-usbphy"; reg = <0x8007c000 0x2000>; + clocks = <&clks 62>; status = "disabled"; }; usbphy1: usbphy@8007e000 { compatible = "fsl,imx28-usbphy", "fsl,imx23-usbphy"; reg = <0x8007e000 0x2000>; + clocks = <&clks 63>; status = "disabled"; }; }; @@ -840,6 +865,7 @@ compatible = "fsl,imx28-usb", "fsl,imx27-usb"; reg = <0x80080000 0x10000>; interrupts = <93>; + clocks = <&clks 60>; fsl,usbphy = <&usbphy0>; status = "disabled"; }; @@ -848,6 +874,7 @@ compatible = "fsl,imx28-usb", "fsl,imx27-usb"; reg = <0x80090000 0x10000>; interrupts = <92>; + clocks = <&clks 61>; fsl,usbphy = <&usbphy1>; status = "disabled"; }; @@ -861,6 +888,8 @@ compatible = "fsl,imx28-fec"; reg = <0x800f0000 0x4000>; interrupts = <101>; + clocks = <&clks 57>, <&clks 57>; + clock-names = "ipg", "ahb"; status = "disabled"; }; @@ -868,6 +897,8 @@ compatible = "fsl,imx28-fec"; reg = <0x800f4000 0x4000>; interrupts = <102>; + clocks = <&clks 57>, <&clks 57>; + clock-names = "ipg", "ahb"; status = "disabled"; }; diff --git a/drivers/clk/mxs/clk-imx28.c b/drivers/clk/mxs/clk-imx28.c index e3aab67b3eb7..613e76f3758e 100644 --- a/drivers/clk/mxs/clk-imx28.c +++ b/drivers/clk/mxs/clk-imx28.c @@ -14,6 +14,7 @@ #include #include #include +#include #include #include #include "clk.h" @@ -120,90 +121,6 @@ static void __init clk_misc_init(void) writel_relaxed(val, FRAC0); } -static struct clk_lookup uart_lookups[] = { - { .dev_id = "duart", }, - { .dev_id = "mxs-auart.0", }, - { .dev_id = "mxs-auart.1", }, - { .dev_id = "mxs-auart.2", }, - { .dev_id = "mxs-auart.3", }, - { .dev_id = "mxs-auart.4", }, - { .dev_id = "8006a000.serial", }, - { .dev_id = "8006c000.serial", }, - { .dev_id = "8006e000.serial", }, - { .dev_id = "80070000.serial", }, - { .dev_id = "80072000.serial", }, - { .dev_id = "80074000.serial", }, -}; - -static struct clk_lookup hbus_lookups[] = { - { .dev_id = "imx28-dma-apbh", }, - { .dev_id = "80004000.dma-apbh", }, -}; - -static struct clk_lookup xbus_lookups[] = { - { .dev_id = "duart", .con_id = "apb_pclk"}, - { .dev_id = "80074000.serial", .con_id = "apb_pclk"}, - { .dev_id = "imx28-dma-apbx", }, - { .dev_id = "80024000.dma-apbx", }, -}; - -static struct clk_lookup ssp0_lookups[] = { - { .dev_id = "imx28-mmc.0", }, - { .dev_id = "80010000.ssp", }, -}; - -static struct clk_lookup ssp1_lookups[] = { - { .dev_id = "imx28-mmc.1", }, - { .dev_id = "80012000.ssp", }, -}; - -static struct clk_lookup ssp2_lookups[] = { - { .dev_id = "imx28-mmc.2", }, - { .dev_id = "80014000.ssp", }, -}; - -static struct clk_lookup ssp3_lookups[] = { - { .dev_id = "imx28-mmc.3", }, - { .dev_id = "80016000.ssp", }, -}; - -static struct clk_lookup lcdif_lookups[] = { - { .dev_id = "imx28-fb", }, - { .dev_id = "80030000.lcdif", }, -}; - -static struct clk_lookup gpmi_lookups[] = { - { .dev_id = "imx28-gpmi-nand", }, - { .dev_id = "8000c000.gpmi-nand", }, -}; - -static struct clk_lookup fec_lookups[] = { - { .dev_id = "imx28-fec.0", }, - { .dev_id = "imx28-fec.1", }, - { .dev_id = "800f0000.ethernet", }, - { .dev_id = "800f4000.ethernet", }, -}; - -static struct clk_lookup can0_lookups[] = { - { .dev_id = "flexcan.0", }, - { .dev_id = "80032000.can", }, -}; - -static struct clk_lookup can1_lookups[] = { - { .dev_id = "flexcan.1", }, - { .dev_id = "80034000.can", }, -}; - -static struct clk_lookup saif0_lookups[] = { - { .dev_id = "mxs-saif.0", }, - { .dev_id = "80042000.saif", }, -}; - -static struct clk_lookup saif1_lookups[] = { - { .dev_id = "mxs-saif.1", }, - { .dev_id = "80046000.saif", }, -}; - static const char *sel_cpu[] __initconst = { "ref_cpu", "ref_xtal", }; static const char *sel_io0[] __initconst = { "ref_io0", "ref_xtal", }; static const char *sel_io1[] __initconst = { "ref_io1", "ref_xtal", }; @@ -228,6 +145,7 @@ enum imx28_clk { }; static struct clk *clks[clk_max]; +static struct clk_onecell_data clk_data; static enum imx28_clk clks_init_on[] __initdata = { cpu, hbus, xbus, emi, uart, @@ -235,6 +153,7 @@ static enum imx28_clk clks_init_on[] __initdata = { int __init mx28_clocks_init(void) { + struct device_node *np; int i; clk_misc_init(); @@ -312,27 +231,15 @@ int __init mx28_clocks_init(void) return PTR_ERR(clks[i]); } + np = of_find_compatible_node(NULL, NULL, "fsl,imx28-clkctrl"); + if (np) { + clk_data.clks = clks; + clk_data.clk_num = ARRAY_SIZE(clks); + of_clk_add_provider(np, of_clk_src_onecell_get, &clk_data); + } + clk_register_clkdev(clks[clk32k], NULL, "timrot"); clk_register_clkdev(clks[enet_out], NULL, "enet_out"); - clk_register_clkdev(clks[pwm], NULL, "80064000.pwm"); - clk_register_clkdevs(clks[hbus], hbus_lookups, ARRAY_SIZE(hbus_lookups)); - clk_register_clkdevs(clks[xbus], xbus_lookups, ARRAY_SIZE(xbus_lookups)); - clk_register_clkdevs(clks[uart], uart_lookups, ARRAY_SIZE(uart_lookups)); - clk_register_clkdevs(clks[ssp0], ssp0_lookups, ARRAY_SIZE(ssp0_lookups)); - clk_register_clkdevs(clks[ssp1], ssp1_lookups, ARRAY_SIZE(ssp1_lookups)); - clk_register_clkdevs(clks[ssp2], ssp2_lookups, ARRAY_SIZE(ssp2_lookups)); - clk_register_clkdevs(clks[ssp3], ssp3_lookups, ARRAY_SIZE(ssp3_lookups)); - clk_register_clkdevs(clks[gpmi], gpmi_lookups, ARRAY_SIZE(gpmi_lookups)); - clk_register_clkdevs(clks[saif0], saif0_lookups, ARRAY_SIZE(saif0_lookups)); - clk_register_clkdevs(clks[saif1], saif1_lookups, ARRAY_SIZE(saif1_lookups)); - clk_register_clkdevs(clks[lcdif], lcdif_lookups, ARRAY_SIZE(lcdif_lookups)); - clk_register_clkdevs(clks[fec], fec_lookups, ARRAY_SIZE(fec_lookups)); - clk_register_clkdevs(clks[can0], can0_lookups, ARRAY_SIZE(can0_lookups)); - clk_register_clkdevs(clks[can1], can1_lookups, ARRAY_SIZE(can1_lookups)); - clk_register_clkdev(clks[usb0_pwr], NULL, "8007c000.usbphy"); - clk_register_clkdev(clks[usb1_pwr], NULL, "8007e000.usbphy"); - clk_register_clkdev(clks[usb0], NULL, "80080000.usb"); - clk_register_clkdev(clks[usb1], NULL, "80090000.usb"); for (i = 0; i < ARRAY_SIZE(clks_init_on); i++) clk_prepare_enable(clks[clks_init_on[i]]); -- cgit v1.2.3 From 53f9443da63db38212e784b0aa205881168757aa Mon Sep 17 00:00:00 2001 From: Shawn Guo Date: Wed, 22 Aug 2012 21:36:30 +0800 Subject: clk: mxs: replace imx23 clk_register_clkdev with clock DT lookup It really becomes a maintenance issue that every time a device needs to look up (clk_get) a clock we have to patch kernel clock file to call clk_register_clkdev for that clock. Since clock DT support which is meant to resolve clock lookup in device tree is in place, the patch moves imx23 client devices' clock lookup over to device tree, so that any new lookup to be added at later time can just get done in DT instead of kernel. Signed-off-by: Shawn Guo --- .../devicetree/bindings/clock/imx23-clock.txt | 76 ++++++++++++++++++++++ arch/arm/boot/dts/imx23.dtsi | 16 ++++- drivers/clk/mxs/clk-imx23.c | 55 +++------------- 3 files changed, 100 insertions(+), 47 deletions(-) create mode 100644 Documentation/devicetree/bindings/clock/imx23-clock.txt (limited to 'drivers') diff --git a/Documentation/devicetree/bindings/clock/imx23-clock.txt b/Documentation/devicetree/bindings/clock/imx23-clock.txt new file mode 100644 index 000000000000..a0b867ef8d96 --- /dev/null +++ b/Documentation/devicetree/bindings/clock/imx23-clock.txt @@ -0,0 +1,76 @@ +* Clock bindings for Freescale i.MX23 + +Required properties: +- compatible: Should be "fsl,imx23-clkctrl" +- reg: Address and length of the register set +- #clock-cells: Should be <1> + +The clock consumer should specify the desired clock by having the clock +ID in its "clocks" phandle cell. The following is a full list of i.MX23 +clocks and IDs. + + Clock ID + ------------------ + ref_xtal 0 + pll 1 + ref_cpu 2 + ref_emi 3 + ref_pix 4 + ref_io 5 + saif_sel 6 + lcdif_sel 7 + gpmi_sel 8 + ssp_sel 9 + emi_sel 10 + cpu 11 + etm_sel 12 + cpu_pll 13 + cpu_xtal 14 + hbus 15 + xbus 16 + lcdif_div 17 + ssp_div 18 + gpmi_div 19 + emi_pll 20 + emi_xtal 21 + etm_div 22 + saif_div 23 + clk32k_div 24 + rtc 25 + adc 26 + spdif_div 27 + clk32k 28 + dri 29 + pwm 30 + filt 31 + uart 32 + ssp 33 + gpmi 34 + spdif 35 + emi 36 + saif 37 + lcdif 38 + etm 39 + usb 40 + usb_pwr 41 + +Examples: + +clks: clkctrl@80040000 { + compatible = "fsl,imx23-clkctrl"; + reg = <0x80040000 0x2000>; + #clock-cells = <1>; + clock-output-names = + ... + "uart", /* 32 */ + ... + "end_of_list"; +}; + +auart0: serial@8006c000 { + compatible = "fsl,imx23-auart"; + reg = <0x8006c000 0x2000>; + interrupts = <24 25 23>; + clocks = <&clks 32>; + status = "disabled"; +}; diff --git a/arch/arm/boot/dts/imx23.dtsi b/arch/arm/boot/dts/imx23.dtsi index b00f3cfb3bf8..9d0e803e3eca 100644 --- a/arch/arm/boot/dts/imx23.dtsi +++ b/arch/arm/boot/dts/imx23.dtsi @@ -52,6 +52,7 @@ dma-apbh@80004000 { compatible = "fsl,imx23-dma-apbh"; reg = <0x80004000 0x2000>; + clocks = <&clks 15>; }; ecc@80008000 { @@ -67,6 +68,7 @@ reg-names = "gpmi-nand", "bch"; interrupts = <13>, <56>; interrupt-names = "gpmi-dma", "bch"; + clocks = <&clks 34>; fsl,gpmi-dma-channel = <4>; status = "disabled"; }; @@ -74,6 +76,7 @@ ssp0: ssp@80010000 { reg = <0x80010000 0x2000>; interrupts = <15 14>; + clocks = <&clks 33>; fsl,ssp-dma-channel = <1>; status = "disabled"; }; @@ -290,6 +293,7 @@ dma-apbx@80024000 { compatible = "fsl,imx23-dma-apbx"; reg = <0x80024000 0x2000>; + clocks = <&clks 16>; }; dcp@80028000 { @@ -316,12 +320,14 @@ compatible = "fsl,imx23-lcdif"; reg = <0x80030000 2000>; interrupts = <46 45>; + clocks = <&clks 38>; status = "disabled"; }; ssp1: ssp@80034000 { reg = <0x80034000 0x2000>; interrupts = <2 20>; + clocks = <&clks 33>; fsl,ssp-dma-channel = <2>; status = "disabled"; }; @@ -339,9 +345,10 @@ reg = <0x80040000 0x40000>; ranges; - clkctl@80040000 { + clks: clkctrl@80040000 { + compatible = "fsl,imx23-clkctrl"; reg = <0x80040000 0x2000>; - status = "disabled"; + #clock-cells = <1>; }; saif0: saif@80042000 { @@ -393,6 +400,7 @@ pwm: pwm@80064000 { compatible = "fsl,imx23-pwm"; reg = <0x80064000 0x2000>; + clocks = <&clks 30>; #pwm-cells = <2>; fsl,pwm-number = <5>; status = "disabled"; @@ -407,6 +415,7 @@ compatible = "fsl,imx23-auart"; reg = <0x8006c000 0x2000>; interrupts = <24 25 23>; + clocks = <&clks 32>; status = "disabled"; }; @@ -414,6 +423,7 @@ compatible = "fsl,imx23-auart"; reg = <0x8006e000 0x2000>; interrupts = <59 60 58>; + clocks = <&clks 32>; status = "disabled"; }; @@ -421,6 +431,8 @@ compatible = "arm,pl011", "arm,primecell"; reg = <0x80070000 0x2000>; interrupts = <0>; + clocks = <&clks 32>, <&clks 16>; + clock-names = "uart", "apb_pclk"; status = "disabled"; }; diff --git a/drivers/clk/mxs/clk-imx23.c b/drivers/clk/mxs/clk-imx23.c index 844043ad0fe4..9f6d15546cbe 100644 --- a/drivers/clk/mxs/clk-imx23.c +++ b/drivers/clk/mxs/clk-imx23.c @@ -14,6 +14,7 @@ #include #include #include +#include #include #include #include "clk.h" @@ -71,44 +72,6 @@ static void __init clk_misc_init(void) __mxs_setl(30 << BP_FRAC_IOFRAC, FRAC); } -static struct clk_lookup uart_lookups[] = { - { .dev_id = "duart", }, - { .dev_id = "mxs-auart.0", }, - { .dev_id = "mxs-auart.1", }, - { .dev_id = "8006c000.serial", }, - { .dev_id = "8006e000.serial", }, - { .dev_id = "80070000.serial", }, -}; - -static struct clk_lookup hbus_lookups[] = { - { .dev_id = "imx23-dma-apbh", }, - { .dev_id = "80004000.dma-apbh", }, -}; - -static struct clk_lookup xbus_lookups[] = { - { .dev_id = "duart", .con_id = "apb_pclk"}, - { .dev_id = "80070000.serial", .con_id = "apb_pclk"}, - { .dev_id = "imx23-dma-apbx", }, - { .dev_id = "80024000.dma-apbx", }, -}; - -static struct clk_lookup ssp_lookups[] = { - { .dev_id = "imx23-mmc.0", }, - { .dev_id = "imx23-mmc.1", }, - { .dev_id = "80010000.ssp", }, - { .dev_id = "80034000.ssp", }, -}; - -static struct clk_lookup lcdif_lookups[] = { - { .dev_id = "imx23-fb", }, - { .dev_id = "80030000.lcdif", }, -}; - -static struct clk_lookup gpmi_lookups[] = { - { .dev_id = "imx23-gpmi-nand", }, - { .dev_id = "8000c000.gpmi-nand", }, -}; - static const char *sel_pll[] __initconst = { "pll", "ref_xtal", }; static const char *sel_cpu[] __initconst = { "ref_cpu", "ref_xtal", }; static const char *sel_pix[] __initconst = { "ref_pix", "ref_xtal", }; @@ -127,6 +90,7 @@ enum imx23_clk { }; static struct clk *clks[clk_max]; +static struct clk_onecell_data clk_data; static enum imx23_clk clks_init_on[] __initdata = { cpu, hbus, xbus, emi, uart, @@ -134,6 +98,7 @@ static enum imx23_clk clks_init_on[] __initdata = { int __init mx23_clocks_init(void) { + struct device_node *np; int i; clk_misc_init(); @@ -188,14 +153,14 @@ int __init mx23_clocks_init(void) return PTR_ERR(clks[i]); } + np = of_find_compatible_node(NULL, NULL, "fsl,imx23-clkctrl"); + if (np) { + clk_data.clks = clks; + clk_data.clk_num = ARRAY_SIZE(clks); + of_clk_add_provider(np, of_clk_src_onecell_get, &clk_data); + } + clk_register_clkdev(clks[clk32k], NULL, "timrot"); - clk_register_clkdev(clks[pwm], NULL, "80064000.pwm"); - clk_register_clkdevs(clks[hbus], hbus_lookups, ARRAY_SIZE(hbus_lookups)); - clk_register_clkdevs(clks[xbus], xbus_lookups, ARRAY_SIZE(xbus_lookups)); - clk_register_clkdevs(clks[uart], uart_lookups, ARRAY_SIZE(uart_lookups)); - clk_register_clkdevs(clks[ssp], ssp_lookups, ARRAY_SIZE(ssp_lookups)); - clk_register_clkdevs(clks[gpmi], gpmi_lookups, ARRAY_SIZE(gpmi_lookups)); - clk_register_clkdevs(clks[lcdif], lcdif_lookups, ARRAY_SIZE(lcdif_lookups)); for (i = 0; i < ARRAY_SIZE(clks_init_on); i++) clk_prepare_enable(clks[clks_init_on[i]]); -- cgit v1.2.3