Commit 498bcf31 authored by Krzysztof Kozlowski's avatar Krzysztof Kozlowski Committed by Alexandre Belloni

rtc: s3c: Handle clock enable failures

clk_enable() can fail so handle such case.
Signed-off-by: default avatarKrzysztof Kozlowski <krzk@kernel.org>
Signed-off-by: default avatarAlexandre Belloni <alexandre.belloni@free-electrons.com>
parent 9903f68a
...@@ -68,18 +68,32 @@ struct s3c_rtc_data { ...@@ -68,18 +68,32 @@ struct s3c_rtc_data {
void (*disable) (struct s3c_rtc *info); void (*disable) (struct s3c_rtc *info);
}; };
static void s3c_rtc_enable_clk(struct s3c_rtc *info) static int s3c_rtc_enable_clk(struct s3c_rtc *info)
{ {
unsigned long irq_flags; unsigned long irq_flags;
int ret = 0;
spin_lock_irqsave(&info->alarm_clk_lock, irq_flags); spin_lock_irqsave(&info->alarm_clk_lock, irq_flags);
if (info->clk_disabled) { if (info->clk_disabled) {
clk_enable(info->rtc_clk); ret = clk_enable(info->rtc_clk);
if (info->data->needs_src_clk) if (ret)
clk_enable(info->rtc_src_clk); goto out;
if (info->data->needs_src_clk) {
ret = clk_enable(info->rtc_src_clk);
if (ret) {
clk_disable(info->rtc_clk);
goto out;
}
}
info->clk_disabled = false; info->clk_disabled = false;
} }
out:
spin_unlock_irqrestore(&info->alarm_clk_lock, irq_flags); spin_unlock_irqrestore(&info->alarm_clk_lock, irq_flags);
return ret;
} }
static void s3c_rtc_disable_clk(struct s3c_rtc *info) static void s3c_rtc_disable_clk(struct s3c_rtc *info)
...@@ -122,10 +136,13 @@ static int s3c_rtc_setaie(struct device *dev, unsigned int enabled) ...@@ -122,10 +136,13 @@ static int s3c_rtc_setaie(struct device *dev, unsigned int enabled)
{ {
struct s3c_rtc *info = dev_get_drvdata(dev); struct s3c_rtc *info = dev_get_drvdata(dev);
unsigned int tmp; unsigned int tmp;
int ret;
dev_dbg(info->dev, "%s: aie=%d\n", __func__, enabled); dev_dbg(info->dev, "%s: aie=%d\n", __func__, enabled);
s3c_rtc_enable_clk(info); ret = s3c_rtc_enable_clk(info);
if (ret)
return ret;
tmp = readb(info->base + S3C2410_RTCALM) & ~S3C2410_RTCALM_ALMEN; tmp = readb(info->base + S3C2410_RTCALM) & ~S3C2410_RTCALM_ALMEN;
...@@ -136,10 +153,13 @@ static int s3c_rtc_setaie(struct device *dev, unsigned int enabled) ...@@ -136,10 +153,13 @@ static int s3c_rtc_setaie(struct device *dev, unsigned int enabled)
s3c_rtc_disable_clk(info); s3c_rtc_disable_clk(info);
if (enabled) if (enabled) {
s3c_rtc_enable_clk(info); ret = s3c_rtc_enable_clk(info);
else if (ret)
return ret;
} else {
s3c_rtc_disable_clk(info); s3c_rtc_disable_clk(info);
}
return 0; return 0;
} }
...@@ -147,10 +167,14 @@ static int s3c_rtc_setaie(struct device *dev, unsigned int enabled) ...@@ -147,10 +167,14 @@ static int s3c_rtc_setaie(struct device *dev, unsigned int enabled)
/* Set RTC frequency */ /* Set RTC frequency */
static int s3c_rtc_setfreq(struct s3c_rtc *info, int freq) static int s3c_rtc_setfreq(struct s3c_rtc *info, int freq)
{ {
int ret;
if (!is_power_of_2(freq)) if (!is_power_of_2(freq))
return -EINVAL; return -EINVAL;
s3c_rtc_enable_clk(info); ret = s3c_rtc_enable_clk(info);
if (ret)
return ret;
spin_lock_irq(&info->pie_lock); spin_lock_irq(&info->pie_lock);
if (info->data->set_freq) if (info->data->set_freq)
...@@ -167,8 +191,11 @@ static int s3c_rtc_gettime(struct device *dev, struct rtc_time *rtc_tm) ...@@ -167,8 +191,11 @@ static int s3c_rtc_gettime(struct device *dev, struct rtc_time *rtc_tm)
{ {
struct s3c_rtc *info = dev_get_drvdata(dev); struct s3c_rtc *info = dev_get_drvdata(dev);
unsigned int have_retried = 0; unsigned int have_retried = 0;
int ret;
s3c_rtc_enable_clk(info); ret = s3c_rtc_enable_clk(info);
if (ret)
return ret;
retry_get_time: retry_get_time:
rtc_tm->tm_min = readb(info->base + S3C2410_RTCMIN); rtc_tm->tm_min = readb(info->base + S3C2410_RTCMIN);
...@@ -212,6 +239,7 @@ static int s3c_rtc_settime(struct device *dev, struct rtc_time *tm) ...@@ -212,6 +239,7 @@ static int s3c_rtc_settime(struct device *dev, struct rtc_time *tm)
{ {
struct s3c_rtc *info = dev_get_drvdata(dev); struct s3c_rtc *info = dev_get_drvdata(dev);
int year = tm->tm_year - 100; int year = tm->tm_year - 100;
int ret;
dev_dbg(dev, "set time %04d.%02d.%02d %02d:%02d:%02d\n", dev_dbg(dev, "set time %04d.%02d.%02d %02d:%02d:%02d\n",
1900 + tm->tm_year, tm->tm_mon, tm->tm_mday, 1900 + tm->tm_year, tm->tm_mon, tm->tm_mday,
...@@ -224,7 +252,9 @@ static int s3c_rtc_settime(struct device *dev, struct rtc_time *tm) ...@@ -224,7 +252,9 @@ static int s3c_rtc_settime(struct device *dev, struct rtc_time *tm)
return -EINVAL; return -EINVAL;
} }
s3c_rtc_enable_clk(info); ret = s3c_rtc_enable_clk(info);
if (ret)
return ret;
writeb(bin2bcd(tm->tm_sec), info->base + S3C2410_RTCSEC); writeb(bin2bcd(tm->tm_sec), info->base + S3C2410_RTCSEC);
writeb(bin2bcd(tm->tm_min), info->base + S3C2410_RTCMIN); writeb(bin2bcd(tm->tm_min), info->base + S3C2410_RTCMIN);
...@@ -243,8 +273,11 @@ static int s3c_rtc_getalarm(struct device *dev, struct rtc_wkalrm *alrm) ...@@ -243,8 +273,11 @@ static int s3c_rtc_getalarm(struct device *dev, struct rtc_wkalrm *alrm)
struct s3c_rtc *info = dev_get_drvdata(dev); struct s3c_rtc *info = dev_get_drvdata(dev);
struct rtc_time *alm_tm = &alrm->time; struct rtc_time *alm_tm = &alrm->time;
unsigned int alm_en; unsigned int alm_en;
int ret;
s3c_rtc_enable_clk(info); ret = s3c_rtc_enable_clk(info);
if (ret)
return ret;
alm_tm->tm_sec = readb(info->base + S3C2410_ALMSEC); alm_tm->tm_sec = readb(info->base + S3C2410_ALMSEC);
alm_tm->tm_min = readb(info->base + S3C2410_ALMMIN); alm_tm->tm_min = readb(info->base + S3C2410_ALMMIN);
...@@ -293,6 +326,7 @@ static int s3c_rtc_setalarm(struct device *dev, struct rtc_wkalrm *alrm) ...@@ -293,6 +326,7 @@ static int s3c_rtc_setalarm(struct device *dev, struct rtc_wkalrm *alrm)
struct s3c_rtc *info = dev_get_drvdata(dev); struct s3c_rtc *info = dev_get_drvdata(dev);
struct rtc_time *tm = &alrm->time; struct rtc_time *tm = &alrm->time;
unsigned int alrm_en; unsigned int alrm_en;
int ret;
int year = tm->tm_year - 100; int year = tm->tm_year - 100;
dev_dbg(dev, "s3c_rtc_setalarm: %d, %04d.%02d.%02d %02d:%02d:%02d\n", dev_dbg(dev, "s3c_rtc_setalarm: %d, %04d.%02d.%02d %02d:%02d:%02d\n",
...@@ -300,7 +334,9 @@ static int s3c_rtc_setalarm(struct device *dev, struct rtc_wkalrm *alrm) ...@@ -300,7 +334,9 @@ static int s3c_rtc_setalarm(struct device *dev, struct rtc_wkalrm *alrm)
1900 + tm->tm_year, tm->tm_mon + 1, tm->tm_mday, 1900 + tm->tm_year, tm->tm_mon + 1, tm->tm_mday,
tm->tm_hour, tm->tm_min, tm->tm_sec); tm->tm_hour, tm->tm_min, tm->tm_sec);
s3c_rtc_enable_clk(info); ret = s3c_rtc_enable_clk(info);
if (ret)
return ret;
alrm_en = readb(info->base + S3C2410_RTCALM) & S3C2410_RTCALM_ALMEN; alrm_en = readb(info->base + S3C2410_RTCALM) & S3C2410_RTCALM_ALMEN;
writeb(0x00, info->base + S3C2410_RTCALM); writeb(0x00, info->base + S3C2410_RTCALM);
...@@ -349,8 +385,11 @@ static int s3c_rtc_setalarm(struct device *dev, struct rtc_wkalrm *alrm) ...@@ -349,8 +385,11 @@ static int s3c_rtc_setalarm(struct device *dev, struct rtc_wkalrm *alrm)
static int s3c_rtc_proc(struct device *dev, struct seq_file *seq) static int s3c_rtc_proc(struct device *dev, struct seq_file *seq)
{ {
struct s3c_rtc *info = dev_get_drvdata(dev); struct s3c_rtc *info = dev_get_drvdata(dev);
int ret;
s3c_rtc_enable_clk(info); ret = s3c_rtc_enable_clk(info);
if (ret)
return ret;
if (info->data->enable_tick) if (info->data->enable_tick)
info->data->enable_tick(info, seq); info->data->enable_tick(info, seq);
...@@ -589,8 +628,11 @@ static int s3c_rtc_probe(struct platform_device *pdev) ...@@ -589,8 +628,11 @@ static int s3c_rtc_probe(struct platform_device *pdev)
static int s3c_rtc_suspend(struct device *dev) static int s3c_rtc_suspend(struct device *dev)
{ {
struct s3c_rtc *info = dev_get_drvdata(dev); struct s3c_rtc *info = dev_get_drvdata(dev);
int ret;
s3c_rtc_enable_clk(info); ret = s3c_rtc_enable_clk(info);
if (ret)
return ret;
/* save TICNT for anyone using periodic interrupts */ /* save TICNT for anyone using periodic interrupts */
if (info->data->save_tick_cnt) if (info->data->save_tick_cnt)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment