1 /* 2 * Copyright (C) 2009 Samsung Electronics 3 * Heungjun Kim <riverful.kim@samsung.com> 4 * Inki Dae <inki.dae@samsung.com> 5 * Minkyu Kang <mk7.kang@samsung.com> 6 * 7 * See file CREDITS for list of people who contributed to this 8 * project. 9 * 10 * This program is free software; you can redistribute it and/or 11 * modify it under the terms of the GNU General Public License as 12 * published by the Free Software Foundation; either version 2 of 13 * the License, or (at your option) any later version. 14 * 15 * This program is distributed in the hope that it will be useful, 16 * but WITHOUT ANY WARRANTY; without even the implied warranty of 17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 * GNU General Public License for more details. 19 * 20 * You should have received a copy of the GNU General Public License 21 * along with this program; if not, write to the Free Software 22 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, 23 * MA 02111-1307 USA 24 */ 25 26 #include <common.h> 27 #include <asm/io.h> 28 #include <asm/arch/pwm.h> 29 #include <asm/arch/clk.h> 30 #include <pwm.h> 31 32 DECLARE_GLOBAL_DATA_PTR; 33 34 unsigned long get_current_tick(void); 35 36 /* macro to read the 16 bit timer */ 37 static inline struct s5p_timer *s5p_get_base_timer(void) 38 { 39 return (struct s5p_timer *)samsung_get_base_timer(); 40 } 41 42 int timer_init(void) 43 { 44 /* PWM Timer 4 */ 45 pwm_init(4, MUX_DIV_2, 0); 46 pwm_config(4, 0, 0); 47 pwm_enable(4); 48 49 reset_timer_masked(); 50 51 return 0; 52 } 53 54 /* 55 * timer without interrupts 56 */ 57 unsigned long get_timer(unsigned long base) 58 { 59 return get_timer_masked() - base; 60 } 61 62 /* delay x useconds */ 63 void __udelay(unsigned long usec) 64 { 65 struct s5p_timer *const timer = s5p_get_base_timer(); 66 unsigned long tmo, tmp, count_value; 67 68 count_value = readl(&timer->tcntb4); 69 70 if (usec >= 1000) { 71 /* 72 * if "big" number, spread normalization 73 * to seconds 74 * 1. start to normalize for usec to ticks per sec 75 * 2. find number of "ticks" to wait to achieve target 76 * 3. finish normalize. 77 */ 78 tmo = usec / 1000; 79 tmo *= (CONFIG_SYS_HZ * count_value); 80 tmo /= 1000; 81 } else { 82 /* else small number, don't kill it prior to HZ multiply */ 83 tmo = usec * CONFIG_SYS_HZ * count_value; 84 tmo /= (1000 * 1000); 85 } 86 87 /* get current timestamp */ 88 tmp = get_current_tick(); 89 90 /* if setting this fordward will roll time stamp */ 91 /* reset "advancing" timestamp to 0, set lastinc value */ 92 /* else, set advancing stamp wake up time */ 93 if ((tmo + tmp + 1) < tmp) 94 reset_timer_masked(); 95 else 96 tmo += tmp; 97 98 /* loop till event */ 99 while (get_current_tick() < tmo) 100 ; /* nop */ 101 } 102 103 void reset_timer_masked(void) 104 { 105 struct s5p_timer *const timer = s5p_get_base_timer(); 106 107 /* reset time */ 108 gd->lastinc = readl(&timer->tcnto4); 109 gd->tbl = 0; 110 } 111 112 unsigned long get_timer_masked(void) 113 { 114 struct s5p_timer *const timer = s5p_get_base_timer(); 115 unsigned long count_value = readl(&timer->tcntb4); 116 117 return get_current_tick() / count_value; 118 } 119 120 unsigned long get_current_tick(void) 121 { 122 struct s5p_timer *const timer = s5p_get_base_timer(); 123 unsigned long now = readl(&timer->tcnto4); 124 unsigned long count_value = readl(&timer->tcntb4); 125 126 if (gd->lastinc >= now) 127 gd->tbl += gd->lastinc - now; 128 else 129 gd->tbl += gd->lastinc + count_value - now; 130 131 gd->lastinc = now; 132 133 return gd->tbl; 134 } 135 136 /* 137 * This function is derived from PowerPC code (read timebase as long long). 138 * On ARM it just returns the timer value. 139 */ 140 unsigned long long get_ticks(void) 141 { 142 return get_timer(0); 143 } 144 145 /* 146 * This function is derived from PowerPC code (timebase clock frequency). 147 * On ARM it returns the number of timer ticks per second. 148 */ 149 unsigned long get_tbclk(void) 150 { 151 return CONFIG_SYS_HZ; 152 } 153