diff options
author | Jonghwa Lee <jonghwa3.lee@samsung.com> | 2014-08-14 19:57:03 +0900 |
---|---|---|
committer | Seung-Woo Kim <sw0312.kim@samsung.com> | 2016-12-14 13:43:16 +0900 |
commit | c7059929406aebc68516dbcdf4536d0fe8849ac9 (patch) | |
tree | 293d2f57f3f8b7c6aecd8294bb1ad3e69573468f | |
parent | 8f63ac9652697259497f76a2c172dd11fb5c5c26 (diff) |
rtc: s3c: Make tick timer to be a selectable option.
s3c rtc driver has enabled timer tick default. However in some system,
it's not a mandatory option. So it modifies driver that tick timer can
be enabled selectively with a property, 's3c-rtc-tick-en', in DT.
Signed-off-by: Jonghwa Lee <jonghwa3.lee@samsung.com>
[k.kozlowski: rebased on 4.1]
Signed-off-by: Krzysztof Kozlowski <k.kozlowski@samsung.com>
-rw-r--r-- | Documentation/devicetree/bindings/rtc/s3c-rtc.txt | 4 | ||||
-rw-r--r-- | drivers/rtc/rtc-s3c.c | 104 | ||||
-rw-r--r-- | drivers/rtc/rtc-s3c.h | 7 |
3 files changed, 82 insertions, 33 deletions
diff --git a/Documentation/devicetree/bindings/rtc/s3c-rtc.txt b/Documentation/devicetree/bindings/rtc/s3c-rtc.txt index ab757b84daa7..6bd598ee03d6 100644 --- a/Documentation/devicetree/bindings/rtc/s3c-rtc.txt +++ b/Documentation/devicetree/bindings/rtc/s3c-rtc.txt @@ -14,10 +14,14 @@ Required properties: is the rtc tick interrupt. The number of cells representing a interrupt depends on the parent interrupt controller. +Optional Properties: +- s3c-rtc-tick-en : flag for enabling tick timer + Example: rtc@10070000 { compatible = "samsung,s3c6410-rtc"; reg = <0x10070000 0x100>; interrupts = <44 0 45 0>; + s3c-rtc-tick-en; }; diff --git a/drivers/rtc/rtc-s3c.c b/drivers/rtc/rtc-s3c.c index 463003d2529c..c3f6dc57ceb7 100644 --- a/drivers/rtc/rtc-s3c.c +++ b/drivers/rtc/rtc-s3c.c @@ -56,10 +56,11 @@ struct s3c_rtc { struct s3c_rtc_data { int max_user_freq; bool needs_src_clk; + bool tick_en; void (*irq_handler) (struct s3c_rtc *info, int mask); void (*set_freq) (struct s3c_rtc *info, int freq); - void (*enable_tick) (struct s3c_rtc *info, struct seq_file *seq); + void (*enable_tick) (struct s3c_rtc *info, bool en); void (*select_tick_clk) (struct s3c_rtc *info); void (*save_tick_cnt) (struct s3c_rtc *info); void (*restore_tick_cnt) (struct s3c_rtc *info); @@ -345,13 +346,8 @@ static int s3c_rtc_proc(struct device *dev, struct seq_file *seq) { struct s3c_rtc *info = dev_get_drvdata(dev); - s3c_rtc_enable_clk(info); - - if (info->data->enable_tick) - info->data->enable_tick(info, seq); - - s3c_rtc_disable_clk(info); - + seq_printf(seq, "periodic_IRQ\t: %s\n", + info->data->tick_en ? "yes" : "no"); return 0; } @@ -435,9 +431,15 @@ static const struct of_device_id s3c_rtc_dt_match[]; static struct s3c_rtc_data *s3c_rtc_get_data(struct platform_device *pdev) { const struct of_device_id *match; + struct s3c_rtc_data *rtc_data; match = of_match_node(s3c_rtc_dt_match, pdev->dev.of_node); - return (struct s3c_rtc_data *)match->data; + rtc_data = (struct s3c_rtc_data *)match->data; + + if (of_get_property(pdev->dev.of_node, "s3c-rtc-tick-en", NULL)) + rtc_data->tick_en = true; + + return rtc_data; } static int s3c_rtc_probe(struct platform_device *pdev) @@ -540,17 +542,23 @@ static int s3c_rtc_probe(struct platform_device *pdev) goto err_nortc; } - ret = devm_request_irq(&pdev->dev, info->irq_tick, s3c_rtc_tickirq, - 0, "s3c2410-rtc tick", info); - if (ret) { - dev_err(&pdev->dev, "IRQ%d error %d\n", info->irq_tick, ret); - goto err_nortc; - } + if (info->data->tick_en) { + ret = devm_request_irq(&pdev->dev, info->irq_tick, + s3c_rtc_tickirq, 0,"s3c2410-rtc tick", info); + if (ret) { + dev_err(&pdev->dev, "IRQ%d error %d\n", + info->irq_tick, ret); + goto err_nortc; + } + info->data->enable_tick(info, true); - if (info->data->select_tick_clk) - info->data->select_tick_clk(info); + if (info->data->select_tick_clk) + info->data->select_tick_clk(info); - s3c_rtc_setfreq(info, 1); + s3c_rtc_setfreq(info, info->rtc->max_user_freq); + } else { + info->data->enable_tick(info, false); + } s3c_rtc_disable_clk(info); @@ -625,15 +633,25 @@ static void s3c6410_rtc_irq(struct s3c_rtc *info, int mask) writeb(mask, info->base + S3C2410_INTP); } +static inline int s3c_rtc_get_tcnt(struct s3c_rtc *info, int freq) +{ + /* + * If requested frequency is larger than supported, + * it sets tick time count to minimum. + */ + if (freq > info->data->max_user_freq) + return S3C_TCNT_MIN; + + return info->data->max_user_freq / freq; +} + static void s3c2410_rtc_setfreq(struct s3c_rtc *info, int freq) { unsigned int tmp = 0; int val; tmp = readb(info->base + S3C2410_TICNT); - tmp &= S3C2410_TICNT_ENABLE; - - val = (info->rtc->max_user_freq / freq) - 1; + val = s3c_rtc_get_tcnt(info, freq); tmp |= val; writel(tmp, info->base + S3C2410_TICNT); @@ -645,9 +663,7 @@ static void s3c2416_rtc_setfreq(struct s3c_rtc *info, int freq) int val; tmp = readb(info->base + S3C2410_TICNT); - tmp &= S3C2410_TICNT_ENABLE; - - val = (info->rtc->max_user_freq / freq) - 1; + val = s3c_rtc_get_tcnt(info, freq); tmp |= S3C2443_TICNT_PART(val); writel(S3C2443_TICNT1_PART(val), info->base + S3C2443_TICNT1); @@ -665,7 +681,7 @@ static void s3c2443_rtc_setfreq(struct s3c_rtc *info, int freq) tmp = readb(info->base + S3C2410_TICNT); tmp &= S3C2410_TICNT_ENABLE; - val = (info->rtc->max_user_freq / freq) - 1; + val = s3c_rtc_get_tcnt(info, freq); tmp |= S3C2443_TICNT_PART(val); writel(S3C2443_TICNT1_PART(val), info->base + S3C2443_TICNT1); @@ -677,18 +693,21 @@ static void s3c6410_rtc_setfreq(struct s3c_rtc *info, int freq) { int val; - val = (info->rtc->max_user_freq / freq) - 1; + val = s3c_rtc_get_tcnt(info, freq); writel(val, info->base + S3C2410_TICNT); } -static void s3c24xx_rtc_enable_tick(struct s3c_rtc *info, struct seq_file *seq) +static void s3c24xx_rtc_enable_tick(struct s3c_rtc *info, bool en) { unsigned int ticnt; ticnt = readb(info->base + S3C2410_TICNT); - ticnt &= S3C2410_TICNT_ENABLE; - - seq_printf(seq, "periodic_IRQ\t: %s\n", ticnt ? "yes" : "no"); + if (en) + ticnt |= S3C2410_TICNT_ENABLE; + else + ticnt &= ~S3C2410_TICNT_ENABLE; + writeb(ticnt, info->base + S3C2410_TICNT); + info->data->tick_en = en; } static void s3c2416_rtc_select_tick_clk(struct s3c_rtc *info) @@ -700,14 +719,31 @@ static void s3c2416_rtc_select_tick_clk(struct s3c_rtc *info) writew(con, info->base + S3C2410_RTCCON); } -static void s3c6410_rtc_enable_tick(struct s3c_rtc *info, struct seq_file *seq) +static void s3c6410_rtc_enable_tick(struct s3c_rtc *info, bool en) { unsigned int ticnt; ticnt = readw(info->base + S3C2410_RTCCON); - ticnt &= S3C64XX_RTCCON_TICEN; + if (en) + ticnt |= S3C64XX_RTCCON_TICEN; + else + ticnt &= ~S3C64XX_RTCCON_TICEN; + writeb(ticnt, info->base + S3C2410_RTCCON); + info->data->tick_en = en; +} - seq_printf(seq, "periodic_IRQ\t: %s\n", ticnt ? "yes" : "no"); +static void s3c6410_rtc_select_tick_clk(struct s3c_rtc *info) +{ + unsigned int tmp; + int val; + + tmp = readl(info->base + S3C2410_RTCCON); + tmp &= ~S3C64XX_CLKSEL_MASK; + val = (S3C_TICK_HZ_MAX / info->data->max_user_freq) - 1; + val <<= S3C64XX_CLKSEL_SHIFT; + val &= S3C64XX_CLKSEL_MASK; + tmp |= val; + writel(tmp, info->base + S3C2410_RTCCON); } static void s3c24xx_rtc_save_tick_cnt(struct s3c_rtc *info) @@ -780,6 +816,7 @@ static struct s3c_rtc_data const s3c6410_rtc_data = { .irq_handler = s3c6410_rtc_irq, .set_freq = s3c6410_rtc_setfreq, .enable_tick = s3c6410_rtc_enable_tick, + .select_tick_clk = s3c6410_rtc_select_tick_clk, .save_tick_cnt = s3c6410_rtc_save_tick_cnt, .restore_tick_cnt = s3c6410_rtc_restore_tick_cnt, .enable = s3c24xx_rtc_enable, @@ -792,6 +829,7 @@ static struct s3c_rtc_data const exynos3250_rtc_data = { .irq_handler = s3c6410_rtc_irq, .set_freq = s3c6410_rtc_setfreq, .enable_tick = s3c6410_rtc_enable_tick, + .select_tick_clk = s3c6410_rtc_select_tick_clk, .save_tick_cnt = s3c6410_rtc_save_tick_cnt, .restore_tick_cnt = s3c6410_rtc_restore_tick_cnt, .enable = s3c24xx_rtc_enable, diff --git a/drivers/rtc/rtc-s3c.h b/drivers/rtc/rtc-s3c.h index 004b61a8343f..2a98c6151b2d 100644 --- a/drivers/rtc/rtc-s3c.h +++ b/drivers/rtc/rtc-s3c.h @@ -23,6 +23,13 @@ #define S3C2410_RTCCON_CLKRST (1 << 3) #define S3C2443_RTCCON_TICSEL (1 << 4) #define S3C64XX_RTCCON_TICEN (1 << 8) +#define S3C64XX_CLKSEL_MASK (0xf << S3C64XX_CLKSEL_SHIFT) +#define S3C64XX_CLKSEL_SHIFT (4) + +/* S3C rtc's Minimum tick count */ +#define S3C_TCNT_MIN 3 +/* S3C rtc's source clock rate is 32KHZ */ +#define S3C_TICK_HZ_MAX 32786 #define S3C2410_TICNT S3C2410_RTCREG(0x44) #define S3C2410_TICNT_ENABLE (1 << 7) |