rtc: s3c: Handle clock enable failures
clk_enable() can fail so handle such case. Signed-off-by: Krzysztof Kozlowski <krzk@kernel.org> Signed-off-by: Alexandre Belloni <alexandre.belloni@free-electrons.com>
This commit is contained in:
parent
9903f68af6
commit
498bcf3139
|
@ -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)
|
||||||
{
|
{
|
||||||
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)
|
||||||
|
|
||||||
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)
|
||||||
/* 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)
|
||||||
{
|
{
|
||||||
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)
|
||||||
{
|
{
|
||||||
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)
|
||||||
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)
|
||||||
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)
|
||||||
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)
|
||||||
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)
|
||||||
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)
|
||||||
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)
|
||||||
|
|
Loading…
Reference in New Issue