[U-Boot] [PATCH 0/9] Fix and Re-organise PWM Timer

This patch set tries to fix few bugs in timer and re-organises PWM clock code.
Akshay Saraswat (9): Exynos: Change get_timer() to work correctly Exynos: Add timer_get_us function Exynos: pwm: Fix two bugs in the exynos pwm configuration code Exynos: Avoid a divide by zero by specifying a non-zero period for pwm 4 Exynos: Tidy up the pwm_config function in the exynos pwm driver Exynos: Add peripherial id for pwm Exynos: clock: Add generic api to get the clk freq Exynos: clock: Correct pwm source clk selection Exynos: pwm: Use generic api to get pwm clk freq
arch/arm/cpu/armv7/exynos/clock.c | 127 ++++++++++++++++++++++++++++++ arch/arm/cpu/armv7/s5p-common/pwm.c | 45 +++++------ arch/arm/cpu/armv7/s5p-common/timer.c | 117 +++++++++++++-------------- arch/arm/include/asm/arch-exynos/clk.h | 27 +++++++ arch/arm/include/asm/arch-exynos/periph.h | 5 ++ board/samsung/smdk5250/setup.h | 2 +- 6 files changed, 237 insertions(+), 86 deletions(-)

At present get_timer() does not return sane values. It should count up smoothly in milliscond intervals.
We can change the PWM to count down at 1MHz, providing a resolution of 1us and a range of about an hour between required get_timer() calls.
TEST=sf probe 1:0; time sf read 40008000 0 1000 Try with different numbers of bytes and see that sane values are obtained
Signed-off-by: Simon Glass sjg@chromium.org Signed-off-by: Akshay Saraswat akshay.s@samsung.com --- arch/arm/cpu/armv7/s5p-common/pwm.c | 6 ++ arch/arm/cpu/armv7/s5p-common/timer.c | 100 +++++++++++++--------------------- 2 files changed, 44 insertions(+), 62 deletions(-)
diff --git a/arch/arm/cpu/armv7/s5p-common/pwm.c b/arch/arm/cpu/armv7/s5p-common/pwm.c index 44d7bc3..3147f59 100644 --- a/arch/arm/cpu/armv7/s5p-common/pwm.c +++ b/arch/arm/cpu/armv7/s5p-common/pwm.c @@ -174,6 +174,12 @@ int pwm_init(int pwm_id, int div, int invert)
/* set count value */ offset = pwm_id * 3; + + /* + * TODO(sjg): Use this as a countdown timer for now. We count down + * from the maximum value to 0, then reset. + */ + timer_rate_hz = -1; writel(timer_rate_hz, &pwm->tcntb0 + offset);
val = readl(&pwm->tcon) & ~(0xf << TCON_OFFSET(pwm_id)); diff --git a/arch/arm/cpu/armv7/s5p-common/timer.c b/arch/arm/cpu/armv7/s5p-common/timer.c index e78c716..c48a297 100644 --- a/arch/arm/cpu/armv7/s5p-common/timer.c +++ b/arch/arm/cpu/armv7/s5p-common/timer.c @@ -39,13 +39,33 @@ static inline struct s5p_timer *s5p_get_base_timer(void) return (struct s5p_timer *)samsung_get_base_timer(); }
+/** + * Read the countdown timer. + * + * This operates at 1MHz and counts downwards. It will wrap about every + * hour (2^32 microseconds). + * + * @return current value of timer + */ +static unsigned long timer_get_us_down(void) +{ + struct s5p_timer *const timer = s5p_get_base_timer(); + + return readl(&timer->tcnto4); +} + int timer_init(void) { /* PWM Timer 4 */ - pwm_init(4, MUX_DIV_2, 0); + pwm_init(4, MUX_DIV_4, 0); pwm_config(4, 0, 0); pwm_enable(4);
+ /* Use this as the current monotonic time in us */ + gd->arch.timer_reset_value = 0; + + /* Use this as the last timer value we saw */ + gd->arch.lastinc = timer_get_us_down(); reset_timer_masked();
return 0; @@ -56,48 +76,28 @@ int timer_init(void) */ unsigned long get_timer(unsigned long base) { - return get_timer_masked() - base; + ulong now = timer_get_us_down(); + + /* + * Increment the time by the amount elapsed since the last read. + * The timer may have wrapped around, but it makes no difference to + * our arithmetic here. + */ + gd->arch.timer_reset_value += gd->arch.lastinc - now; + gd->arch.lastinc = now; + + /* Divide by 1000 to convert from us to ms */ + return gd->arch.timer_reset_value / 1000 - base; }
/* delay x useconds */ void __udelay(unsigned long usec) { - struct s5p_timer *const timer = s5p_get_base_timer(); - unsigned long tmo, tmp, count_value; - - count_value = readl(&timer->tcntb4); - - if (usec >= 1000) { - /* - * if "big" number, spread normalization - * to seconds - * 1. start to normalize for usec to ticks per sec - * 2. find number of "ticks" to wait to achieve target - * 3. finish normalize. - */ - tmo = usec / 1000; - tmo *= (CONFIG_SYS_HZ * count_value); - tmo /= 1000; - } else { - /* else small number, don't kill it prior to HZ multiply */ - tmo = usec * CONFIG_SYS_HZ * count_value; - tmo /= (1000 * 1000); - } - - /* get current timestamp */ - tmp = get_current_tick(); - - /* if setting this fordward will roll time stamp */ - /* reset "advancing" timestamp to 0, set lastinc value */ - /* else, set advancing stamp wake up time */ - if ((tmo + tmp + 1) < tmp) - reset_timer_masked(); - else - tmo += tmp; - - /* loop till event */ - while (get_current_tick() < tmo) - ; /* nop */ + unsigned long count_value; + + count_value = timer_get_us_down(); + while ((int)(count_value - timer_get_us_down()) < (int)usec) + ; }
void reset_timer_masked(void) @@ -109,30 +109,6 @@ void reset_timer_masked(void) gd->arch.tbl = 0; }
-unsigned long get_timer_masked(void) -{ - struct s5p_timer *const timer = s5p_get_base_timer(); - unsigned long count_value = readl(&timer->tcntb4); - - return get_current_tick() / count_value; -} - -unsigned long get_current_tick(void) -{ - struct s5p_timer *const timer = s5p_get_base_timer(); - unsigned long now = readl(&timer->tcnto4); - unsigned long count_value = readl(&timer->tcntb4); - - if (gd->arch.lastinc >= now) - gd->arch.tbl += gd->arch.lastinc - now; - else - gd->arch.tbl += gd->arch.lastinc + count_value - now; - - gd->arch.lastinc = now; - - return gd->arch.tbl; -} - /* * This function is derived from PowerPC code (read timebase as long long). * On ARM it just returns the timer value.

On Wed, Feb 27, 2013 at 2:02 AM, Akshay Saraswat akshay.s@samsung.com wrote:
At present get_timer() does not return sane values. It should count up smoothly in milliscond intervals.
We can change the PWM to count down at 1MHz, providing a resolution of 1us and a range of about an hour between required get_timer() calls.
TEST=sf probe 1:0; time sf read 40008000 0 1000 Try with different numbers of bytes and see that sane values are obtained
Signed-off-by: Simon Glass sjg@chromium.org Signed-off-by: Akshay Saraswat akshay.s@samsung.com
Acked-by: Simon Glass sjg@chromium.org
arch/arm/cpu/armv7/s5p-common/pwm.c | 6 ++ arch/arm/cpu/armv7/s5p-common/timer.c | 100 +++++++++++++--------------------- 2 files changed, 44 insertions(+), 62 deletions(-)
diff --git a/arch/arm/cpu/armv7/s5p-common/pwm.c b/arch/arm/cpu/armv7/s5p-common/pwm.c index 44d7bc3..3147f59 100644 --- a/arch/arm/cpu/armv7/s5p-common/pwm.c +++ b/arch/arm/cpu/armv7/s5p-common/pwm.c @@ -174,6 +174,12 @@ int pwm_init(int pwm_id, int div, int invert)
/* set count value */ offset = pwm_id * 3;
/*
* TODO(sjg): Use this as a countdown timer for now. We count down
* from the maximum value to 0, then reset.
*/
timer_rate_hz = -1; writel(timer_rate_hz, &pwm->tcntb0 + offset); val = readl(&pwm->tcon) & ~(0xf << TCON_OFFSET(pwm_id));
diff --git a/arch/arm/cpu/armv7/s5p-common/timer.c b/arch/arm/cpu/armv7/s5p-common/timer.c index e78c716..c48a297 100644 --- a/arch/arm/cpu/armv7/s5p-common/timer.c +++ b/arch/arm/cpu/armv7/s5p-common/timer.c @@ -39,13 +39,33 @@ static inline struct s5p_timer *s5p_get_base_timer(void) return (struct s5p_timer *)samsung_get_base_timer(); }
+/**
- Read the countdown timer.
- This operates at 1MHz and counts downwards. It will wrap about every
- hour (2^32 microseconds).
- @return current value of timer
- */
+static unsigned long timer_get_us_down(void) +{
struct s5p_timer *const timer = s5p_get_base_timer();
return readl(&timer->tcnto4);
+}
int timer_init(void) { /* PWM Timer 4 */
pwm_init(4, MUX_DIV_2, 0);
pwm_init(4, MUX_DIV_4, 0); pwm_config(4, 0, 0); pwm_enable(4);
/* Use this as the current monotonic time in us */
gd->arch.timer_reset_value = 0;
/* Use this as the last timer value we saw */
gd->arch.lastinc = timer_get_us_down(); reset_timer_masked(); return 0;
@@ -56,48 +76,28 @@ int timer_init(void) */ unsigned long get_timer(unsigned long base) {
return get_timer_masked() - base;
ulong now = timer_get_us_down();
/*
* Increment the time by the amount elapsed since the last read.
* The timer may have wrapped around, but it makes no difference to
* our arithmetic here.
*/
gd->arch.timer_reset_value += gd->arch.lastinc - now;
gd->arch.lastinc = now;
/* Divide by 1000 to convert from us to ms */
return gd->arch.timer_reset_value / 1000 - base;
}
/* delay x useconds */ void __udelay(unsigned long usec) {
struct s5p_timer *const timer = s5p_get_base_timer();
unsigned long tmo, tmp, count_value;
count_value = readl(&timer->tcntb4);
if (usec >= 1000) {
/*
* if "big" number, spread normalization
* to seconds
* 1. start to normalize for usec to ticks per sec
* 2. find number of "ticks" to wait to achieve target
* 3. finish normalize.
*/
tmo = usec / 1000;
tmo *= (CONFIG_SYS_HZ * count_value);
tmo /= 1000;
} else {
/* else small number, don't kill it prior to HZ multiply */
tmo = usec * CONFIG_SYS_HZ * count_value;
tmo /= (1000 * 1000);
}
/* get current timestamp */
tmp = get_current_tick();
/* if setting this fordward will roll time stamp */
/* reset "advancing" timestamp to 0, set lastinc value */
/* else, set advancing stamp wake up time */
if ((tmo + tmp + 1) < tmp)
reset_timer_masked();
else
tmo += tmp;
/* loop till event */
while (get_current_tick() < tmo)
; /* nop */
unsigned long count_value;
count_value = timer_get_us_down();
while ((int)(count_value - timer_get_us_down()) < (int)usec)
;
}
void reset_timer_masked(void) @@ -109,30 +109,6 @@ void reset_timer_masked(void) gd->arch.tbl = 0; }
-unsigned long get_timer_masked(void) -{
struct s5p_timer *const timer = s5p_get_base_timer();
unsigned long count_value = readl(&timer->tcntb4);
return get_current_tick() / count_value;
-}
-unsigned long get_current_tick(void) -{
struct s5p_timer *const timer = s5p_get_base_timer();
unsigned long now = readl(&timer->tcnto4);
unsigned long count_value = readl(&timer->tcntb4);
if (gd->arch.lastinc >= now)
gd->arch.tbl += gd->arch.lastinc - now;
else
gd->arch.tbl += gd->arch.lastinc + count_value - now;
gd->arch.lastinc = now;
return gd->arch.tbl;
-}
/*
- This function is derived from PowerPC code (read timebase as long long).
- On ARM it just returns the timer value.
-- 1.8.0

timer_get_us returns the time in microseconds since a certain reference point of history. However, it does not guarantee to return an accurate time after a long period; instead, it wraps around (that is, the reference point is reset to some other point of history) after some periods. The frequency of wrapping around is about an hour (or 2^32 microseconds).
TEST=sf probe 1:0; time sf read 40008000 0 1000 Try with different numbers of bytes and see that sane values are obtained
Signed-off-by: Che-Liang Chiou clchiou@chromium.org Signed-off-by: Akshay Saraswat akshay.s@samsung.com --- arch/arm/cpu/armv7/s5p-common/timer.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+)
diff --git a/arch/arm/cpu/armv7/s5p-common/timer.c b/arch/arm/cpu/armv7/s5p-common/timer.c index c48a297..de61405 100644 --- a/arch/arm/cpu/armv7/s5p-common/timer.c +++ b/arch/arm/cpu/armv7/s5p-common/timer.c @@ -90,6 +90,21 @@ unsigned long get_timer(unsigned long base) return gd->arch.timer_reset_value / 1000 - base; }
+unsigned long timer_get_us(void) +{ + static unsigned long base_time_us; + + struct s5p_timer *const timer = + (struct s5p_timer *)samsung_get_base_timer(); + unsigned long now_downward_us = readl(&timer->tcnto4); + + if (!base_time_us) + base_time_us = now_downward_us; + + /* Note that this timer counts downward. */ + return base_time_us - now_downward_us; +} + /* delay x useconds */ void __udelay(unsigned long usec) {

On Wed, Feb 27, 2013 at 2:02 AM, Akshay Saraswat akshay.s@samsung.com wrote:
timer_get_us returns the time in microseconds since a certain reference point of history. However, it does not guarantee to return an accurate time after a long period; instead, it wraps around (that is, the reference point is reset to some other point of history) after some periods. The frequency of wrapping around is about an hour (or 2^32 microseconds).
TEST=sf probe 1:0; time sf read 40008000 0 1000 Try with different numbers of bytes and see that sane values are obtained
Signed-off-by: Che-Liang Chiou clchiou@chromium.org Signed-off-by: Akshay Saraswat akshay.s@samsung.com
Acked-by: Simon Glass sjg@chromium.org
arch/arm/cpu/armv7/s5p-common/timer.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+)
diff --git a/arch/arm/cpu/armv7/s5p-common/timer.c b/arch/arm/cpu/armv7/s5p-common/timer.c index c48a297..de61405 100644 --- a/arch/arm/cpu/armv7/s5p-common/timer.c +++ b/arch/arm/cpu/armv7/s5p-common/timer.c @@ -90,6 +90,21 @@ unsigned long get_timer(unsigned long base) return gd->arch.timer_reset_value / 1000 - base; }
+unsigned long timer_get_us(void) +{
static unsigned long base_time_us;
struct s5p_timer *const timer =
(struct s5p_timer *)samsung_get_base_timer();
unsigned long now_downward_us = readl(&timer->tcnto4);
if (!base_time_us)
base_time_us = now_downward_us;
/* Note that this timer counts downward. */
return base_time_us - now_downward_us;
+}
/* delay x useconds */ void __udelay(unsigned long usec) { -- 1.8.0

First, the "div" value was being used incorrectly to compute the frequency of the PWM timer. The value passed in is a constant which reflects the value that would be found in a configuration register, 0 to 4. That should correspond to a scaling factor of 1, 2, 4, 8, or 16, 1 << div, but div + 1 was being used instead.
Second, the reset value of the timers were being calculated to give an overall frequency, thrown out, and set to a maximum value. This was done so that PWM 4 could be used as the system clock by counting down from a high value, but it was applied indiscriminantly. It should at most be applied only to PWM 4.
This change also takes the opportunity to tidy up the pwm_init function.
TEST=sf probe 1:0; time sf read 40008000 0 1000 Try with different numbers of bytes and see that sane values are obtained Build and boot U-boot with this patch, backlight works properly.
Signed-off-by: Gabe Black gabeblack@google.com Signed-off-by: Akshay Saraswat akshay.s@samsung.com --- arch/arm/cpu/armv7/s5p-common/pwm.c | 24 ++++++++++++++---------- 1 file changed, 14 insertions(+), 10 deletions(-)
diff --git a/arch/arm/cpu/armv7/s5p-common/pwm.c b/arch/arm/cpu/armv7/s5p-common/pwm.c index 3147f59..02156d1 100644 --- a/arch/arm/cpu/armv7/s5p-common/pwm.c +++ b/arch/arm/cpu/armv7/s5p-common/pwm.c @@ -143,7 +143,7 @@ int pwm_init(int pwm_id, int div, int invert) u32 val; const struct s5p_timer *pwm = (struct s5p_timer *)samsung_get_base_timer(); - unsigned long timer_rate_hz; + unsigned long ticks_per_period; unsigned int offset, prescaler;
/* @@ -167,20 +167,24 @@ int pwm_init(int pwm_id, int div, int invert) val |= (div & 0xf) << MUX_DIV_SHIFT(pwm_id); writel(val, &pwm->tcfg1);
- timer_rate_hz = get_pwm_clk() / ((prescaler + 1) * - (div + 1)); + if (pwm_id == 4) { + /* + * TODO(sjg): Use this as a countdown timer for now. We count + * down from the maximum value to 0, then reset. + */ + ticks_per_period = -1UL; + } else { + const unsigned long pwm_hz = 1000; + unsigned long timer_rate_hz = get_pwm_clk() / + ((prescaler + 1) * (1 << div));
- timer_rate_hz = timer_rate_hz / CONFIG_SYS_HZ; + ticks_per_period = timer_rate_hz / pwm_hz; + }
/* set count value */ offset = pwm_id * 3;
- /* - * TODO(sjg): Use this as a countdown timer for now. We count down - * from the maximum value to 0, then reset. - */ - timer_rate_hz = -1; - writel(timer_rate_hz, &pwm->tcntb0 + offset); + writel(ticks_per_period, &pwm->tcntb0 + offset);
val = readl(&pwm->tcon) & ~(0xf << TCON_OFFSET(pwm_id)); if (invert && (pwm_id < 4))

On Wed, Feb 27, 2013 at 2:02 AM, Akshay Saraswat akshay.s@samsung.com wrote:
First, the "div" value was being used incorrectly to compute the frequency of the PWM timer. The value passed in is a constant which reflects the value that would be found in a configuration register, 0 to 4. That should correspond to a scaling factor of 1, 2, 4, 8, or 16, 1 << div, but div + 1 was being used instead.
Second, the reset value of the timers were being calculated to give an overall frequency, thrown out, and set to a maximum value. This was done so that PWM 4 could be used as the system clock by counting down from a high value, but it was applied indiscriminantly. It should at most be applied only to PWM 4.
This change also takes the opportunity to tidy up the pwm_init function.
TEST=sf probe 1:0; time sf read 40008000 0 1000 Try with different numbers of bytes and see that sane values are obtained Build and boot U-boot with this patch, backlight works properly.
Signed-off-by: Gabe Black gabeblack@google.com Signed-off-by: Akshay Saraswat akshay.s@samsung.com
Acked-by: Simon Glass sjg@chromium.org
If you redo this patch, I suggest you remove the TODOs.
arch/arm/cpu/armv7/s5p-common/pwm.c | 24 ++++++++++++++---------- 1 file changed, 14 insertions(+), 10 deletions(-)
diff --git a/arch/arm/cpu/armv7/s5p-common/pwm.c b/arch/arm/cpu/armv7/s5p-common/pwm.c index 3147f59..02156d1 100644 --- a/arch/arm/cpu/armv7/s5p-common/pwm.c +++ b/arch/arm/cpu/armv7/s5p-common/pwm.c @@ -143,7 +143,7 @@ int pwm_init(int pwm_id, int div, int invert) u32 val; const struct s5p_timer *pwm = (struct s5p_timer *)samsung_get_base_timer();
unsigned long timer_rate_hz;
unsigned long ticks_per_period; unsigned int offset, prescaler; /*
@@ -167,20 +167,24 @@ int pwm_init(int pwm_id, int div, int invert) val |= (div & 0xf) << MUX_DIV_SHIFT(pwm_id); writel(val, &pwm->tcfg1);
timer_rate_hz = get_pwm_clk() / ((prescaler + 1) *
(div + 1));
if (pwm_id == 4) {
/*
* TODO(sjg): Use this as a countdown timer for now. We count
* down from the maximum value to 0, then reset.
*/
ticks_per_period = -1UL;
} else {
const unsigned long pwm_hz = 1000;
unsigned long timer_rate_hz = get_pwm_clk() /
((prescaler + 1) * (1 << div));
timer_rate_hz = timer_rate_hz / CONFIG_SYS_HZ;
ticks_per_period = timer_rate_hz / pwm_hz;
} /* set count value */ offset = pwm_id * 3;
/*
* TODO(sjg): Use this as a countdown timer for now. We count down
* from the maximum value to 0, then reset.
*/
timer_rate_hz = -1;
writel(timer_rate_hz, &pwm->tcntb0 + offset);
writel(ticks_per_period, &pwm->tcntb0 + offset); val = readl(&pwm->tcon) & ~(0xf << TCON_OFFSET(pwm_id)); if (invert && (pwm_id < 4))
-- 1.8.0

The pwm_config function in the exynos pwm driver divides by its period period parameter. A function was calling pwm_config with a 0ns period and a 0ns duty cycle. That doesn't actually make any sense physically, and results in a divide by zero in the driver. This change changes the paremters to be a 100000ns period and duty cycle.
TEST=sf probe 1:0; time sf read 40008000 0 1000 Try with different numbers of bytes and see that sane values are obtained Build and boot U-boot with this patch, backlight works properly.
Signed-off-by: Gabe Black gabeblack@google.com Signed-off-by: Akshay Saraswat akshay.s@samsung.com --- arch/arm/cpu/armv7/s5p-common/timer.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/arch/arm/cpu/armv7/s5p-common/timer.c b/arch/arm/cpu/armv7/s5p-common/timer.c index de61405..6a0fa58 100644 --- a/arch/arm/cpu/armv7/s5p-common/timer.c +++ b/arch/arm/cpu/armv7/s5p-common/timer.c @@ -58,7 +58,7 @@ int timer_init(void) { /* PWM Timer 4 */ pwm_init(4, MUX_DIV_4, 0); - pwm_config(4, 0, 0); + pwm_config(4, 100000, 100000); pwm_enable(4);
/* Use this as the current monotonic time in us */

On Wed, Feb 27, 2013 at 2:02 AM, Akshay Saraswat akshay.s@samsung.com wrote:
The pwm_config function in the exynos pwm driver divides by its period period parameter. A function was calling pwm_config with a 0ns period and a 0ns duty cycle. That doesn't actually make any sense physically, and results in a divide by zero in the driver. This change changes the paremters to be a 100000ns period and duty cycle.
TEST=sf probe 1:0; time sf read 40008000 0 1000 Try with different numbers of bytes and see that sane values are obtained Build and boot U-boot with this patch, backlight works properly.
Signed-off-by: Gabe Black gabeblack@google.com Signed-off-by: Akshay Saraswat akshay.s@samsung.com
Acked-by: Simon Glass sjg@chromium.org
arch/arm/cpu/armv7/s5p-common/timer.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/arch/arm/cpu/armv7/s5p-common/timer.c b/arch/arm/cpu/armv7/s5p-common/timer.c index de61405..6a0fa58 100644 --- a/arch/arm/cpu/armv7/s5p-common/timer.c +++ b/arch/arm/cpu/armv7/s5p-common/timer.c @@ -58,7 +58,7 @@ int timer_init(void) { /* PWM Timer 4 */ pwm_init(4, MUX_DIV_4, 0);
pwm_config(4, 0, 0);
pwm_config(4, 100000, 100000); pwm_enable(4); /* Use this as the current monotonic time in us */
-- 1.8.0

Some small fixes in the exynos pwm driver:
1. NS_IN_HZ is non-sensical since these are not compatible units. This constant actually describes the number of nanoseconds in a second. Renamed it to NS_IN_SEC. Also dropped the unnecessary parenthesis. 2. The variable "period" is not used to hold a period, it's used to hold a frequency. Renamed it to "frequency". 3. tcmp is an unsigned value, so (tcmp < 0) will never be true and the if which checks that condition will never execute. Also, there should be no problem if the pwm never switches, so there's no reason to subtract one from tcmp and therefore no reason to compare it against zero. Removed both ifs. If they weren't removed, tcmp should be a signed value. 4. Add a check for a 0 period.
TEST=sf probe 1:0; time sf read 40008000 0 1000 Try with different numbers of bytes and see that sane values are obtained Build and boot U-boot with this patch, backlight works properly.
Signed-off-by: Gabe Black gabeblack@google.com Signed-off-by: Akshay Saraswat akshay.s@samsung.com --- arch/arm/cpu/armv7/s5p-common/pwm.c | 22 ++++++---------------- 1 file changed, 6 insertions(+), 16 deletions(-)
diff --git a/arch/arm/cpu/armv7/s5p-common/pwm.c b/arch/arm/cpu/armv7/s5p-common/pwm.c index 02156d1..6f401b8 100644 --- a/arch/arm/cpu/armv7/s5p-common/pwm.c +++ b/arch/arm/cpu/armv7/s5p-common/pwm.c @@ -70,7 +70,7 @@ static unsigned long pwm_calc_tin(int pwm_id, unsigned long freq) return tin_parent_rate / 16; }
-#define NS_IN_HZ (1000000000UL) +#define NS_IN_SEC 1000000000UL
int pwm_config(int pwm_id, int duty_ns, int period_ns) { @@ -79,7 +79,7 @@ int pwm_config(int pwm_id, int duty_ns, int period_ns) unsigned int offset; unsigned long tin_rate; unsigned long tin_ns; - unsigned long period; + unsigned long frequency; unsigned long tcon; unsigned long tcnt; unsigned long tcmp; @@ -89,34 +89,24 @@ int pwm_config(int pwm_id, int duty_ns, int period_ns) * fact that anything faster than 1GHz is easily representable * by 32bits. */ - if (period_ns > NS_IN_HZ || duty_ns > NS_IN_HZ) + if (period_ns > NS_IN_SEC || duty_ns > NS_IN_SEC || period_ns == 0) return -ERANGE;
if (duty_ns > period_ns) return -EINVAL;
- period = NS_IN_HZ / period_ns; + frequency = NS_IN_SEC / period_ns;
/* Check to see if we are changing the clock rate of the PWM */ - tin_rate = pwm_calc_tin(pwm_id, period); + tin_rate = pwm_calc_tin(pwm_id, frequency);
- tin_ns = NS_IN_HZ / tin_rate; + tin_ns = NS_IN_SEC / tin_rate; tcnt = period_ns / tin_ns;
/* Note, counters count down */ tcmp = duty_ns / tin_ns; tcmp = tcnt - tcmp;
- /* - * the pwm hw only checks the compare register after a decrement, - * so the pin never toggles if tcmp = tcnt - */ - if (tcmp == tcnt) - tcmp--; - - if (tcmp < 0) - tcmp = 0; - /* Update the PWM register block. */ offset = pwm_id * 3; if (pwm_id < 4) {

On Wed, Feb 27, 2013 at 2:02 AM, Akshay Saraswat akshay.s@samsung.com wrote:
Some small fixes in the exynos pwm driver:
- NS_IN_HZ is non-sensical since these are not compatible units. This
constant actually describes the number of nanoseconds in a second. Renamed it to NS_IN_SEC. Also dropped the unnecessary parenthesis. 2. The variable "period" is not used to hold a period, it's used to hold a frequency. Renamed it to "frequency". 3. tcmp is an unsigned value, so (tcmp < 0) will never be true and the if which checks that condition will never execute. Also, there should be no problem if the pwm never switches, so there's no reason to subtract one from tcmp and therefore no reason to compare it against zero. Removed both ifs. If they weren't removed, tcmp should be a signed value. 4. Add a check for a 0 period.
TEST=sf probe 1:0; time sf read 40008000 0 1000 Try with different numbers of bytes and see that sane values are obtained Build and boot U-boot with this patch, backlight works properly.
Signed-off-by: Gabe Black gabeblack@google.com Signed-off-by: Akshay Saraswat akshay.s@samsung.com
Acked-by: Simon Glass sjg@chromium.org
arch/arm/cpu/armv7/s5p-common/pwm.c | 22 ++++++---------------- 1 file changed, 6 insertions(+), 16 deletions(-)
diff --git a/arch/arm/cpu/armv7/s5p-common/pwm.c b/arch/arm/cpu/armv7/s5p-common/pwm.c index 02156d1..6f401b8 100644 --- a/arch/arm/cpu/armv7/s5p-common/pwm.c +++ b/arch/arm/cpu/armv7/s5p-common/pwm.c @@ -70,7 +70,7 @@ static unsigned long pwm_calc_tin(int pwm_id, unsigned long freq) return tin_parent_rate / 16; }
-#define NS_IN_HZ (1000000000UL) +#define NS_IN_SEC 1000000000UL
int pwm_config(int pwm_id, int duty_ns, int period_ns) { @@ -79,7 +79,7 @@ int pwm_config(int pwm_id, int duty_ns, int period_ns) unsigned int offset; unsigned long tin_rate; unsigned long tin_ns;
unsigned long period;
unsigned long frequency; unsigned long tcon; unsigned long tcnt; unsigned long tcmp;
@@ -89,34 +89,24 @@ int pwm_config(int pwm_id, int duty_ns, int period_ns) * fact that anything faster than 1GHz is easily representable * by 32bits. */
if (period_ns > NS_IN_HZ || duty_ns > NS_IN_HZ)
if (period_ns > NS_IN_SEC || duty_ns > NS_IN_SEC || period_ns == 0) return -ERANGE; if (duty_ns > period_ns) return -EINVAL;
period = NS_IN_HZ / period_ns;
frequency = NS_IN_SEC / period_ns; /* Check to see if we are changing the clock rate of the PWM */
tin_rate = pwm_calc_tin(pwm_id, period);
tin_rate = pwm_calc_tin(pwm_id, frequency);
tin_ns = NS_IN_HZ / tin_rate;
tin_ns = NS_IN_SEC / tin_rate; tcnt = period_ns / tin_ns; /* Note, counters count down */ tcmp = duty_ns / tin_ns; tcmp = tcnt - tcmp;
/*
* the pwm hw only checks the compare register after a decrement,
* so the pin never toggles if tcmp = tcnt
*/
if (tcmp == tcnt)
tcmp--;
if (tcmp < 0)
tcmp = 0;
/* Update the PWM register block. */ offset = pwm_id * 3; if (pwm_id < 4) {
-- 1.8.0

Add peripherial id for pwm inorder to support generic api to get the clk frequency
TEST=sf probe 1:0; time sf read 40008000 0 1000 Try with different numbers of bytes and see that sane values are obtained Build and boot U-boot with this patch, backlight works properly.
Signed-off-by: Padmavathi Venna padma.v@samsung.com Signed-off-by: Akshay Saraswat akshay.s@samsung.com --- arch/arm/include/asm/arch-exynos/periph.h | 5 +++++ 1 file changed, 5 insertions(+)
diff --git a/arch/arm/include/asm/arch-exynos/periph.h b/arch/arm/include/asm/arch-exynos/periph.h index 89bcdfc..e5aed4b 100644 --- a/arch/arm/include/asm/arch-exynos/periph.h +++ b/arch/arm/include/asm/arch-exynos/periph.h @@ -61,6 +61,11 @@ enum periph_id { PERIPH_ID_SPI3, PERIPH_ID_SPI4, PERIPH_ID_SDMMC4, + PERIPH_ID_PWM0, + PERIPH_ID_PWM1, + PERIPH_ID_PWM2, + PERIPH_ID_PWM3, + PERIPH_ID_PWM4,
PERIPH_ID_COUNT, PERIPH_ID_NONE = -1,

Hi Akshay,
On Wed, Feb 27, 2013 at 2:02 AM, Akshay Saraswat akshay.s@samsung.com wrote:
Add peripherial id for pwm inorder to support generic api to get the clk frequency
TEST=sf probe 1:0; time sf read 40008000 0 1000 Try with different numbers of bytes and see that sane values are obtained Build and boot U-boot with this patch, backlight works properly.
Signed-off-by: Padmavathi Venna padma.v@samsung.com Signed-off-by: Akshay Saraswat akshay.s@samsung.com
arch/arm/include/asm/arch-exynos/periph.h | 5 +++++ 1 file changed, 5 insertions(+)
diff --git a/arch/arm/include/asm/arch-exynos/periph.h b/arch/arm/include/asm/arch-exynos/periph.h index 89bcdfc..e5aed4b 100644 --- a/arch/arm/include/asm/arch-exynos/periph.h +++ b/arch/arm/include/asm/arch-exynos/periph.h @@ -61,6 +61,11 @@ enum periph_id { PERIPH_ID_SPI3, PERIPH_ID_SPI4, PERIPH_ID_SDMMC4,
PERIPH_ID_PWM0,
PERIPH_ID_PWM1,
PERIPH_ID_PWM2,
PERIPH_ID_PWM3,
PERIPH_ID_PWM4,
I don't believe this file is used now.
Regards, Simon
PERIPH_ID_COUNT, PERIPH_ID_NONE = -1,
-- 1.8.0

Add generic api to get the frequency of the required peripherial. This API gets the source clock frequency and returns the required frequency by dividing with first and second dividers based on the requirement.
TEST=sf probe 1:0; time sf read 40008000 0 1000 Try with different numbers of bytes and see that sane values are obtained Build and boot U-boot with this patch, backlight works properly.
Signed-off-by: Padmavathi Venna padma.v@samsung.com Signed-off-by: Akshay Saraswat akshay.s@samsung.com --- arch/arm/cpu/armv7/exynos/clock.c | 127 +++++++++++++++++++++++++++++++++ arch/arm/include/asm/arch-exynos/clk.h | 27 +++++++ 2 files changed, 154 insertions(+)
diff --git a/arch/arm/cpu/armv7/exynos/clock.c b/arch/arm/cpu/armv7/exynos/clock.c index 956427c..a7a3066 100644 --- a/arch/arm/cpu/armv7/exynos/clock.c +++ b/arch/arm/cpu/armv7/exynos/clock.c @@ -27,6 +27,39 @@ #include <asm/arch/clk.h> #include <asm/arch/periph.h>
+/* src_bit div_bit prediv_bit */ +static struct clk_bit_info clk_bit_info[PERIPH_ID_COUNT] = { + {0, 0, -1}, + {4, 4, -1}, + {8, 8, -1}, + {12, 12, -1}, + {0, 0, 8}, + {4, 16, 24}, + {8, 0, 8}, + {12, 16, 24}, + {-1, -1, -1}, + {16, 0, 8}, + {20, 16, 24}, + {24, 0, 8}, + {0, 0, 4}, + {4, 12, 16}, + {-1, -1, -1}, + {-1, -1, -1}, + {-1, 24, 0}, + {-1, 24, 0}, + {-1, 24, 0}, + {-1, 24, 0}, + {-1, 24, 0}, + {-1, 24, 0}, + {-1, 24, 0}, + {-1, 24, 0}, + {24, 0, -1}, + {24, 0, -1}, + {24, 0, -1}, + {24, 0, -1}, + {24, 0, -1}, +}; + /* Epll Clock division values to achive different frequency output */ static struct set_epll_con_val exynos5_epll_div[] = { { 192000000, 0, 48, 3, 1, 0 }, @@ -201,6 +234,100 @@ static unsigned long exynos5_get_pll_clk(int pllreg) return fout; }
+unsigned long exynos5_get_periph_rate(enum periph_id peripheral) +{ + struct clk_bit_info *bit_info = &clk_bit_info[peripheral]; + unsigned long sclk, sub_clk; + unsigned int src, div, sub_div; + struct exynos5_clock *clk = + (struct exynos5_clock *)samsung_get_base_clock(); + + switch (peripheral) { + case PERIPH_ID_UART0: + case PERIPH_ID_UART1: + case PERIPH_ID_UART2: + case PERIPH_ID_UART3: + src = readl(&clk->src_peric0); + div = readl(&clk->div_peric0); + break; + case PERIPH_ID_PWM0: + case PERIPH_ID_PWM1: + case PERIPH_ID_PWM2: + case PERIPH_ID_PWM3: + case PERIPH_ID_PWM4: + src = readl(&clk->src_peric0); + div = readl(&clk->div_peric3); + break; + case PERIPH_ID_SPI0: + case PERIPH_ID_SPI1: + src = readl(&clk->src_peric1); + div = readl(&clk->div_peric1); + break; + case PERIPH_ID_SPI2: + src = readl(&clk->src_peric1); + div = readl(&clk->div_peric2); + break; + case PERIPH_ID_SPI3: + case PERIPH_ID_SPI4: + src = readl(&clk->sclk_src_isp); + div = readl(&clk->sclk_div_isp); + break; + case PERIPH_ID_SDMMC0: + case PERIPH_ID_SDMMC1: + case PERIPH_ID_SDMMC2: + case PERIPH_ID_SDMMC3: + src = readl(&clk->src_fsys); + div = readl(&clk->div_fsys1); + break; + case PERIPH_ID_I2C0: + case PERIPH_ID_I2C1: + case PERIPH_ID_I2C2: + case PERIPH_ID_I2C3: + case PERIPH_ID_I2C4: + case PERIPH_ID_I2C5: + case PERIPH_ID_I2C6: + case PERIPH_ID_I2C7: + sclk = exynos5_get_pll_clk(MPLL); + sub_div = ((readl(&clk->div_top1) >> bit_info->div_bit) & 0x7) + 1; + div = ((readl(&clk->div_top0) >> bit_info->prediv_bit) & 0x7) + 1; + return (sclk / sub_div) / div; + default: + debug("%s: invalid peripheral %d", __func__, peripheral); + return -1; + }; + + src = (src >> bit_info->src_bit) & 0xf; + if (src == SRC_MPLL) + sclk = exynos5_get_pll_clk(MPLL); + else if (src == SRC_EPLL) + sclk = exynos5_get_pll_clk(EPLL); + else if (src == SRC_VPLL) + sclk = exynos5_get_pll_clk(VPLL); + else + return 0; + + sub_div = (div >> bit_info->div_bit) & 0xf; + sub_clk = sclk / (sub_div + 1); + + if (peripheral == PERIPH_ID_SDMMC0 || peripheral == PERIPH_ID_SDMMC2) { + div = (div >> bit_info->prediv_bit) & 0xff; + return sub_clk / (div + 1); + } + + return sub_clk; +} + +unsigned long clock_get_periph_rate(enum periph_id peripheral) +{ + if (cpu_is_exynos5()) + return exynos5_get_periph_rate(peripheral); + else { + if (proid_is_exynos4412()) + return 0; + return 0; + } +} + /* exynos4: return ARM clock frequency */ static unsigned long exynos4_get_arm_clk(void) { diff --git a/arch/arm/include/asm/arch-exynos/clk.h b/arch/arm/include/asm/arch-exynos/clk.h index 1935b0b..b459b16 100644 --- a/arch/arm/include/asm/arch-exynos/clk.h +++ b/arch/arm/include/asm/arch-exynos/clk.h @@ -22,6 +22,8 @@ #ifndef __ASM_ARM_ARCH_CLK_H_ #define __ASM_ARM_ARCH_CLK_H_
+#include <asm/arch/periph.h> + #define APLL 0 #define MPLL 1 #define EPLL 2 @@ -29,6 +31,22 @@ #define VPLL 4 #define BPLL 5
+enum pll_src_bit { + SRC_MPLL = 6, + SRC_EPLL, + SRC_VPLL, +}; + +/* * + * This structure is to store the src bit, div bit and prediv bit + * positions of the peripheral clocks of the src and div registers + */ +struct clk_bit_info { + int src_bit; + int div_bit; + int prediv_bit; +}; + unsigned long get_pll_clk(int pllreg); unsigned long get_arm_clk(void); unsigned long get_i2c_clk(void); @@ -44,4 +62,13 @@ int set_i2s_clk_prescaler(unsigned int src_frq, unsigned int dst_frq); int set_epll_clk(unsigned long rate); int set_spi_clk(int periph_id, unsigned int rate);
+/** + * get the clk frequency of the required peripherial + * + * @param peripherial Peripherial id + * + * @return frequency of the peripherial clk + */ +unsigned long clock_get_periph_rate(enum periph_id peripheral); + #endif

Hi Akshay,
On Wed, Feb 27, 2013 at 2:02 AM, Akshay Saraswat akshay.s@samsung.com wrote:
Add generic api to get the frequency of the required peripherial. This API gets the source clock frequency and returns the required frequency by dividing with first and second dividers based on the requirement.
TEST=sf probe 1:0; time sf read 40008000 0 1000 Try with different numbers of bytes and see that sane values are obtained Build and boot U-boot with this patch, backlight works properly.
Please remove the TEST= stuff. patman might do the first line for you (and will print a warning).
Signed-off-by: Padmavathi Venna padma.v@samsung.com Signed-off-by: Akshay Saraswat akshay.s@samsung.com
arch/arm/cpu/armv7/exynos/clock.c | 127 +++++++++++++++++++++++++++++++++ arch/arm/include/asm/arch-exynos/clk.h | 27 +++++++ 2 files changed, 154 insertions(+)
diff --git a/arch/arm/cpu/armv7/exynos/clock.c b/arch/arm/cpu/armv7/exynos/clock.c index 956427c..a7a3066 100644 --- a/arch/arm/cpu/armv7/exynos/clock.c +++ b/arch/arm/cpu/armv7/exynos/clock.c @@ -27,6 +27,39 @@ #include <asm/arch/clk.h> #include <asm/arch/periph.h>
+/* src_bit div_bit prediv_bit */ +static struct clk_bit_info clk_bit_info[PERIPH_ID_COUNT] = {
{0, 0, -1},
{4, 4, -1},
{8, 8, -1},
{12, 12, -1},
{0, 0, 8},
{4, 16, 24},
{8, 0, 8},
{12, 16, 24},
{-1, -1, -1},
{16, 0, 8},
{20, 16, 24},
{24, 0, 8},
{0, 0, 4},
{4, 12, 16},
{-1, -1, -1},
{-1, -1, -1},
{-1, 24, 0},
{-1, 24, 0},
{-1, 24, 0},
{-1, 24, 0},
{-1, 24, 0},
{-1, 24, 0},
{-1, 24, 0},
{-1, 24, 0},
{24, 0, -1},
{24, 0, -1},
{24, 0, -1},
{24, 0, -1},
{24, 0, -1},
+};
/* Epll Clock division values to achive different frequency output */ static struct set_epll_con_val exynos5_epll_div[] = { { 192000000, 0, 48, 3, 1, 0 }, @@ -201,6 +234,100 @@ static unsigned long exynos5_get_pll_clk(int pllreg) return fout; }
+unsigned long exynos5_get_periph_rate(enum periph_id peripheral) +{
struct clk_bit_info *bit_info = &clk_bit_info[peripheral];
unsigned long sclk, sub_clk;
unsigned int src, div, sub_div;
struct exynos5_clock *clk =
(struct exynos5_clock *)samsung_get_base_clock();
switch (peripheral) {
case PERIPH_ID_UART0:
case PERIPH_ID_UART1:
case PERIPH_ID_UART2:
case PERIPH_ID_UART3:
src = readl(&clk->src_peric0);
div = readl(&clk->div_peric0);
break;
case PERIPH_ID_PWM0:
case PERIPH_ID_PWM1:
case PERIPH_ID_PWM2:
case PERIPH_ID_PWM3:
case PERIPH_ID_PWM4:
src = readl(&clk->src_peric0);
div = readl(&clk->div_peric3);
break;
case PERIPH_ID_SPI0:
case PERIPH_ID_SPI1:
src = readl(&clk->src_peric1);
div = readl(&clk->div_peric1);
break;
case PERIPH_ID_SPI2:
src = readl(&clk->src_peric1);
div = readl(&clk->div_peric2);
break;
case PERIPH_ID_SPI3:
case PERIPH_ID_SPI4:
src = readl(&clk->sclk_src_isp);
div = readl(&clk->sclk_div_isp);
break;
case PERIPH_ID_SDMMC0:
case PERIPH_ID_SDMMC1:
case PERIPH_ID_SDMMC2:
case PERIPH_ID_SDMMC3:
src = readl(&clk->src_fsys);
div = readl(&clk->div_fsys1);
break;
case PERIPH_ID_I2C0:
case PERIPH_ID_I2C1:
case PERIPH_ID_I2C2:
case PERIPH_ID_I2C3:
case PERIPH_ID_I2C4:
case PERIPH_ID_I2C5:
case PERIPH_ID_I2C6:
case PERIPH_ID_I2C7:
sclk = exynos5_get_pll_clk(MPLL);
sub_div = ((readl(&clk->div_top1) >> bit_info->div_bit) & 0x7) + 1;
div = ((readl(&clk->div_top0) >> bit_info->prediv_bit) & 0x7) + 1;
return (sclk / sub_div) / div;
default:
debug("%s: invalid peripheral %d", __func__, peripheral);
return -1;
};
src = (src >> bit_info->src_bit) & 0xf;
if (src == SRC_MPLL)
sclk = exynos5_get_pll_clk(MPLL);
else if (src == SRC_EPLL)
sclk = exynos5_get_pll_clk(EPLL);
else if (src == SRC_VPLL)
sclk = exynos5_get_pll_clk(VPLL);
else
return 0;
sub_div = (div >> bit_info->div_bit) & 0xf;
sub_clk = sclk / (sub_div + 1);
if (peripheral == PERIPH_ID_SDMMC0 || peripheral == PERIPH_ID_SDMMC2) {
Please can you add a comment for what this if() is doing?
div = (div >> bit_info->prediv_bit) & 0xff;
return sub_clk / (div + 1);
}
return sub_clk;
+}
+unsigned long clock_get_periph_rate(enum periph_id peripheral) +{
if (cpu_is_exynos5())
return exynos5_get_periph_rate(peripheral);
else {
if (proid_is_exynos4412())
return 0;
return 0;
}
+}
/* exynos4: return ARM clock frequency */ static unsigned long exynos4_get_arm_clk(void) { diff --git a/arch/arm/include/asm/arch-exynos/clk.h b/arch/arm/include/asm/arch-exynos/clk.h index 1935b0b..b459b16 100644 --- a/arch/arm/include/asm/arch-exynos/clk.h +++ b/arch/arm/include/asm/arch-exynos/clk.h @@ -22,6 +22,8 @@ #ifndef __ASM_ARM_ARCH_CLK_H_ #define __ASM_ARM_ARCH_CLK_H_
+#include <asm/arch/periph.h>
#define APLL 0 #define MPLL 1 #define EPLL 2 @@ -29,6 +31,22 @@ #define VPLL 4 #define BPLL 5
Suggest EXYNOS_ prefix on these
+enum pll_src_bit {
SRC_MPLL = 6,
SRC_EPLL,
SRC_VPLL,
+};
+/* *
- This structure is to store the src bit, div bit and prediv bit
- positions of the peripheral clocks of the src and div registers
- */
+struct clk_bit_info {
int src_bit;
int div_bit;
int prediv_bit;
Should these perhaps be int8_t ? Can this structure move to the C file?
+};
unsigned long get_pll_clk(int pllreg); unsigned long get_arm_clk(void); unsigned long get_i2c_clk(void); @@ -44,4 +62,13 @@ int set_i2s_clk_prescaler(unsigned int src_frq, unsigned int dst_frq); int set_epll_clk(unsigned long rate); int set_spi_clk(int periph_id, unsigned int rate);
+/**
- get the clk frequency of the required peripherial
- @param peripherial Peripherial id
- @return frequency of the peripherial clk
- */
+unsigned long clock_get_periph_rate(enum periph_id peripheral);
#endif
1.8.0
Regards, Simon

MPLL is selected as the source clk of pwm by default
TEST=sf probe 1:0; time sf read 40008000 0 1000 Try with different numbers of bytes and see that sane values are obtained Build and boot U-boot with this patch, backlight works properly.
Signed-off-by: Padmavathi Venna padma.v@samsung.com Signed-off-by: Akshay Saraswat akshay.s@samsung.com --- board/samsung/smdk5250/setup.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/board/samsung/smdk5250/setup.h b/board/samsung/smdk5250/setup.h index a159601..34d8bc3 100644 --- a/board/samsung/smdk5250/setup.h +++ b/board/samsung/smdk5250/setup.h @@ -343,7 +343,7 @@ #define TOP2_VAL 0x0110000
/* CLK_SRC_PERIC0 */ -#define PWM_SEL 0 +#define PWM_SEL 6 #define UART3_SEL 6 #define UART2_SEL 6 #define UART1_SEL 6

Use generic api to get the pwm clock frequency
TEST=sf probe 1:0; time sf read 40008000 0 1000 Try with different numbers of bytes and see that sane values are obtained Build and boot U-boot with this patch, backlight works properly.
Signed-off-by: Padmavathi Venna padma.v@samsung.com Signed-off-by: Akshay Saraswat akshay.s@samsung.com --- arch/arm/cpu/armv7/s5p-common/pwm.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-)
diff --git a/arch/arm/cpu/armv7/s5p-common/pwm.c b/arch/arm/cpu/armv7/s5p-common/pwm.c index 6f401b8..06e0351 100644 --- a/arch/arm/cpu/armv7/s5p-common/pwm.c +++ b/arch/arm/cpu/armv7/s5p-common/pwm.c @@ -28,6 +28,7 @@ #include <asm/io.h> #include <asm/arch/pwm.h> #include <asm/arch/clk.h> +#include <asm/arch/periph.h>
int pwm_enable(int pwm_id) { @@ -60,7 +61,7 @@ static unsigned long pwm_calc_tin(int pwm_id, unsigned long freq) unsigned long tin_parent_rate; unsigned int div;
- tin_parent_rate = get_pwm_clk(); + tin_parent_rate = clock_get_periph_rate(PERIPH_ID_PWM0);
for (div = 2; div <= 16; div *= 2) { if ((tin_parent_rate / (div << 16)) < freq) @@ -165,8 +166,8 @@ int pwm_init(int pwm_id, int div, int invert) ticks_per_period = -1UL; } else { const unsigned long pwm_hz = 1000; - unsigned long timer_rate_hz = get_pwm_clk() / - ((prescaler + 1) * (1 << div)); + unsigned long timer_rate_hz = clock_get_periph_rate( + PERIPH_ID_PWM0) / ((prescaler + 1) * (1 << div));
ticks_per_period = timer_rate_hz / pwm_hz; }

On Wed, Feb 27, 2013 at 2:02 AM, Akshay Saraswat akshay.s@samsung.com wrote:
Use generic api to get the pwm clock frequency
TEST=sf probe 1:0; time sf read 40008000 0 1000 Try with different numbers of bytes and see that sane values are obtained Build and boot U-boot with this patch, backlight works properly.
Signed-off-by: Padmavathi Venna padma.v@samsung.com Signed-off-by: Akshay Saraswat akshay.s@samsung.com
Acked-by: Simon Glass sjg@chromium.org
arch/arm/cpu/armv7/s5p-common/pwm.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-)
diff --git a/arch/arm/cpu/armv7/s5p-common/pwm.c b/arch/arm/cpu/armv7/s5p-common/pwm.c index 6f401b8..06e0351 100644 --- a/arch/arm/cpu/armv7/s5p-common/pwm.c +++ b/arch/arm/cpu/armv7/s5p-common/pwm.c @@ -28,6 +28,7 @@ #include <asm/io.h> #include <asm/arch/pwm.h> #include <asm/arch/clk.h> +#include <asm/arch/periph.h>
int pwm_enable(int pwm_id) { @@ -60,7 +61,7 @@ static unsigned long pwm_calc_tin(int pwm_id, unsigned long freq) unsigned long tin_parent_rate; unsigned int div;
tin_parent_rate = get_pwm_clk();
tin_parent_rate = clock_get_periph_rate(PERIPH_ID_PWM0); for (div = 2; div <= 16; div *= 2) { if ((tin_parent_rate / (div << 16)) < freq)
@@ -165,8 +166,8 @@ int pwm_init(int pwm_id, int div, int invert) ticks_per_period = -1UL; } else { const unsigned long pwm_hz = 1000;
unsigned long timer_rate_hz = get_pwm_clk() /
((prescaler + 1) * (1 << div));
unsigned long timer_rate_hz = clock_get_periph_rate(
PERIPH_ID_PWM0) / ((prescaler + 1) * (1 << div)); ticks_per_period = timer_rate_hz / pwm_hz; }
-- 1.8.0

Hi Akshay
On Wed, Feb 27, 2013 at 3:32 PM, Akshay Saraswat akshay.s@samsung.com wrote:
Use generic api to get the pwm clock frequency
TEST=sf probe 1:0; time sf read 40008000 0 1000 Try with different numbers of bytes and see that sane values are obtained Build and boot U-boot with this patch, backlight works properly.
Signed-off-by: Padmavathi Venna padma.v@samsung.com Signed-off-by: Akshay Saraswat akshay.s@samsung.com
arch/arm/cpu/armv7/s5p-common/pwm.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-)
diff --git a/arch/arm/cpu/armv7/s5p-common/pwm.c b/arch/arm/cpu/armv7/s5p-common/pwm.c index 6f401b8..06e0351 100644 --- a/arch/arm/cpu/armv7/s5p-common/pwm.c +++ b/arch/arm/cpu/armv7/s5p-common/pwm.c @@ -28,6 +28,7 @@ #include <asm/io.h> #include <asm/arch/pwm.h> #include <asm/arch/clk.h> +#include <asm/arch/periph.h>
int pwm_enable(int pwm_id) { @@ -60,7 +61,7 @@ static unsigned long pwm_calc_tin(int pwm_id, unsigned long freq) unsigned long tin_parent_rate; unsigned int div;
tin_parent_rate = get_pwm_clk();
tin_parent_rate = clock_get_periph_rate(PERIPH_ID_PWM0);
Kindly check if it works for other S5P soc as clock_get_periph_rate is only defined for EXYNOS5.
for (div = 2; div <= 16; div *= 2) { if ((tin_parent_rate / (div << 16)) < freq)
@@ -165,8 +166,8 @@ int pwm_init(int pwm_id, int div, int invert) ticks_per_period = -1UL; } else { const unsigned long pwm_hz = 1000;
unsigned long timer_rate_hz = get_pwm_clk() /
((prescaler + 1) * (1 << div));
unsigned long timer_rate_hz = clock_get_periph_rate(
PERIPH_ID_PWM0) / ((prescaler + 1) * (1 << div)); ticks_per_period = timer_rate_hz / pwm_hz; }
-- 1.8.0
U-Boot mailing list U-Boot@lists.denx.de http://lists.denx.de/mailman/listinfo/u-boot
participants (3)
-
Akshay Saraswat
-
Rajeshwari Birje
-
Simon Glass