- Main Page
- Related Pages
- Data Structures
- Files

# pm_at32ap7000.c

Go to the documentation of this file.

    00001 /*This file has been prepared for Doxygen automatic documentation generation.*/
    00016 /* Copyright (C) 2006-2008, Atmel Corporation All rights reserved.
    00017  *
    00018  * Redistribution and use in source and binary forms, with or without
    00019  * modification, are permitted provided that the following conditions are met:
    00020  *
    00021  * 1. Redistributions of source code must retain the above copyright notice,
    00022  * this list of conditions and the following disclaimer.
    00023  *
    00024  * 2. Redistributions in binary form must reproduce the above copyright notice,
    00025  * this list of conditions and the following disclaimer in the documentation
    00026  * and/or other materials provided with the distribution.
    00027  *
    00028  * 3. The name of ATMEL may not be used to endorse or promote products derived
    00029  * from this software without specific prior written permission.
    00030  *
    00031  * THIS SOFTWARE IS PROVIDED BY ATMEL ``AS IS'' AND ANY EXPRESS OR IMPLIED
    00032  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
    00033  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE EXPRESSLY AND
    00034  * SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT,
    00035  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
    00036  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
    00037  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
    00038  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
    00039  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
    00040  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
    00041  */
    00042
    00043 #include "pm_at32ap7000.h"
    00044 #include "board.h"
    00045 #include "ap7_errno.h"
    00046 #include "compiler.h"
    00047
    00048 int pm_reset(void)
    00049 {
    00050   volatile avr32_pm_t *pm = &AVR32_PM;
    00051   unsigned int status = 0;
    00052   int disable_module_mask = 0xFFFFffff;
    00053
    00054   pm_set_mclk_source(PM_OSC0);
    00055
    00056   pm->cksel = 0x00000000;
    00057   status |= pm_wait_for_status(AVR32_PM_ISR_CKRDY);
    00058
    00059   pm->cpumask = disable_module_mask;
    00060   status |= pm_wait_for_status(AVR32_PM_ISR_MSKRDY);
    00061
    00062   pm->hsbmask = disable_module_mask;
    00063   status |= pm_wait_for_status(AVR32_PM_ISR_MSKRDY);
    00064
    00065   pm->pbamask = disable_module_mask;
    00066   status |= pm_wait_for_status(AVR32_PM_ISR_MSKRDY);
    00067
    00068   pm->pbbmask = disable_module_mask;
    00069   status |= pm_wait_for_status(AVR32_PM_ISR_MSKRDY);
    00070
    00071   pm->idr = 0x7f; /* disable all interrupts*/
    00072   pm->icr = 0x7f; /* clear all interrupts */
    00073
    00074   return status;
    00075 }
    00076
    00077
    00078 unsigned int pm_get_reset_cause(void)
    00079 {
    00080   volatile avr32_pm_t *pm = &AVR32_PM;
    00081
    00082   return pm->rcause;
    00083 }
    00084
    00085
    00086 int pm_start_osc(const pm_osc_opt_t *opt)
    00087 {
    00088   return PM_NOT_SUPPORTED;
    00089 }
    00090
    00091
    00092 int pm_stop_osc(int osc_id)
    00093 {
    00094   return PM_NOT_SUPPORTED;
    00095 }
    00096
    00097
    00098 int pm_start_pll(pm_pll_opt_t *opt)
    00099 {
    00100   volatile avr32_pm_t *pm = &AVR32_PM;
    00101   unsigned int pllreg;
    00102   int retval;
    00103
    00104   /* Ensure that mclk is not driven by PLL */
    00105   if ((opt->pll_id == 0) && (pm_get_mclk_source() == PM_PLL0))
    00106     pm_set_mclk_source(PM_OSC0);
    00107
    00108   if ((opt->mul == 0) | (opt->div == 0) | (opt->osc_id > 1))
    00109     return INVALID_ARGUMENT;
    00110
    00111   pllreg = opt->count << AVR32_PM_PLLCOUNT_OFFSET
    00112            | (opt->mul - 1) << AVR32_PM_PLLMUL_OFFSET
    00113            | (opt->div - 1) << AVR32_PM_PLLDIV_OFFSET
    00114            | 4 << AVR32_PM_PLLOPT_OFFSET
    00115            | opt->osc_id << AVR32_PM_PLLOSC_OFFSET
    00116            | 1 << AVR32_PM_PLLEN_OFFSET;
    00117
    00118   if (opt->pll_id == 0)
    00119     pm->pll0 = pllreg;
    00120   else if (opt->pll_id == 1)
    00121     pm->pll1 = pllreg;
    00122   else
    00123     return INVALID_ARGUMENT;
    00124
    00125   if (opt->wait_for_lock) {
    00126     retval = pm_wait_for_clock_source_lock(opt->pll_id == 0 ? PM_PLL0 : PM_PLL1);
    00127     if (retval != 0)
    00128       return retval;
    00129   }
    00130
    00131   return pm_get_clock_source_freq_hz(opt->pll_id == 0 ? PM_PLL0 : PM_PLL1);
    00132 }
    00133
    00134
    00135 int pm_start_pll_freq(int pll, unsigned int freq, Bool wait_for_lock)
    00136 {
    00137   return PM_NOT_SUPPORTED;
    00138 }
    00139
    00140
    00141 int pm_stop_pll(int pll)
    00142 {
    00143   return PM_NOT_SUPPORTED;
    00144 }
    00145
    00146
    00147 int pm_wait_for_clock_source_lock(int source)
    00148 {
    00149   unsigned int status;
    00150
    00151   switch (source) {
    00152     case PM_OSC0:
    00153     case PM_OSC1:
    00154       return 0;
    00155     case PM_PLL0:
    00156       status = 1 << AVR32_PM_ISR_LOCK0;
    00157       break;
    00158     case PM_PLL1:
    00159       status = 1 << AVR32_PM_ISR_LOCK1;
    00160       break;
    00161     default:
    00162       return INVALID_ARGUMENT;
    00163   }
    00164
    00165   return pm_wait_for_status(status);
    00166 }
    00167
    00168
    00169 int pm_get_clock_source_freq_hz(int clock_source)
    00170 {
    00171   volatile avr32_pm_t *pm = &AVR32_PM;
    00172   unsigned int mul, div, osc;
    00173
    00174   switch (clock_source) {
    00175     case PM_OSC0:
    00176       return FOSC0;
    00177     case PM_OSC1:
    00178       return FOSC1;
    00179     case PM_PLL0:
    00180       mul = ((pm->pll0 & AVR32_PM_PLL0_PLLMUL_MASK) >> AVR32_PM_PLL0_PLLMUL_OFFSET) + 1;
    00181       div = ((pm->pll0 & AVR32_PM_PLL0_PLLDIV_MASK) >> AVR32_PM_PLL0_PLLDIV_OFFSET) + 1;
    00182       if((pm->pll0 & AVR32_PM_PLL0_PLLOSC_MASK) >> AVR32_PM_PLL0_PLLOSC_OFFSET) /* Oscillator #1 */
    00183         osc = FOSC1;
    00184       else
    00185         osc = FOSC0;
    00186       break;
    00187     case PM_PLL1:
    00188       mul = ((pm->pll1 & AVR32_PM_PLL1_PLLMUL_MASK) >> AVR32_PM_PLL1_PLLMUL_OFFSET) + 1;
    00189       div = ((pm->pll1 & AVR32_PM_PLL1_PLLDIV_MASK) >> AVR32_PM_PLL1_PLLDIV_OFFSET) + 1;
    00190       if((pm->pll1 & AVR32_PM_PLL1_PLLOSC_MASK) >> AVR32_PM_PLL1_PLLOSC_OFFSET) /* Oscillator #1 */
    00191         osc = FOSC1;
    00192       else
    00193         osc = FOSC0;
    00194       break;
    00195     default:
    00196       return INVALID_ARGUMENT;
    00197   }
    00198
    00199   return (mul * osc) / div;
    00200 }
    00201
    00202
    00203 int pm_wait_for_status(unsigned int status)
    00204 {
    00205   unsigned int timeout = PM_TIMEOUT;
    00206
    00207   while ((pm_get_interrupt_status() & status) != status) {
    00208     timeout--;
    00209     if (timeout==0)
    00210       return -1;
    00211   }
    00212
    00213   pm_clear_interrupt_status(status);
    00214
    00215   return 0;
    00216 }
    00217
    00218
    00219 int pm_enable_interrupt(unsigned int mask)
    00220 {
    00221   volatile avr32_pm_t *pm = &AVR32_PM;
    00222
    00223   pm->ier = mask;
    00224
    00225   return pm->ier;
    00226 }
    00227
    00228
    00229 int pm_disable_interrupt(unsigned int mask)
    00230 {
    00231   volatile avr32_pm_t *pm = &AVR32_PM;
    00232
    00233   pm->idr = mask;
    00234
    00235   return pm->idr;
    00236 }
    00237
    00238
    00239 unsigned int pm_get_enabled_interrupts(void)
    00240 {
    00241   volatile avr32_pm_t *pm = &AVR32_PM;
    00242
    00243   return pm->imr;
    00244 }
    00245
    00246
    00247 unsigned int pm_get_interrupt_status(void)
    00248 {
    00249   volatile avr32_pm_t *pm = &AVR32_PM;
    00250   return pm->isr;
    00251 }
    00252
    00253
    00254 int pm_clear_interrupt_status(unsigned int mask)
    00255 {
    00256   volatile avr32_pm_t *pm = &AVR32_PM;
    00257
    00258   pm->icr=mask;
    00259
    00260   return ~(pm->isr & mask);
    00261 }
    00262
    00263
    00264 int pm_calibrate(int source, unsigned int calibration_value)
    00265 {
    00266   return PM_NOT_SUPPORTED;
    00267 }
    00268
    00269
    00270 int pm_set_bod_settings(unsigned int bod_control, Bool hysteresis, unsigned char level)
    00271 {
    00272   return PM_NOT_SUPPORTED;
    00273 }
    00274
    00275
    00276 int pm_get_bod_settings(unsigned int bod_control, Bool hysteresis, unsigned char level)
    00277 {
    00278   return PM_NOT_SUPPORTED;
    00279 }
    00280
    00281
    00282 int pm_set_mclk_source(int clock_source)
    00283 {
    00284   volatile avr32_pm_t *pm = &AVR32_PM;
    00285
    00286   if ((clock_source == PM_OSC0))
    00287     pm->mcctrl = (0 << AVR32_PM_PLLSEL_OFFSET);
    00288   else if (clock_source == PM_PLL0)
    00289     pm->mcctrl = (1 << AVR32_PM_PLLSEL_OFFSET);
    00290   else
    00291     return INVALID_ARGUMENT;
    00292
    00293   return pm_wait_for_clock_source_lock(clock_source);
    00294 }
    00295
    00296
    00297 int pm_get_mclk_source(void)
    00298 {
    00299   unsigned int source;
    00300   volatile avr32_pm_t *pm = &AVR32_PM;
    00301
    00302   source = pm->mcctrl & AVR32_PM_PLLSEL_MASK;
    00303
    00304   if(source==0)
    00305     return PM_OSC0;
    00306   else if(source==AVR32_PM_PLLSEL_MASK)
    00307     return PM_PLL0;
    00308   else
    00309     return INVALID_ARGUMENT;
    00310 }
    00311
    00312
    00313 int pm_get_mclk_freq_hz(void)
    00314 {
    00315   unsigned int f_hz;
    00316   int source;
    00317
    00318   /* Get mclk module source */
    00319   source = pm_get_mclk_source();
    00320
    00321   /* check wheter oscillator 0 is used */
    00322   if( source == PM_OSC0 )
    00323     f_hz = FOSC0;
    00324   /* check wheter pll 0 is used */
    00325   else if ( source == PM_PLL0 )
    00326     f_hz = pm_get_clock_source_freq_hz(PM_PLL0);
    00327   else
    00328     return INVALID_ARGUMENT;
    00329
    00330   return f_hz;
    00331 }
    00332
    00333
    00334 int pm_read_module_domain_scaler(unsigned int module_domain)
    00335 {
    00336   volatile avr32_pm_t *pm = &AVR32_PM;
    00337   unsigned int divider, offset, cksel;
    00338
    00339   /* Get offset for divider */
    00340   if(module_domain == PM_PBB_DOMAIN)
    00341     offset = AVR32_PM_CKSEL_PBBSEL_OFFSET;
    00342   else if(module_domain == PM_PBA_DOMAIN)
    00343     offset = AVR32_PM_CKSEL_PBASEL_OFFSET;
    00344   else if(module_domain == PM_HSB_DOMAIN)
    00345     offset = AVR32_PM_CKSEL_HSBSEL_OFFSET;
    00346   else if(module_domain == PM_CPU_DOMAIN)
    00347     offset = AVR32_PM_CKSEL_CPUSEL_OFFSET;
    00348   else
    00349     return INVALID_ARGUMENT;
    00350
    00351   cksel = pm->cksel >> offset;
    00352   // Check if prescaler is enabled
    00353   if (cksel & AVR32_PM_CKSEL_CPUDIV_MASK)
    00354     divider = 1 << ((cksel & AVR32_PM_CKSEL_CPUSEL_MASK) + 1);
    00355   else
    00356     divider = 1;
    00357
    00358   return divider;
    00359 }
    00360
    00361
    00362 int pm_set_clock_domain_scaler(unsigned int clock_domain, int divider)
    00363 {
    00364   volatile avr32_pm_t *pm = &AVR32_PM;
    00365   unsigned int offset;
    00366   int divsel;
    00367
    00368   // Count trailing zeros
    00369   divsel = ctz(divider);
    00370
    00371   if ((divsel > 8) || ((1 << divsel) != divider))
    00372     return INVALID_ARGUMENT;
    00373
    00374   if (divsel > 0)
    00375     divsel = (divsel - 1) | AVR32_PM_CKSEL_CPUDIV_MASK;
    00376
    00377   // Get offset for bitfields
    00378   switch (clock_domain){
    00379     case PM_PBB_DOMAIN:
    00380       offset = AVR32_PM_CKSEL_PBBSEL_OFFSET;
    00381       break;
    00382     case PM_PBA_DOMAIN:
    00383       offset = AVR32_PM_CKSEL_PBASEL_OFFSET;
    00384       break;
    00385     case PM_HSB_DOMAIN:
    00386       offset = AVR32_PM_CKSEL_HSBSEL_OFFSET;
    00387       break;
    00388     case PM_CPU_DOMAIN:
    00389       offset = AVR32_PM_CKSEL_CPUSEL_OFFSET;
    00390       break;
    00391     default:
    00392       return INVALID_ARGUMENT;
    00393   } /* end switch */
    00394
    00395   pm->cksel = (pm->cksel & ~((AVR32_PM_CKSEL_CPUDIV_MASK | AVR32_PM_CKSEL_CPUSEL_MASK) << offset))
    00396               | (divsel << offset);
    00397
    00398   pm_wait_for_status(AVR32_PM_ISR_CKRDY);
    00399
    00400   return 0;
    00401 } /* End pm_set_clock_domain_scaler() */
    00402
    00403
    00404 int pm_read_module_freq_hz(unsigned int module)
    00405 {
    00406   unsigned int clk, domain;
    00407   int divider;
    00408
    00409   clk = pm_get_mclk_freq_hz();
    00410
    00411   domain = module / 32;
    00412   divider = pm_read_module_domain_scaler(domain);
    00413   if (divider < 0)
    00414     return divider;
    00415
    00416   /* CHECK WHETHER THE CLOCK IS MASKED */
    00417
    00418   return clk / divider;
    00419 }
    00420
    00421
    00422 int pm_enable_module(unsigned int module)
    00423 {
    00424   volatile avr32_pm_t *pm = &AVR32_PM;
    00425
    00426   switch (module % 32){
    00427     case PM_CPU_DOMAIN:
    00428       /* Check whether the module is out of bounds */
    00429       if( (module/32) > PM_CPU_DOMAIN_SIZE )
    00430         return INVALID_ARGUMENT;
    00431       else{
    00432         pm->cpumask |= ( 1<<(module/32) );
    00433         break;
    00434       }
    00435     case PM_HSB_DOMAIN:
    00436       /* Check whether the module is out of bounds */
    00437       if( (module/32) > PM_HSB_DOMAIN_SIZE )
    00438         return INVALID_ARGUMENT;
    00439       else{
    00440         pm->hsbmask |= ( 1<<(module/32) );
    00441         break;
    00442       }
    00443     case PM_PBA_DOMAIN:
    00444       /* Check whether the module is out of bounds */
    00445       if( (module/32) > PM_PBA_DOMAIN_SIZE )
    00446         return INVALID_ARGUMENT;
    00447       else{
    00448         pm->pbamask |= ( 1<<(module/32) );
    00449         break;
    00450       }
    00451     case PM_PBB_DOMAIN:
    00452       /* Check whether the module is out of bounds */
    00453       if( (module/32) > PM_PBB_DOMAIN_SIZE )
    00454         return INVALID_ARGUMENT;
    00455       else{
    00456         pm->pbbmask |= ( 1<<(module/32) );
    00457         break;
    00458       }
    00459     default:
    00460       return INVALID_ARGUMENT;
    00461   }
    00462   return 0;
    00463 }
    00464
    00465
    00466 int pm_disable_module(unsigned int module)
    00467 {
    00468   volatile avr32_pm_t *pm = &AVR32_PM;
    00469
    00470   switch (module % 32){
    00471     case PM_CPU_DOMAIN:
    00472       /* Check whether the module is out of bounds */
    00473       if( (module/32) > PM_CPU_DOMAIN_SIZE )
    00474         return INVALID_ARGUMENT;
    00475       else{
    00476         pm->cpumask &= ~( 1<<(module/32) );
    00477         break;
    00478       }
    00479     case PM_HSB_DOMAIN:
    00480       /* Check whether the module is out of bounds */
    00481       if( (module/32) > PM_HSB_DOMAIN_SIZE )
    00482         return INVALID_ARGUMENT;
    00483       else{
    00484         pm->hsbmask &= ~( 1<<(module/32) );
    00485         break;
    00486       }
    00487     case PM_PBA_DOMAIN:
    00488       /* Check whether the module is out of bounds */
    00489       if( (module/32) > PM_PBA_DOMAIN_SIZE )
    00490         return INVALID_ARGUMENT;
    00491       else{
    00492         pm->pbamask &= ~( 1<<(module/32) );
    00493         break;
    00494       }
    00495     case PM_PBB_DOMAIN:
    00496       /* Check whether the module is out of bounds */
    00497       if( (module/32) > PM_PBB_DOMAIN_SIZE )
    00498         return INVALID_ARGUMENT;
    00499       else{
    00500         pm->pbbmask &= ~( 1<<(module/32) );
    00501         break;
    00502       }
    00503     default:
    00504       return INVALID_ARGUMENT;
    00505   }
    00506   return 0;
    00507 }
    00508
    00509
    00510 int pm_start_generic_clock(unsigned int clock, const pm_gen_clk_opt_t *opt)
    00511 {
    00512   volatile avr32_pm_t *pm = &AVR32_PM;
    00513   unsigned int reg = 1 << AVR32_PM_GCCTRL0_CEN_OFFSET;
    00514
    00515   if (opt->divider > 1)
    00516     reg |= (((opt->divider >> 1) - 1) << AVR32_PM_GCCTRL0_DIV_OFFSET) | (1 << AVR32_PM_GCCTRL0_DIVEN_OFFSET);
    00517
    00518   if ( (opt->clock_source == PM_OSC0) || (opt->clock_source == PM_OSC1) )
    00519     reg |= opt->clock_source << AVR32_PM_GCCTRL0_OSCSEL_OFFSET;
    00520   else if ( (opt->clock_source == PM_PLL0) || (opt->clock_source == PM_PLL1) )
    00521     reg |= ((opt->clock_source-3) << AVR32_PM_GCCTRL0_OSCSEL_OFFSET) | (1 << AVR32_PM_GCCTRL0_PLLSEL_OFFSET);
    00522   else
    00523     return INVALID_ARGUMENT;
    00524
    00525   pm->gcctrl[clock] = reg;
    00526
    00527   return 0;
    00528 }
    00529
    00530
    00531 int pm_stop_generic_clock(unsigned int clock)
    00532 {
    00533   volatile avr32_pm_t *pm = &AVR32_PM;
    00534
    00535   pm->gcctrl[clock] &= ~(1 << AVR32_PM_GCCTRL0_CEN_OFFSET);
    00536
    00537   return 0;
    00538 }
    00539