1/* 2 * linux/arch/arm/mach-pxa/clock-pxa3xx.c 3 * 4 * This program is free software; you can redistribute it and/or modify 5 * it under the terms of the GNU General Public License version 2 as 6 * published by the Free Software Foundation. 7 */ 8 9#include <linux/module.h> 10#include <linux/kernel.h> 11#include <linux/init.h> 12#include <linux/io.h> 13#include <linux/syscore_ops.h> 14 15#include <mach/smemc.h> 16#include <mach/pxa3xx-regs.h> 17 18#include "clock.h" 19 20/* Crystal clock: 13MHz */ 21#define BASE_CLK 13000000 22 23/* Ring Oscillator Clock: 60MHz */ 24#define RO_CLK 60000000 25 26#define ACCR_D0CS (1 << 26) 27#define ACCR_PCCE (1 << 11) 28 29/* crystal frequency to HSIO bus frequency multiplier (HSS) */ 30static unsigned char hss_mult[4] = { 8, 12, 16, 24 }; 31 32/* 33 * Get the clock frequency as reflected by CCSR and the turbo flag. 34 * We assume these values have been applied via a fcs. 35 * If info is not 0 we also display the current settings. 36 */ 37unsigned int pxa3xx_get_clk_frequency_khz(int info) 38{ 39 unsigned long acsr, xclkcfg; 40 unsigned int t, xl, xn, hss, ro, XL, XN, CLK, HSS; 41 42 /* Read XCLKCFG register turbo bit */ 43 __asm__ __volatile__("mrc\tp14, 0, %0, c6, c0, 0" : "=r"(xclkcfg)); 44 t = xclkcfg & 0x1; 45 46 acsr = ACSR; 47 48 xl = acsr & 0x1f; 49 xn = (acsr >> 8) & 0x7; 50 hss = (acsr >> 14) & 0x3; 51 52 XL = xl * BASE_CLK; 53 XN = xn * XL; 54 55 ro = acsr & ACCR_D0CS; 56 57 CLK = (ro) ? RO_CLK : ((t) ? XN : XL); 58 HSS = (ro) ? RO_CLK : hss_mult[hss] * BASE_CLK; 59 60 if (info) { 61 pr_info("RO Mode clock: %d.%02dMHz (%sactive)\n", 62 RO_CLK / 1000000, (RO_CLK % 1000000) / 10000, 63 (ro) ? "" : "in"); 64 pr_info("Run Mode clock: %d.%02dMHz (*%d)\n", 65 XL / 1000000, (XL % 1000000) / 10000, xl); 66 pr_info("Turbo Mode clock: %d.%02dMHz (*%d, %sactive)\n", 67 XN / 1000000, (XN % 1000000) / 10000, xn, 68 (t) ? "" : "in"); 69 pr_info("HSIO bus clock: %d.%02dMHz\n", 70 HSS / 1000000, (HSS % 1000000) / 10000); 71 } 72 73 return CLK / 1000; 74} 75 76/* 77 * Return the current AC97 clock frequency. 78 */ 79static unsigned long clk_pxa3xx_ac97_getrate(struct clk *clk) 80{ 81 unsigned long rate = 312000000; 82 unsigned long ac97_div; 83 84 ac97_div = AC97_DIV; 85 86 /* This may loose precision for some rates but won't for the 87 * standard 24.576MHz. 88 */ 89 rate /= (ac97_div >> 12) & 0x7fff; 90 rate *= (ac97_div & 0xfff); 91 92 return rate; 93} 94 95/* 96 * Return the current HSIO bus clock frequency 97 */ 98static unsigned long clk_pxa3xx_hsio_getrate(struct clk *clk) 99{ 100 unsigned long acsr; 101 unsigned int hss, hsio_clk; 102 103 acsr = ACSR; 104 105 hss = (acsr >> 14) & 0x3; 106 hsio_clk = (acsr & ACCR_D0CS) ? RO_CLK : hss_mult[hss] * BASE_CLK; 107 108 return hsio_clk; 109} 110 111/* crystal frequency to static memory controller multiplier (SMCFS) */ 112static unsigned int smcfs_mult[8] = { 6, 0, 8, 0, 0, 16, }; 113static unsigned int df_clkdiv[4] = { 1, 2, 4, 1 }; 114 115static unsigned long clk_pxa3xx_smemc_getrate(struct clk *clk) 116{ 117 unsigned long acsr = ACSR; 118 unsigned long memclkcfg = __raw_readl(MEMCLKCFG); 119 120 return BASE_CLK * smcfs_mult[(acsr >> 23) & 0x7] / 121 df_clkdiv[(memclkcfg >> 16) & 0x3]; 122} 123 124void clk_pxa3xx_cken_enable(struct clk *clk) 125{ 126 unsigned long mask = 1ul << (clk->cken & 0x1f); 127 128 if (clk->cken < 32) 129 CKENA |= mask; 130 else if (clk->cken < 64) 131 CKENB |= mask; 132 else 133 CKENC |= mask; 134} 135 136void clk_pxa3xx_cken_disable(struct clk *clk) 137{ 138 unsigned long mask = 1ul << (clk->cken & 0x1f); 139 140 if (clk->cken < 32) 141 CKENA &= ~mask; 142 else if (clk->cken < 64) 143 CKENB &= ~mask; 144 else 145 CKENC &= ~mask; 146} 147 148const struct clkops clk_pxa3xx_cken_ops = { 149 .enable = clk_pxa3xx_cken_enable, 150 .disable = clk_pxa3xx_cken_disable, 151}; 152 153const struct clkops clk_pxa3xx_hsio_ops = { 154 .enable = clk_pxa3xx_cken_enable, 155 .disable = clk_pxa3xx_cken_disable, 156 .getrate = clk_pxa3xx_hsio_getrate, 157}; 158 159const struct clkops clk_pxa3xx_ac97_ops = { 160 .enable = clk_pxa3xx_cken_enable, 161 .disable = clk_pxa3xx_cken_disable, 162 .getrate = clk_pxa3xx_ac97_getrate, 163}; 164 165const struct clkops clk_pxa3xx_smemc_ops = { 166 .enable = clk_pxa3xx_cken_enable, 167 .disable = clk_pxa3xx_cken_disable, 168 .getrate = clk_pxa3xx_smemc_getrate, 169}; 170 171static void clk_pout_enable(struct clk *clk) 172{ 173 OSCC |= OSCC_PEN; 174} 175 176static void clk_pout_disable(struct clk *clk) 177{ 178 OSCC &= ~OSCC_PEN; 179} 180 181const struct clkops clk_pxa3xx_pout_ops = { 182 .enable = clk_pout_enable, 183 .disable = clk_pout_disable, 184}; 185 186#ifdef CONFIG_PM 187static uint32_t cken[2]; 188static uint32_t accr; 189 190static int pxa3xx_clock_suspend(void) 191{ 192 cken[0] = CKENA; 193 cken[1] = CKENB; 194 accr = ACCR; 195 return 0; 196} 197 198static void pxa3xx_clock_resume(void) 199{ 200 ACCR = accr; 201 CKENA = cken[0]; 202 CKENB = cken[1]; 203} 204#else 205#define pxa3xx_clock_suspend NULL 206#define pxa3xx_clock_resume NULL 207#endif 208 209struct syscore_ops pxa3xx_clock_syscore_ops = { 210 .suspend = pxa3xx_clock_suspend, 211 .resume = pxa3xx_clock_resume, 212}; 213