pm.c

Go to the documentation of this file.
00001 /* Copyright (c) 2007, Atmel Corporation All rights reserved.
00002  *
00003  * Redistribution and use in source and binary forms, with or without
00004  * modification, are permitted provided that the following conditions are met:
00005  *
00006  * 1. Redistributions of source code must retain the above copyright notice,
00007  * this list of conditions and the following disclaimer.
00008  *
00009  * 2. Redistributions in binary form must reproduce the above copyright notice,
00010  * this list of conditions and the following disclaimer in the documentation
00011  * and/or other materials provided with the distribution.
00012  *
00013  * 3. The name of ATMEL may not be used to endorse or promote products derived
00014  * from this software without specific prior written permission.
00015  *
00016  * THIS SOFTWARE IS PROVIDED BY ATMEL ``AS IS'' AND ANY EXPRESS OR IMPLIED
00017  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
00018  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE EXPRESSLY AND
00019  * SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT,
00020  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
00021  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
00022  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
00023  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
00024  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
00025  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00026  */
00027 
00028 #include "pm.h"
00029 
00030 /* reset all clocks and set mclk to osc0 */
00031 int pm_reset( void )
00032 {
00033         avr32_pm_t *pm = (void *) AVR32_PM_ADDRESS;
00034         unsigned int status = SUCCESS;
00035         int disable_clock_mask = 0xFFFFffff;
00036 
00037         pm_set_mclk_source(PM_OSC0);
00038 
00039         pm->cksel = 0x00000000;
00040         status |= pm_wait_for_lock(AVR32_PM_ISR_CKRDY);
00041 
00042         pm->cpu_mask = disable_clock_mask;
00043         status |= pm_wait_for_lock(AVR32_PM_ISR_MSKRDY);
00044 
00045         pm->hsb_mask = disable_clock_mask;
00046         status |= pm_wait_for_lock(AVR32_PM_ISR_MSKRDY);
00047 
00048         pm->pba_mask = disable_clock_mask;
00049         status |= pm_wait_for_lock(AVR32_PM_ISR_MSKRDY);
00050 
00051         pm->pbb_mask = disable_clock_mask;
00052         status |= pm_wait_for_lock(AVR32_PM_ISR_MSKRDY);
00053 
00054         pm->ier = 0x7F; /* enable all interrupts*/
00055         pm->icr |= 0x7F; /* clear all interrupts */
00056 
00057         return status;
00058 }
00059 
00060 int pm_wait_for_lock(unsigned int lockbit)
00061 {
00062         unsigned int timeout = PM_TIMEOUT;
00063         unsigned int lockStatus=0;
00064 
00065         while (!lockStatus){
00066                 lockStatus =  pm_interrupt_status(lockbit);
00067                 --timeout;
00068                 if (timeout==0)
00069                         return PM_LOCK_ERROR;
00070         }
00071 
00072         pm_interrupt_clear(lockbit);
00073 
00074         return SUCCESS;
00075 }
00076 
00077 /* Modify a specific pll */
00078 int pm_set_pll(volatile struct pll_opt_t *opt)
00079 {
00080         volatile avr32_pm_t *pm = (void *) AVR32_PM_ADDRESS;
00081         unsigned int pllreg, lockbit;
00082 
00083         /* Ensure that mclk is driven by the current pll */
00084         if(pm_read_mclk_source()==PM_PLL0)
00085                 pm_set_mclk_source(PM_OSC0);
00086 
00087         if ( (opt->multiplier == 0) | (opt->divider == 0) )
00088                 return INVALID_ARGUMENT;
00089 
00090         pllreg = (1<<AVR32_PM_PLL0_PLLCOUNT_OFFSET)|(1<<AVR32_PM_PLL0_PLLEN_OFFSET);
00091 
00092         // add multiplier
00093         if (opt->multiplier != 0)
00094         pllreg = pllreg | (((opt->multiplier) -1 ) << AVR32_PM_PLLMUL_OFFSET);
00095         // add divider
00096         if(opt->divider != 0)
00097         pllreg = pllreg | (((opt->divider) - 1) << AVR32_PM_PLLDIV_OFFSET);
00098         // select oscillator
00099         if(opt->oscillator <= 1)
00100         pllreg = pllreg | ((opt->oscillator) << AVR32_PM_PLLOSC_OFFSET);
00101 
00102 
00103         /* CHECK FOR VALID ARGUMENTS*/
00104         if( opt->pll == PM_PLL0 )
00105                 pm->pll0 = pllreg;
00106         else if ( opt->pll == PM_PLL1 )
00107                 pm->pll1 = pllreg;
00108         else
00109                 return INVALID_ARGUMENT;
00110 
00111         // Get lock bit
00112         if(opt->pll == PM_PLL0){
00113                 lockbit =  AVR32_PM_ISR_LOCK0;
00114         }
00115         else{
00116                 lockbit =  AVR32_PM_ISR_LOCK1;
00117         }
00118 
00119         return pm_wait_for_lock(lockbit);
00120 }
00121 
00122 int pm_read_pll_frequency( unsigned int pll )
00123 {
00124         volatile avr32_pm_t *pm = (void *) AVR32_PM_ADDRESS;
00125         unsigned int mul,div,osc;
00126 
00127         if ( pll==PM_PLL0 ){
00128                 mul = ( (pm->pll0&AVR32_PM_PLL0_PLLMUL_MASK)>>AVR32_PM_PLL0_PLLMUL_OFFSET)+1;
00129                 div = ( (pm->pll0&AVR32_PM_PLL0_PLLDIV_MASK)>>AVR32_PM_PLL0_PLLDIV_OFFSET)+1;
00130                 if((pm->pll0&AVR32_PM_PLL0_PLLOSC_MASK)>>AVR32_PM_PLL0_PLLOSC_OFFSET) /* Oscillator #1 */
00131                         osc = PM_OSC1_HZ;
00132                 else
00133                         osc = PM_OSC0_HZ;
00134         }
00135         else if ( pll==PM_PLL1 ){
00136                 mul = ( (pm->pll1&AVR32_PM_PLL1_PLLMUL_MASK)>>AVR32_PM_PLL1_PLLMUL_OFFSET)+1;
00137                 div = ( (pm->pll1&AVR32_PM_PLL1_PLLDIV_MASK)>>AVR32_PM_PLL1_PLLDIV_OFFSET)+1;
00138                 if((pm->pll1&AVR32_PM_PLL1_PLLOSC_MASK)>>AVR32_PM_PLL1_PLLOSC_OFFSET) /* Oscillator #1 */
00139                         osc = PM_OSC1_HZ;
00140                 else
00141                         osc = PM_OSC0_HZ;
00142         }
00143         else
00144                 return INVALID_ARGUMENT;
00145 
00146         return (mul*osc)/div;
00147 }
00148 
00149 
00150 /*Read a specific oscillator value*/
00151 int pm_read_osc( unsigned int osc )
00152 {
00153         if(osc == 0)
00154                 return PM_OSC0_HZ;
00155         else if(osc == 1)
00156                 return PM_OSC1_HZ;
00157         else
00158                 return INVALID_ARGUMENT;
00159 }
00160 
00161 /* Set the source for the main clock */
00162 int pm_set_mclk_source(unsigned int source)
00163 {
00164         volatile avr32_pm_t *pm = (void *) AVR32_PM_ADDRESS;
00165 
00166         if( (source == PM_OSC0) ){
00167                 pm->mcctrl = (0 << AVR32_PM_PLLSEL_OFFSET);
00168         }
00169         else if( source ==PM_PLL0 ){
00170                 pm->mcctrl = (1 << AVR32_PM_PLLSEL_OFFSET);
00171         }
00172         else
00173                 return INVALID_ARGUMENT;
00174 
00175         return pm_wait_for_lock(AVR32_PM_ISR_CKRDY);
00176 
00177 }
00178 
00179 
00180 
00181 /* Read the main clock src */
00182 int pm_read_mclk_source( void )
00183 {
00184         int source;
00185         avr32_pm_t *pm = (void *) AVR32_PM_ADDRESS;
00186 
00187         source = (pm->mcctrl)&AVR32_PM_PLLSEL_MASK;
00188 
00189         if(source==0)
00190                 return PM_OSC0;
00191         else if(source==AVR32_PM_PLLSEL_MASK)
00192                 return PM_PLL0;
00193         else
00194                 return INVALID_ARGUMENT;
00195 }
00196 
00197 
00198 
00199 /* Read the main clock frequency*/
00200 int pm_read_mclk( void )
00201 {
00202         unsigned int f_hz, source;
00203 
00204         /* Get mclk clock source */
00205         source = pm_read_mclk_source();
00206 
00207         /* check wheter oscillator 0 is used */
00208         if( source == PM_OSC0 )
00209                 f_hz = PM_OSC0_HZ;
00210         /* check wheter pll 0 is used */
00211         else if ( source == PM_PLL0 )
00212                 f_hz = pm_read_pll_frequency(PM_PLL0);
00213         else
00214                 return INVALID_ARGUMENT;
00215 
00216         return f_hz;
00217 } /* End pm_read_mclk() */
00218 
00219 
00220 
00221 /* Get the clock frequency for the given clock domain */
00222 int pm_read_clock_domain_scaler(unsigned int clock_domain)
00223 {
00224         static avr32_pm_t *pm = (void *) AVR32_PM_ADDRESS;
00225         int divider, offset;
00226 
00227         /* Get offset for divider */
00228         if(clock_domain == PM_PBB_DOMAIN)
00229                 offset = AVR32_PM_CKSEL_PBBSEL_OFFSET;
00230         else if(clock_domain == PM_PBA_DOMAIN)
00231                 offset = AVR32_PM_CKSEL_PBASEL_OFFSET;
00232         else if(clock_domain == PM_HSB_DOMAIN)
00233                 offset = AVR32_PM_CKSEL_HSBSEL_OFFSET;
00234         else if(clock_domain == PM_CPU_DOMAIN)
00235                 offset = AVR32_PM_CKSEL_CPUSEL_OFFSET;
00236         else
00237                 return INVALID_ARGUMENT;
00238 
00239 
00240         divider = pm->cksel & (AVR32_PM_CKSEL_CPUSEL_MASK<<offset);
00241         divider = divider >> offset;
00242 
00243         return (divider+1);
00244 
00245 } /* End pm_read_clock_domain_scaler() */
00246 
00247 
00248 
00249 /* Select clocks for different domains of the system */
00250 int pm_set_clock_domain_scaler(volatile struct clk_sel_opt_t *opt)
00251 {
00252         volatile avr32_pm_t *pm = (void *) AVR32_PM_ADDRESS;
00253         int offset,new_settings;
00254 
00255         // Check for invalid division factor
00256         if( (opt->div_enable == 1) & ((opt->divider == 0)|(opt->divider >= (1<<AVR32_PM_CKSEL_CPUSEL_SIZE))) )
00257                 return INVALID_ARGUMENT;
00258 
00259         // Get offset for bitfields
00260         switch (opt->clock){
00261                 case PM_PBB_DOMAIN:
00262                         offset = AVR32_PM_CKSEL_PBBSEL_OFFSET;
00263                         break;
00264                 case PM_PBA_DOMAIN:
00265                         offset = AVR32_PM_CKSEL_PBASEL_OFFSET;
00266                         break;
00267                 case PM_HSB_DOMAIN:
00268                         offset = AVR32_PM_CKSEL_HSBSEL_OFFSET;
00269                         break;
00270                 case PM_CPU_DOMAIN:
00271                         offset = AVR32_PM_CKSEL_CPUSEL_OFFSET;
00272                         break;
00273                 default:
00274                         return INVALID_ARGUMENT;
00275                         break;
00276         } /* end switch */
00277 
00278         // Check whether division should be disabled
00279         if(opt->div_enable == 0){
00280                 new_settings = 0x00;
00281         }
00282 
00283         // Division is to be used
00284         else if (opt->div_enable == 1) {
00285                 new_settings = 1<<AVR32_PM_CKSEL_CPUDIV;
00286                 new_settings |= ((opt->divider)-1);
00287         }
00288 
00289         // Error. div_enable >1
00290         else
00291                 return INVALID_ARGUMENT;
00292 
00293         pm->cksel &=  ~((AVR32_PM_CKSEL_CPUDIV_MASK|AVR32_PM_CKSEL_CPUSEL_MASK)<<offset);
00294         pm->cksel |= (new_settings<<offset);
00295 
00296         pm_wait_for_lock(AVR32_PM_ISR_CKRDY);
00297 
00298         return SUCCESS;
00299 
00300 } /* End pm_set_clock_domain_scaler() */
00301 
00302 /* Return the value of the scaling register */
00303 int pm_read_scaling_register(void)
00304 {
00305         volatile avr32_pm_t *pm = (void *) AVR32_PM_ADDRESS;
00306 
00307         return pm->cksel;
00308 }
00309 
00310 /* Start a single module clock part of a clock domain */
00311 int pm_unmask_module_clock( unsigned int clock )
00312 {
00313         avr32_pm_t *pm = (void *)AVR32_PM_ADDRESS;
00314 
00315         switch (clock % 32){
00316                 case PM_CPU_DOMAIN:
00317                         /* Check whether the clock is out of bounds */
00318                         if( (clock/32) > PM_CPU_DOMAIN_SIZE )
00319                                 return INVALID_ARGUMENT;
00320                         else{
00321                                 pm->cpu_mask |= ( 1<<(clock/32) );
00322                                 break;
00323                         }
00324                 case PM_HSB_DOMAIN:
00325                         /* Check whether the clock is out of bounds */
00326                         if( (clock/32) > PM_HSB_DOMAIN_SIZE )
00327                                 return INVALID_ARGUMENT;
00328                         else{
00329                                 pm->hsb_mask |= ( 1<<(clock/32) );
00330                                 break;
00331                         }
00332                 case PM_PBA_DOMAIN:
00333                         /* Check whether the clock is out of bounds */
00334                         if( (clock/32) > PM_PBA_DOMAIN_SIZE )
00335                                 return INVALID_ARGUMENT;
00336                         else{
00337                                 pm->pba_mask |= ( 1<<(clock/32) );
00338                                 break;
00339                         }
00340                 case PM_PBB_DOMAIN:
00341                         /* Check whether the clock is out of bounds */
00342                         if( (clock/32) > PM_PBB_DOMAIN_SIZE )
00343                                 return INVALID_ARGUMENT;
00344                         else{
00345                                 pm->pbb_mask |= ( 1<<(clock/32) );
00346                                 break;
00347                         }
00348                 default:
00349                         return INVALID_ARGUMENT;
00350         }
00351         return 0;
00352 } /* End pm_start_clock() */
00353 
00354 
00355 
00356 /* Stop a single module clock part of a clock domain */
00357 int pm_mask_module_clock( unsigned int clock )
00358 {
00359         avr32_pm_t *pm = (void *)AVR32_PM_ADDRESS;
00360 
00361         switch (clock % 32){
00362                 case PM_CPU_DOMAIN:
00363                         /* Check whether the clock is out of bounds */
00364                         if( (clock/32) > PM_CPU_DOMAIN_SIZE )
00365                                 return INVALID_ARGUMENT;
00366                         else{
00367                                 pm->cpu_mask &= ~( 1<<(clock/32) );
00368                                 break;
00369                         }
00370                 case PM_HSB_DOMAIN:
00371                         /* Check whether the clock is out of bounds */
00372                         if( (clock/32) > PM_HSB_DOMAIN_SIZE )
00373                                 return INVALID_ARGUMENT;
00374                         else{
00375                                 pm->hsb_mask &= ~( 1<<(clock/32) );
00376                                 break;
00377                         }
00378                 case PM_PBA_DOMAIN:
00379                         /* Check whether the clock is out of bounds */
00380                         if( (clock/32) > PM_PBA_DOMAIN_SIZE )
00381                                 return INVALID_ARGUMENT;
00382                         else{
00383                                 pm->pba_mask &= ~( 1<<(clock/32) );
00384                                 break;
00385                         }
00386                 case PM_PBB_DOMAIN:
00387                         /* Check whether the clock is out of bounds */
00388                         if( (clock/32) > PM_PBB_DOMAIN_SIZE )
00389                                 return INVALID_ARGUMENT;
00390                         else{
00391                                 pm->pbb_mask &= ~( 1<<(clock/32) );
00392                                 break;
00393                         }
00394                 default:
00395                         return INVALID_ARGUMENT;
00396         }
00397         return 0;
00398 } /* End pm_stop_clock */
00399 
00400 /* Unmask all module clocks */
00401 void pm_unmask_all_module_clocks ( void )
00402 {
00403         avr32_pm_t *pm = (void *)AVR32_PM_ADDRESS;
00404 
00405         pm->cpu_mask = 0x00000000;
00406         pm->hsb_mask = 0x00000000;
00407         pm->pba_mask = 0x00000000;
00408         pm->pbb_mask = 0x00000000;
00409         pm_wait_for_lock(AVR32_PM_ISR_MSKRDY);
00410 }
00411 
00412 /* Mask all module clocks */
00413 void pm_mask_all_module_clocks ( void )
00414 {
00415         avr32_pm_t *pm = (void *)AVR32_PM_ADDRESS;
00416 
00417         pm->cpu_mask = 0xFFFFffff;
00418         pm->hsb_mask = 0xFFFFffff;
00419         pm->pba_mask = 0xFFFFffff;
00420         pm->pbb_mask = 0xFFFFffff;
00421 
00422         pm_wait_for_lock(AVR32_PM_ISR_MSKRDY);
00423 }
00424 
00425 int pm_read_module_frequency(int module)
00426 {
00427         int clk, domain, divider;
00428 
00429         clk = pm_read_mclk();
00430         divider = pm_read_clock_domain_scaler(PM_HSB_DOMAIN);
00431         domain = module/32;
00432         
00433         if ( domain == PM_HSB_DOMAIN )
00434                 divider = divider;
00435         else if( domain==PM_PBA_DOMAIN )
00436                 divider = divider * pm_read_clock_domain_scaler(PM_PBA_DOMAIN);
00437         else if( domain==PM_PBB_DOMAIN )
00438                 divider = divider * pm_read_clock_domain_scaler(PM_PBB_DOMAIN);
00439         else
00440                 return INVALID_ARGUMENT;
00441 
00442         /* CHECK WHETHER THE CLOCK IS MASKED */
00443 
00444         return clk/divider;
00445 }
00446 
00447 /* Enable interrupt */
00448 int pm_interrupt_enable( unsigned int source )
00449 {
00450         avr32_pm_t *pm = (void *)AVR32_PM_ADDRESS;
00451 
00452         if( source > (PM_INT_SOURCES-1) )
00453                 return INVALID_ARGUMENT;
00454         else{
00455                 pm->ier |= (1 << source);
00456                 return 0;
00457         }
00458 }
00459 
00460 
00461 
00462 /* Disable interrupt*/
00463 int pm_interrupt_disable( unsigned int source )
00464 {
00465         avr32_pm_t *pm = (void *)AVR32_PM_ADDRESS;
00466 
00467         if( source > (PM_INT_SOURCES-1) )
00468                 return INVALID_ARGUMENT;
00469         else{
00470                 pm->idr |= (1 << source);
00471                 return 0;
00472         }
00473 }
00474 
00475 
00476 
00477 /* Status of interrupt*/
00478 int pm_interrupt_status( unsigned int source )
00479 {
00480         avr32_pm_t *pm = (void *)AVR32_PM_ADDRESS;
00481 
00482         if ( source > (PM_INT_SOURCES-1) )
00483                 return INVALID_ARGUMENT;
00484         else
00485                 return (pm->isr & source)>>source;
00486 }
00487 
00488 
00489 
00490 /* Clear interrupt */
00491 int pm_interrupt_clear( unsigned int source )
00492 {
00493         avr32_pm_t *pm = (void *)AVR32_PM_ADDRESS;
00494 
00495         if( source > (PM_INT_SOURCES-1) )
00496                 return INVALID_ARGUMENT;
00497         else{
00498                 pm->icr |= (1 << source);
00499                 return 0;
00500         }
00501 }
00502 
00503 
00504 
00505 /* Clear interrupt */
00506 int pm_interrupt_mask( unsigned int source )
00507 {
00508         avr32_pm_t *pm = (void *)AVR32_PM_ADDRESS;
00509 
00510         if( source > (PM_INT_SOURCES-1) )
00511                 return INVALID_ARGUMENT;
00512         else{
00513                 return (pm->ier & source ) >> source ;
00514         }
00515 }
00516 
00517 
00518 
00519 /* Modify the generic clock */
00520 int pm_generic_clock_control( struct gen_clk_opt_t *opt, unsigned char genclk)
00521 {
00522         avr32_pm_t *pm = (void *)AVR32_PM_ADDRESS;
00523 
00524         /* Check whether div-field is larger than 8 bits */
00525         if( opt->div > 0xFF)
00526                 return INVALID_ARGUMENT;
00527         /* Check for valid single bits */
00528         if ( ((opt->diven)|(opt->cen)|(opt->pllsel)|(opt->oscsel)|(genclk > 1)) > 1 )
00529                 return INVALID_ARGUMENT;
00530         else
00531                 pm->gcctrl[genclk] = ( (opt->div << AVR32_PM_GCCTRL0_DIV_OFFSET)| \
00532                         (opt->diven << AVR32_PM_GCCTRL0_DIVEN_OFFSET)|\
00533                         (opt->cen << AVR32_PM_GCCTRL0_CEN_OFFSET)|\
00534                         (opt->pllsel << AVR32_PM_GCCTRL0_PLLSEL_OFFSET)|\
00535                         (opt->oscsel << AVR32_PM_GCCTRL0_OSCSEL_OFFSET) );
00536         
00537         return 0;
00538 } /* End pm_generic_clock_control() */
00539 

Generated on Wed May 7 16:03:17 2008 for AVR32114 Using the AVR32 LCD Controller by  doxygen 1.5.3-20071008