10ad6125bSBoris BREZILLON /* 20ad6125bSBoris BREZILLON * Copyright (C) 2013 Boris BREZILLON <b.brezillon@overkiz.com> 30ad6125bSBoris BREZILLON * 40ad6125bSBoris BREZILLON * This program is free software; you can redistribute it and/or modify 50ad6125bSBoris BREZILLON * it under the terms of the GNU General Public License as published by 60ad6125bSBoris BREZILLON * the Free Software Foundation; either version 2 of the License, or 70ad6125bSBoris BREZILLON * (at your option) any later version. 80ad6125bSBoris BREZILLON * 90ad6125bSBoris BREZILLON */ 100ad6125bSBoris BREZILLON 110ad6125bSBoris BREZILLON #include <linux/clk-provider.h> 120ad6125bSBoris BREZILLON #include <linux/clkdev.h> 130ad6125bSBoris BREZILLON #include <linux/clk/at91_pmc.h> 140ad6125bSBoris BREZILLON #include <linux/of.h> 15863a81c3SBoris Brezillon #include <linux/mfd/syscon.h> 16b3b02eacSAlexandre Belloni #include <linux/platform_device.h> 171bdf0232SBoris Brezillon #include <linux/regmap.h> 18b3b02eacSAlexandre Belloni #include <linux/syscore_ops.h> 190ad6125bSBoris BREZILLON 200ad6125bSBoris BREZILLON #include <asm/proc-fns.h> 210ad6125bSBoris BREZILLON 220ad6125bSBoris BREZILLON #include "pmc.h" 230ad6125bSBoris BREZILLON 24b3b02eacSAlexandre Belloni #define PMC_MAX_IDS 128 25b3b02eacSAlexandre Belloni 260ad6125bSBoris BREZILLON int of_at91_get_clk_range(struct device_node *np, const char *propname, 270ad6125bSBoris BREZILLON struct clk_range *range) 280ad6125bSBoris BREZILLON { 290ad6125bSBoris BREZILLON u32 min, max; 300ad6125bSBoris BREZILLON int ret; 310ad6125bSBoris BREZILLON 320ad6125bSBoris BREZILLON ret = of_property_read_u32_index(np, propname, 0, &min); 330ad6125bSBoris BREZILLON if (ret) 340ad6125bSBoris BREZILLON return ret; 350ad6125bSBoris BREZILLON 360ad6125bSBoris BREZILLON ret = of_property_read_u32_index(np, propname, 1, &max); 370ad6125bSBoris BREZILLON if (ret) 380ad6125bSBoris BREZILLON return ret; 390ad6125bSBoris BREZILLON 400ad6125bSBoris BREZILLON if (range) { 410ad6125bSBoris BREZILLON range->min = min; 420ad6125bSBoris BREZILLON range->max = max; 430ad6125bSBoris BREZILLON } 440ad6125bSBoris BREZILLON 450ad6125bSBoris BREZILLON return 0; 460ad6125bSBoris BREZILLON } 470ad6125bSBoris BREZILLON EXPORT_SYMBOL_GPL(of_at91_get_clk_range); 48b3b02eacSAlexandre Belloni 49b3b02eacSAlexandre Belloni #ifdef CONFIG_PM 50b3b02eacSAlexandre Belloni static struct regmap *pmcreg; 51b3b02eacSAlexandre Belloni 52b3b02eacSAlexandre Belloni static u8 registered_ids[PMC_MAX_IDS]; 53b3b02eacSAlexandre Belloni 54b3b02eacSAlexandre Belloni static struct 55b3b02eacSAlexandre Belloni { 56b3b02eacSAlexandre Belloni u32 scsr; 57b3b02eacSAlexandre Belloni u32 pcsr0; 58b3b02eacSAlexandre Belloni u32 uckr; 59b3b02eacSAlexandre Belloni u32 mor; 60b3b02eacSAlexandre Belloni u32 mcfr; 61b3b02eacSAlexandre Belloni u32 pllar; 62b3b02eacSAlexandre Belloni u32 mckr; 63b3b02eacSAlexandre Belloni u32 usb; 64b3b02eacSAlexandre Belloni u32 imr; 65b3b02eacSAlexandre Belloni u32 pcsr1; 66b3b02eacSAlexandre Belloni u32 pcr[PMC_MAX_IDS]; 67b3b02eacSAlexandre Belloni u32 audio_pll0; 68b3b02eacSAlexandre Belloni u32 audio_pll1; 69b3b02eacSAlexandre Belloni } pmc_cache; 70b3b02eacSAlexandre Belloni 71b3b02eacSAlexandre Belloni void pmc_register_id(u8 id) 72b3b02eacSAlexandre Belloni { 73b3b02eacSAlexandre Belloni int i; 74b3b02eacSAlexandre Belloni 75b3b02eacSAlexandre Belloni for (i = 0; i < PMC_MAX_IDS; i++) { 76b3b02eacSAlexandre Belloni if (registered_ids[i] == 0) { 77b3b02eacSAlexandre Belloni registered_ids[i] = id; 78b3b02eacSAlexandre Belloni break; 79b3b02eacSAlexandre Belloni } 80b3b02eacSAlexandre Belloni if (registered_ids[i] == id) 81b3b02eacSAlexandre Belloni break; 82b3b02eacSAlexandre Belloni } 83b3b02eacSAlexandre Belloni } 84b3b02eacSAlexandre Belloni 85b3b02eacSAlexandre Belloni static int pmc_suspend(void) 86b3b02eacSAlexandre Belloni { 87b3b02eacSAlexandre Belloni int i; 88b3b02eacSAlexandre Belloni 89b3b02eacSAlexandre Belloni regmap_read(pmcreg, AT91_PMC_IMR, &pmc_cache.scsr); 90b3b02eacSAlexandre Belloni regmap_read(pmcreg, AT91_PMC_PCSR, &pmc_cache.pcsr0); 91b3b02eacSAlexandre Belloni regmap_read(pmcreg, AT91_CKGR_UCKR, &pmc_cache.uckr); 92b3b02eacSAlexandre Belloni regmap_read(pmcreg, AT91_CKGR_MOR, &pmc_cache.mor); 93b3b02eacSAlexandre Belloni regmap_read(pmcreg, AT91_CKGR_MCFR, &pmc_cache.mcfr); 94b3b02eacSAlexandre Belloni regmap_read(pmcreg, AT91_CKGR_PLLAR, &pmc_cache.pllar); 95b3b02eacSAlexandre Belloni regmap_read(pmcreg, AT91_PMC_MCKR, &pmc_cache.mckr); 96b3b02eacSAlexandre Belloni regmap_read(pmcreg, AT91_PMC_USB, &pmc_cache.usb); 97b3b02eacSAlexandre Belloni regmap_read(pmcreg, AT91_PMC_IMR, &pmc_cache.imr); 98b3b02eacSAlexandre Belloni regmap_read(pmcreg, AT91_PMC_PCSR1, &pmc_cache.pcsr1); 99b3b02eacSAlexandre Belloni 100b3b02eacSAlexandre Belloni for (i = 0; registered_ids[i]; i++) { 101b3b02eacSAlexandre Belloni regmap_write(pmcreg, AT91_PMC_PCR, 102b3b02eacSAlexandre Belloni (registered_ids[i] & AT91_PMC_PCR_PID_MASK)); 103b3b02eacSAlexandre Belloni regmap_read(pmcreg, AT91_PMC_PCR, 104b3b02eacSAlexandre Belloni &pmc_cache.pcr[registered_ids[i]]); 105b3b02eacSAlexandre Belloni } 106b3b02eacSAlexandre Belloni 107b3b02eacSAlexandre Belloni return 0; 108b3b02eacSAlexandre Belloni } 109b3b02eacSAlexandre Belloni 110960e1c4dSRomain Izard static bool pmc_ready(unsigned int mask) 111960e1c4dSRomain Izard { 112960e1c4dSRomain Izard unsigned int status; 113960e1c4dSRomain Izard 114960e1c4dSRomain Izard regmap_read(pmcreg, AT91_PMC_SR, &status); 115960e1c4dSRomain Izard 116960e1c4dSRomain Izard return ((status & mask) == mask) ? 1 : 0; 117960e1c4dSRomain Izard } 118960e1c4dSRomain Izard 119b3b02eacSAlexandre Belloni static void pmc_resume(void) 120b3b02eacSAlexandre Belloni { 121960e1c4dSRomain Izard int i; 122b3b02eacSAlexandre Belloni u32 tmp; 123960e1c4dSRomain Izard u32 mask = AT91_PMC_MCKRDY | AT91_PMC_LOCKA; 124b3b02eacSAlexandre Belloni 125b3b02eacSAlexandre Belloni regmap_read(pmcreg, AT91_PMC_MCKR, &tmp); 126b3b02eacSAlexandre Belloni if (pmc_cache.mckr != tmp) 127b3b02eacSAlexandre Belloni pr_warn("MCKR was not configured properly by the firmware\n"); 128b3b02eacSAlexandre Belloni regmap_read(pmcreg, AT91_CKGR_PLLAR, &tmp); 129b3b02eacSAlexandre Belloni if (pmc_cache.pllar != tmp) 130b3b02eacSAlexandre Belloni pr_warn("PLLAR was not configured properly by the firmware\n"); 131b3b02eacSAlexandre Belloni 132b3b02eacSAlexandre Belloni regmap_write(pmcreg, AT91_PMC_IMR, pmc_cache.scsr); 133b3b02eacSAlexandre Belloni regmap_write(pmcreg, AT91_PMC_PCER, pmc_cache.pcsr0); 134b3b02eacSAlexandre Belloni regmap_write(pmcreg, AT91_CKGR_UCKR, pmc_cache.uckr); 135b3b02eacSAlexandre Belloni regmap_write(pmcreg, AT91_CKGR_MOR, pmc_cache.mor); 136b3b02eacSAlexandre Belloni regmap_write(pmcreg, AT91_CKGR_MCFR, pmc_cache.mcfr); 137b3b02eacSAlexandre Belloni regmap_write(pmcreg, AT91_PMC_USB, pmc_cache.usb); 138b3b02eacSAlexandre Belloni regmap_write(pmcreg, AT91_PMC_IMR, pmc_cache.imr); 139b3b02eacSAlexandre Belloni regmap_write(pmcreg, AT91_PMC_PCER1, pmc_cache.pcsr1); 140b3b02eacSAlexandre Belloni 141b3b02eacSAlexandre Belloni for (i = 0; registered_ids[i]; i++) { 142b3b02eacSAlexandre Belloni regmap_write(pmcreg, AT91_PMC_PCR, 143b3b02eacSAlexandre Belloni pmc_cache.pcr[registered_ids[i]] | 144b3b02eacSAlexandre Belloni AT91_PMC_PCR_CMD); 145b3b02eacSAlexandre Belloni } 146b3b02eacSAlexandre Belloni 147960e1c4dSRomain Izard if (pmc_cache.uckr & AT91_PMC_UPLLEN) 148960e1c4dSRomain Izard mask |= AT91_PMC_LOCKU; 149960e1c4dSRomain Izard 150960e1c4dSRomain Izard while (!pmc_ready(mask)) 151960e1c4dSRomain Izard cpu_relax(); 152b3b02eacSAlexandre Belloni } 153b3b02eacSAlexandre Belloni 154b3b02eacSAlexandre Belloni static struct syscore_ops pmc_syscore_ops = { 155b3b02eacSAlexandre Belloni .suspend = pmc_suspend, 156b3b02eacSAlexandre Belloni .resume = pmc_resume, 157b3b02eacSAlexandre Belloni }; 158b3b02eacSAlexandre Belloni 159b3b02eacSAlexandre Belloni static const struct of_device_id sama5d2_pmc_dt_ids[] = { 160b3b02eacSAlexandre Belloni { .compatible = "atmel,sama5d2-pmc" }, 161b3b02eacSAlexandre Belloni { /* sentinel */ } 162b3b02eacSAlexandre Belloni }; 163b3b02eacSAlexandre Belloni 164b3b02eacSAlexandre Belloni static int __init pmc_register_ops(void) 165b3b02eacSAlexandre Belloni { 166b3b02eacSAlexandre Belloni struct device_node *np; 167b3b02eacSAlexandre Belloni 168b3b02eacSAlexandre Belloni np = of_find_matching_node(NULL, sama5d2_pmc_dt_ids); 169b3b02eacSAlexandre Belloni 170b3b02eacSAlexandre Belloni pmcreg = syscon_node_to_regmap(np); 171b3b02eacSAlexandre Belloni if (IS_ERR(pmcreg)) 172b3b02eacSAlexandre Belloni return PTR_ERR(pmcreg); 173b3b02eacSAlexandre Belloni 174b3b02eacSAlexandre Belloni register_syscore_ops(&pmc_syscore_ops); 175b3b02eacSAlexandre Belloni 176b3b02eacSAlexandre Belloni return 0; 177b3b02eacSAlexandre Belloni } 178b3b02eacSAlexandre Belloni /* This has to happen before arch_initcall because of the tcb_clksrc driver */ 179b3b02eacSAlexandre Belloni postcore_initcall(pmc_register_ops); 180b3b02eacSAlexandre Belloni #endif 181