diff options
-rw-r--r-- | drivers/clocksource/samsung_pwm_timer.c | 157 |
1 files changed, 74 insertions, 83 deletions
diff --git a/drivers/clocksource/samsung_pwm_timer.c b/drivers/clocksource/samsung_pwm_timer.c index d9048b843546..e3257fae04e6 100644 --- a/drivers/clocksource/samsung_pwm_timer.c +++ b/drivers/clocksource/samsung_pwm_timer.c @@ -52,21 +52,25 @@ DEFINE_SPINLOCK(samsung_pwm_lock); EXPORT_SYMBOL(samsung_pwm_lock); -struct samsung_timer_source { +struct samsung_pwm_clocksource { + void __iomem *base; + unsigned int irq[SAMSUNG_PWM_NUM]; + struct samsung_pwm_variant variant; + + struct clk *timerclk; + unsigned int event_id; unsigned int source_id; unsigned int tcnt_max; unsigned int tscaler_div; unsigned int tdiv; + + unsigned long clock_count_per_tick; }; -static struct samsung_pwm *pwm; -static struct clk *timerclk; -static struct samsung_timer_source timer_source; -static unsigned long clock_count_per_tick; +static struct samsung_pwm_clocksource pwm; -static void samsung_timer_set_prescale(struct samsung_pwm *pwm, - unsigned int channel, u16 prescale) +static void samsung_timer_set_prescale(unsigned int channel, u16 prescale) { unsigned long flags; u8 shift = 0; @@ -77,30 +81,29 @@ static void samsung_timer_set_prescale(struct samsung_pwm *pwm, spin_lock_irqsave(&samsung_pwm_lock, flags); - reg = readl(pwm->base + REG_TCFG0); + reg = readl(pwm.base + REG_TCFG0); reg &= ~(TCFG0_PRESCALER_MASK << shift); reg |= (prescale - 1) << shift; - writel(reg, pwm->base + REG_TCFG0); + writel(reg, pwm.base + REG_TCFG0); spin_unlock_irqrestore(&samsung_pwm_lock, flags); } -static void samsung_timer_set_divisor(struct samsung_pwm *pwm, - unsigned int channel, u8 divisor) +static void samsung_timer_set_divisor(unsigned int channel, u8 divisor) { u8 shift = TCFG1_SHIFT(channel); unsigned long flags; u32 reg; u8 bits; - bits = (fls(divisor) - 1) - pwm->variant.div_base; + bits = (fls(divisor) - 1) - pwm.variant.div_base; spin_lock_irqsave(&samsung_pwm_lock, flags); - reg = readl(pwm->base + REG_TCFG1); + reg = readl(pwm.base + REG_TCFG1); reg &= ~(TCFG1_MUX_MASK << shift); reg |= bits << shift; - writel(reg, pwm->base + REG_TCFG1); + writel(reg, pwm.base + REG_TCFG1); spin_unlock_irqrestore(&samsung_pwm_lock, flags); } @@ -115,9 +118,9 @@ static void samsung_time_stop(unsigned int channel) spin_lock_irqsave(&samsung_pwm_lock, flags); - tcon = __raw_readl(pwm->base + REG_TCON); + tcon = __raw_readl(pwm.base + REG_TCON); tcon &= ~TCON_START(channel); - __raw_writel(tcon, pwm->base + REG_TCON); + __raw_writel(tcon, pwm.base + REG_TCON); spin_unlock_irqrestore(&samsung_pwm_lock, flags); } @@ -133,16 +136,16 @@ static void samsung_time_setup(unsigned int channel, unsigned long tcnt) spin_lock_irqsave(&samsung_pwm_lock, flags); - tcon = __raw_readl(pwm->base + REG_TCON); + tcon = __raw_readl(pwm.base + REG_TCON); tcnt--; tcon &= ~(TCON_START(tcon_chan) | TCON_AUTORELOAD(tcon_chan)); tcon |= TCON_MANUALUPDATE(tcon_chan); - __raw_writel(tcnt, pwm->base + REG_TCNTB(channel)); - __raw_writel(tcnt, pwm->base + REG_TCMPB(channel)); - __raw_writel(tcon, pwm->base + REG_TCON); + __raw_writel(tcnt, pwm.base + REG_TCNTB(channel)); + __raw_writel(tcnt, pwm.base + REG_TCMPB(channel)); + __raw_writel(tcon, pwm.base + REG_TCON); spin_unlock_irqrestore(&samsung_pwm_lock, flags); } @@ -157,7 +160,7 @@ static void samsung_time_start(unsigned int channel, bool periodic) spin_lock_irqsave(&samsung_pwm_lock, flags); - tcon = __raw_readl(pwm->base + REG_TCON); + tcon = __raw_readl(pwm.base + REG_TCON); tcon &= ~TCON_MANUALUPDATE(channel); tcon |= TCON_START(channel); @@ -167,7 +170,7 @@ static void samsung_time_start(unsigned int channel, bool periodic) else tcon &= ~TCON_AUTORELOAD(channel); - __raw_writel(tcon, pwm->base + REG_TCON); + __raw_writel(tcon, pwm.base + REG_TCON); spin_unlock_irqrestore(&samsung_pwm_lock, flags); } @@ -175,8 +178,8 @@ static void samsung_time_start(unsigned int channel, bool periodic) static int samsung_set_next_event(unsigned long cycles, struct clock_event_device *evt) { - samsung_time_setup(timer_source.event_id, cycles); - samsung_time_start(timer_source.event_id, false); + samsung_time_setup(pwm.event_id, cycles); + samsung_time_start(pwm.event_id, false); return 0; } @@ -184,23 +187,23 @@ static int samsung_set_next_event(unsigned long cycles, static void samsung_timer_resume(void) { /* event timer restart */ - samsung_time_setup(timer_source.event_id, clock_count_per_tick); - samsung_time_start(timer_source.event_id, true); + samsung_time_setup(pwm.event_id, pwm.clock_count_per_tick); + samsung_time_start(pwm.event_id, true); /* source timer restart */ - samsung_time_setup(timer_source.source_id, timer_source.tcnt_max); - samsung_time_start(timer_source.source_id, true); + samsung_time_setup(pwm.source_id, pwm.tcnt_max); + samsung_time_start(pwm.source_id, true); } static void samsung_set_mode(enum clock_event_mode mode, struct clock_event_device *evt) { - samsung_time_stop(timer_source.event_id); + samsung_time_stop(pwm.event_id); switch (mode) { case CLOCK_EVT_MODE_PERIODIC: - samsung_time_setup(timer_source.event_id, clock_count_per_tick); - samsung_time_start(timer_source.event_id, true); + samsung_time_setup(pwm.event_id, pwm.clock_count_per_tick); + samsung_time_start(pwm.event_id, true); break; case CLOCK_EVT_MODE_ONESHOT: @@ -228,9 +231,9 @@ static irqreturn_t samsung_clock_event_isr(int irq, void *dev_id) { struct clock_event_device *evt = dev_id; - if (pwm->variant.has_tint_cstat) { - u32 mask = (1 << timer_source.event_id); - writel(mask | (mask << 5), pwm->base + REG_TINT_CSTAT); + if (pwm.variant.has_tint_cstat) { + u32 mask = (1 << pwm.event_id); + writel(mask | (mask << 5), pwm.base + REG_TINT_CSTAT); } evt->event_handler(evt); @@ -251,39 +254,37 @@ static void __init samsung_clockevent_init(void) unsigned long clock_rate; unsigned int irq_number; - pclk = clk_get_rate(timerclk); + pclk = clk_get_rate(pwm.timerclk); - samsung_timer_set_prescale(pwm, timer_source.event_id, - timer_source.tscaler_div); - samsung_timer_set_divisor(pwm, timer_source.event_id, - timer_source.tdiv); + samsung_timer_set_prescale(pwm.event_id, pwm.tscaler_div); + samsung_timer_set_divisor(pwm.event_id, pwm.tdiv); - clock_rate = pclk / (timer_source.tscaler_div * timer_source.tdiv); - clock_count_per_tick = clock_rate / HZ; + clock_rate = pclk / (pwm.tscaler_div * pwm.tdiv); + pwm.clock_count_per_tick = clock_rate / HZ; time_event_device.cpumask = cpumask_of(0); clockevents_config_and_register(&time_event_device, clock_rate, 1, -1); - irq_number = pwm->irq[timer_source.event_id]; + irq_number = pwm.irq[pwm.event_id]; setup_irq(irq_number, &samsung_clock_event_irq); - if (pwm->variant.has_tint_cstat) { - u32 mask = (1 << timer_source.event_id); - writel(mask | (mask << 5), pwm->base + REG_TINT_CSTAT); + if (pwm.variant.has_tint_cstat) { + u32 mask = (1 << pwm.event_id); + writel(mask | (mask << 5), pwm.base + REG_TINT_CSTAT); } } static void __iomem *samsung_timer_reg(void) { - switch (timer_source.source_id) { + switch (pwm.source_id) { case 0: case 1: case 2: case 3: - return pwm->base + timer_source.source_id * 0x0c + 0x14; + return pwm.base + pwm.source_id * 0x0c + 0x14; case 4: - return pwm->base + 0x40; + return pwm.base + 0x40; default: BUG(); @@ -314,23 +315,21 @@ static void __init samsung_clocksource_init(void) unsigned long clock_rate; int ret; - pclk = clk_get_rate(timerclk); + pclk = clk_get_rate(pwm.timerclk); - samsung_timer_set_prescale(pwm, timer_source.source_id, - timer_source.tscaler_div); - samsung_timer_set_divisor(pwm, timer_source.source_id, - timer_source.tdiv); + samsung_timer_set_prescale(pwm.source_id, pwm.tscaler_div); + samsung_timer_set_divisor(pwm.source_id, pwm.tdiv); - clock_rate = pclk / (timer_source.tscaler_div * timer_source.tdiv); + clock_rate = pclk / (pwm.tscaler_div * pwm.tdiv); - samsung_time_setup(timer_source.source_id, timer_source.tcnt_max); - samsung_time_start(timer_source.source_id, true); + samsung_time_setup(pwm.source_id, pwm.tcnt_max); + samsung_time_start(pwm.source_id, true); setup_sched_clock(samsung_read_sched_clock, - pwm->variant.bits, clock_rate); + pwm.variant.bits, clock_rate); ret = clocksource_mmio_init(reg, "samsung_clocksource_timer", - clock_rate, 250, pwm->variant.bits, + clock_rate, 250, pwm.variant.bits, clocksource_mmio_readl_down); if (ret) panic("samsung_clocksource_timer: can't register clocksource\n"); @@ -338,19 +337,19 @@ static void __init samsung_clocksource_init(void) static void __init samsung_timer_resources(void) { - timerclk = clk_get(NULL, "timers"); - if (IS_ERR(timerclk)) + pwm.timerclk = clk_get(NULL, "timers"); + if (IS_ERR(pwm.timerclk)) panic("failed to get timers clock for timer"); - clk_prepare_enable(timerclk); + clk_prepare_enable(pwm.timerclk); - timer_source.tcnt_max = (1UL << pwm->variant.bits) - 1; - if (pwm->variant.bits == 16) { - timer_source.tscaler_div = 25; - timer_source.tdiv = 2; + pwm.tcnt_max = (1UL << pwm.variant.bits) - 1; + if (pwm.variant.bits == 16) { + pwm.tscaler_div = 25; + pwm.tdiv = 2; } else { - timer_source.tscaler_div = 2; - timer_source.tdiv = 1; + pwm.tscaler_div = 2; + pwm.tdiv = 1; } } @@ -362,20 +361,17 @@ static void __init samsung_pwm_clocksource_init(void) u8 mask; int channel; - if (!pwm) - panic("no pwm clocksource device found"); - - mask = ~pwm->variant.output_mask & ((1 << SAMSUNG_PWM_NUM) - 1); + mask = ~pwm.variant.output_mask & ((1 << SAMSUNG_PWM_NUM) - 1); channel = fls(mask) - 1; if (channel < 0) panic("failed to find PWM channel for clocksource"); - timer_source.source_id = channel; + pwm.source_id = channel; mask &= ~(1 << channel); channel = fls(mask) - 1; if (channel < 0) panic("failed to find PWM channel for clock event"); - timer_source.event_id = channel; + pwm.event_id = channel; samsung_timer_resources(); samsung_clockevent_init(); @@ -391,14 +387,9 @@ static void __init samsung_pwm_alloc(struct device_node *np, u32 val; int i; - pwm = kzalloc(sizeof(*pwm), GFP_KERNEL); - if (!pwm) { - pr_err("%s: could not allocate PWM device struct\n", __func__); - return; - } - memcpy(&pwm->variant, variant, sizeof(pwm->variant)); + memcpy(&pwm.variant, variant, sizeof(pwm.variant)); for (i = 0; i < SAMSUNG_PWM_NUM; ++i) - pwm->irq[i] = irq_of_parse_and_map(np, i); + pwm.irq[i] = irq_of_parse_and_map(np, i); of_property_for_each_u32(np, "samsung,pwm-outputs", prop, cur, val) { if (val >= SAMSUNG_PWM_NUM) { @@ -406,7 +397,7 @@ static void __init samsung_pwm_alloc(struct device_node *np, __func__); continue; } - pwm->variant.output_mask |= 1 << val; + pwm.variant.output_mask |= 1 << val; } of_address_to_resource(np, 0, &res); @@ -416,8 +407,8 @@ static void __init samsung_pwm_alloc(struct device_node *np, return; } - pwm->base = ioremap(res.start, resource_size(&res)); - if (!pwm->base) { + pwm.base = ioremap(res.start, resource_size(&res)); + if (!pwm.base) { pr_err("%s: failed to map PWM registers\n", __func__); release_mem_region(res.start, resource_size(&res)); return; |