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

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
Loading
Loading
Loading
Loading
+57 −15
Original line number Original line Diff line number Diff line
@@ -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 @@ err_src_clk:
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)