forked from mirrors/linux
		
	rtc: s3c: add s3c_rtc_data structure to use variant data instead of s3c_cpu_type
Add s3c_rtc_data structure to variant data according to SoC type. The s3c_rtc_data structure includes some functions to control RTC operation and specific data dependent on SoC type. Signed-off-by: Chanwoo Choi <cw00.choi@samsung.com> Acked-by: Kyungmin Park <kyungmin.park@samsung.com> Cc: Alessandro Zummo <a.zummo@towertech.it> Cc: Kukjin Kim <kgene.kim@samsung.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
This commit is contained in:
		
							parent
							
								
									d67288da51
								
							
						
					
					
						commit
						ae05c95074
					
				
					 1 changed files with 297 additions and 180 deletions
				
			
		|  | @ -32,17 +32,6 @@ | |||
| #include <asm/irq.h> | ||||
| #include "rtc-s3c.h" | ||||
| 
 | ||||
| enum s3c_cpu_type { | ||||
| 	TYPE_S3C2410, | ||||
| 	TYPE_S3C2416, | ||||
| 	TYPE_S3C2443, | ||||
| 	TYPE_S3C64XX, | ||||
| }; | ||||
| 
 | ||||
| struct s3c_rtc_drv_data { | ||||
| 	int cpu_type; | ||||
| }; | ||||
| 
 | ||||
| struct s3c_rtc { | ||||
| 	struct device *dev; | ||||
| 	struct rtc_device *rtc; | ||||
|  | @ -51,7 +40,7 @@ struct s3c_rtc { | |||
| 	struct clk *rtc_clk; | ||||
| 	bool enabled; | ||||
| 
 | ||||
| 	enum s3c_cpu_type cpu_type; | ||||
| 	struct s3c_rtc_data *data; | ||||
| 
 | ||||
| 	int irq_alarm; | ||||
| 	int irq_tick; | ||||
|  | @ -63,6 +52,19 @@ struct s3c_rtc { | |||
| 	bool wake_en; | ||||
| }; | ||||
| 
 | ||||
| struct s3c_rtc_data { | ||||
| 	int max_user_freq; | ||||
| 
 | ||||
| 	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 (*select_tick_clk) (struct s3c_rtc *info); | ||||
| 	void (*save_tick_cnt) (struct s3c_rtc *info); | ||||
| 	void (*restore_tick_cnt) (struct s3c_rtc *info); | ||||
| 	void (*enable) (struct s3c_rtc *info); | ||||
| 	void (*disable) (struct s3c_rtc *info); | ||||
| }; | ||||
| 
 | ||||
| static void s3c_rtc_alarm_clk_enable(struct s3c_rtc *info, bool enable) | ||||
| { | ||||
| 	unsigned long irq_flags; | ||||
|  | @ -83,34 +85,22 @@ static void s3c_rtc_alarm_clk_enable(struct s3c_rtc *info, bool enable) | |||
| } | ||||
| 
 | ||||
| /* IRQ Handlers */ | ||||
| static irqreturn_t s3c_rtc_alarmirq(int irq, void *id) | ||||
| { | ||||
| 	struct s3c_rtc *info = (struct s3c_rtc *)id; | ||||
| 
 | ||||
| 	clk_enable(info->rtc_clk); | ||||
| 	rtc_update_irq(info->rtc, 1, RTC_AF | RTC_IRQF); | ||||
| 
 | ||||
| 	if (info->cpu_type == TYPE_S3C64XX) | ||||
| 		writeb(S3C2410_INTP_ALM, info->base + S3C2410_INTP); | ||||
| 
 | ||||
| 	clk_disable(info->rtc_clk); | ||||
| 
 | ||||
| 	s3c_rtc_alarm_clk_enable(info, false); | ||||
| 
 | ||||
| 	return IRQ_HANDLED; | ||||
| } | ||||
| 
 | ||||
| static irqreturn_t s3c_rtc_tickirq(int irq, void *id) | ||||
| { | ||||
| 	struct s3c_rtc *info = (struct s3c_rtc *)id; | ||||
| 
 | ||||
| 	clk_enable(info->rtc_clk); | ||||
| 	rtc_update_irq(info->rtc, 1, RTC_PF | RTC_IRQF); | ||||
| 	if (info->data->irq_handler) | ||||
| 		info->data->irq_handler(info, S3C2410_INTP_TIC); | ||||
| 
 | ||||
| 	if (info->cpu_type == TYPE_S3C64XX) | ||||
| 		writeb(S3C2410_INTP_TIC, info->base + S3C2410_INTP); | ||||
| 	return IRQ_HANDLED; | ||||
| } | ||||
| 
 | ||||
| 	clk_disable(info->rtc_clk); | ||||
| static irqreturn_t s3c_rtc_alarmirq(int irq, void *id) | ||||
| { | ||||
| 	struct s3c_rtc *info = (struct s3c_rtc *)id; | ||||
| 
 | ||||
| 	if (info->data->irq_handler) | ||||
| 		info->data->irq_handler(info, S3C2410_INTP_ALM); | ||||
| 
 | ||||
| 	return IRQ_HANDLED; | ||||
| } | ||||
|  | @ -137,36 +127,18 @@ static int s3c_rtc_setaie(struct device *dev, unsigned int enabled) | |||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| /* Set RTC frequency */ | ||||
| static int s3c_rtc_setfreq(struct s3c_rtc *info, int freq) | ||||
| { | ||||
| 	unsigned int tmp = 0; | ||||
| 	int val; | ||||
| 
 | ||||
| 	if (!is_power_of_2(freq)) | ||||
| 		return -EINVAL; | ||||
| 
 | ||||
| 	clk_enable(info->rtc_clk); | ||||
| 	spin_lock_irq(&info->pie_lock); | ||||
| 
 | ||||
| 	if (info->cpu_type != TYPE_S3C64XX) { | ||||
| 		tmp = readb(info->base + S3C2410_TICNT); | ||||
| 		tmp &= S3C2410_TICNT_ENABLE; | ||||
| 	} | ||||
| 	if (info->data->set_freq) | ||||
| 		info->data->set_freq(info, freq); | ||||
| 
 | ||||
| 	val = (info->rtc->max_user_freq / freq) - 1; | ||||
| 
 | ||||
| 	if (info->cpu_type == TYPE_S3C2416 || info->cpu_type == TYPE_S3C2443) { | ||||
| 		tmp |= S3C2443_TICNT_PART(val); | ||||
| 		writel(S3C2443_TICNT1_PART(val), info->base + S3C2443_TICNT1); | ||||
| 
 | ||||
| 		if (info->cpu_type == TYPE_S3C2416) | ||||
| 			writel(S3C2416_TICNT2_PART(val), | ||||
| 				info->base + S3C2416_TICNT2); | ||||
| 	} else { | ||||
| 		tmp |= val; | ||||
| 	} | ||||
| 
 | ||||
| 	writel(tmp, info->base + S3C2410_TICNT); | ||||
| 	spin_unlock_irq(&info->pie_lock); | ||||
| 	clk_disable(info->rtc_clk); | ||||
| 
 | ||||
|  | @ -174,7 +146,6 @@ static int s3c_rtc_setfreq(struct s3c_rtc *info, int freq) | |||
| } | ||||
| 
 | ||||
| /* Time read/write */ | ||||
| 
 | ||||
| static int s3c_rtc_gettime(struct device *dev, struct rtc_time *rtc_tm) | ||||
| { | ||||
| 	struct s3c_rtc *info = dev_get_drvdata(dev); | ||||
|  | @ -355,19 +326,14 @@ static int s3c_rtc_setalarm(struct device *dev, struct rtc_wkalrm *alrm) | |||
| static int s3c_rtc_proc(struct device *dev, struct seq_file *seq) | ||||
| { | ||||
| 	struct s3c_rtc *info = dev_get_drvdata(dev); | ||||
| 	unsigned int ticnt; | ||||
| 
 | ||||
| 	clk_enable(info->rtc_clk); | ||||
| 	if (info->cpu_type == TYPE_S3C64XX) { | ||||
| 		ticnt = readw(info->base + S3C2410_RTCCON); | ||||
| 		ticnt &= S3C64XX_RTCCON_TICEN; | ||||
| 	} else { | ||||
| 		ticnt = readb(info->base + S3C2410_TICNT); | ||||
| 		ticnt &= S3C2410_TICNT_ENABLE; | ||||
| 	} | ||||
| 
 | ||||
| 	seq_printf(seq, "periodic_IRQ\t: %s\n", ticnt  ? "yes" : "no"); | ||||
| 	if (info->data->enable_tick) | ||||
| 		info->data->enable_tick(info, seq); | ||||
| 
 | ||||
| 	clk_disable(info->rtc_clk); | ||||
| 
 | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
|  | @ -380,50 +346,69 @@ static const struct rtc_class_ops s3c_rtcops = { | |||
| 	.alarm_irq_enable = s3c_rtc_setaie, | ||||
| }; | ||||
| 
 | ||||
| static void s3c_rtc_enable(struct s3c_rtc *info, int en) | ||||
| static void s3c24xx_rtc_enable(struct s3c_rtc *info) | ||||
| { | ||||
| 	unsigned int con, tmp; | ||||
| 
 | ||||
| 	clk_enable(info->rtc_clk); | ||||
| 
 | ||||
| 	con = readw(info->base + S3C2410_RTCCON); | ||||
| 	if (!en) { | ||||
| 		if (info->cpu_type == TYPE_S3C64XX) | ||||
| 			con &= ~S3C64XX_RTCCON_TICEN; | ||||
| 		con &= ~S3C2410_RTCCON_RTCEN; | ||||
| 		writew(con, info->base + S3C2410_RTCCON); | ||||
| 	/* re-enable the device, and check it is ok */ | ||||
| 	if ((con & S3C2410_RTCCON_RTCEN) == 0) { | ||||
| 		dev_info(info->dev, "rtc disabled, re-enabling\n"); | ||||
| 
 | ||||
| 		if (info->cpu_type != TYPE_S3C64XX) { | ||||
| 			con = readb(info->base + S3C2410_TICNT); | ||||
| 			con &= ~S3C2410_TICNT_ENABLE; | ||||
| 			writeb(con, info->base + S3C2410_TICNT); | ||||
| 		} | ||||
| 	} else { | ||||
| 		/* re-enable the device, and check it is ok */ | ||||
| 		if ((con & S3C2410_RTCCON_RTCEN) == 0) { | ||||
| 			dev_info(info->dev, "rtc disabled, re-enabling\n"); | ||||
| 
 | ||||
| 			tmp = readw(info->base + S3C2410_RTCCON); | ||||
| 			writew(tmp | S3C2410_RTCCON_RTCEN, | ||||
| 				info->base + S3C2410_RTCCON); | ||||
| 		} | ||||
| 
 | ||||
| 		if (con & S3C2410_RTCCON_CNTSEL) { | ||||
| 			dev_info(info->dev, "removing RTCCON_CNTSEL\n"); | ||||
| 
 | ||||
| 			tmp = readw(info->base + S3C2410_RTCCON); | ||||
| 			writew(tmp & ~S3C2410_RTCCON_CNTSEL, | ||||
| 				info->base + S3C2410_RTCCON); | ||||
| 		} | ||||
| 
 | ||||
| 		if (con & S3C2410_RTCCON_CLKRST) { | ||||
| 			dev_info(info->dev, "removing RTCCON_CLKRST\n"); | ||||
| 
 | ||||
| 			tmp = readw(info->base + S3C2410_RTCCON); | ||||
| 			writew(tmp & ~S3C2410_RTCCON_CLKRST, | ||||
| 				info->base + S3C2410_RTCCON); | ||||
| 		} | ||||
| 		tmp = readw(info->base + S3C2410_RTCCON); | ||||
| 		writew(tmp | S3C2410_RTCCON_RTCEN, | ||||
| 			info->base + S3C2410_RTCCON); | ||||
| 	} | ||||
| 
 | ||||
| 	if (con & S3C2410_RTCCON_CNTSEL) { | ||||
| 		dev_info(info->dev, "removing RTCCON_CNTSEL\n"); | ||||
| 
 | ||||
| 		tmp = readw(info->base + S3C2410_RTCCON); | ||||
| 		writew(tmp & ~S3C2410_RTCCON_CNTSEL, | ||||
| 			info->base + S3C2410_RTCCON); | ||||
| 	} | ||||
| 
 | ||||
| 	if (con & S3C2410_RTCCON_CLKRST) { | ||||
| 		dev_info(info->dev, "removing RTCCON_CLKRST\n"); | ||||
| 
 | ||||
| 		tmp = readw(info->base + S3C2410_RTCCON); | ||||
| 		writew(tmp & ~S3C2410_RTCCON_CLKRST, | ||||
| 			info->base + S3C2410_RTCCON); | ||||
| 	} | ||||
| 
 | ||||
| 	clk_disable(info->rtc_clk); | ||||
| } | ||||
| 
 | ||||
| static void s3c24xx_rtc_disable(struct s3c_rtc *info) | ||||
| { | ||||
| 	unsigned int con; | ||||
| 
 | ||||
| 	clk_enable(info->rtc_clk); | ||||
| 
 | ||||
| 	con = readw(info->base + S3C2410_RTCCON); | ||||
| 	con &= ~S3C2410_RTCCON_RTCEN; | ||||
| 	writew(con, info->base + S3C2410_RTCCON); | ||||
| 
 | ||||
| 	con = readb(info->base + S3C2410_TICNT); | ||||
| 	con &= ~S3C2410_TICNT_ENABLE; | ||||
| 	writeb(con, info->base + S3C2410_TICNT); | ||||
| 
 | ||||
| 	clk_disable(info->rtc_clk); | ||||
| } | ||||
| 
 | ||||
| static void s3c6410_rtc_disable(struct s3c_rtc *info) | ||||
| { | ||||
| 	unsigned int con; | ||||
| 
 | ||||
| 	clk_enable(info->rtc_clk); | ||||
| 
 | ||||
| 	con = readw(info->base + S3C2410_RTCCON); | ||||
| 	con &= ~S3C64XX_RTCCON_TICEN; | ||||
| 	con &= ~S3C2410_RTCCON_RTCEN; | ||||
| 	writew(con, info->base + S3C2410_RTCCON); | ||||
| 
 | ||||
| 	clk_disable(info->rtc_clk); | ||||
| } | ||||
| 
 | ||||
|  | @ -441,20 +426,12 @@ static int s3c_rtc_remove(struct platform_device *pdev) | |||
| 
 | ||||
| static const struct of_device_id s3c_rtc_dt_match[]; | ||||
| 
 | ||||
| static inline int s3c_rtc_get_driver_data(struct platform_device *pdev) | ||||
| static struct s3c_rtc_data *s3c_rtc_get_data(struct platform_device *pdev) | ||||
| { | ||||
| #ifdef CONFIG_OF | ||||
| 	struct s3c_rtc_drv_data *data; | ||||
| 	const struct of_device_id *match; | ||||
| 
 | ||||
| 	if (pdev->dev.of_node) { | ||||
| 		const struct of_device_id *match; | ||||
| 
 | ||||
| 		match = of_match_node(s3c_rtc_dt_match, pdev->dev.of_node); | ||||
| 		data = (struct s3c_rtc_drv_data *) match->data; | ||||
| 		return data->cpu_type; | ||||
| 	} | ||||
| #endif | ||||
| 	return platform_get_device_id(pdev)->driver_data; | ||||
| 	match = of_match_node(s3c_rtc_dt_match, pdev->dev.of_node); | ||||
| 	return (struct s3c_rtc_data *)match->data; | ||||
| } | ||||
| 
 | ||||
| static int s3c_rtc_probe(struct platform_device *pdev) | ||||
|  | @ -463,7 +440,6 @@ static int s3c_rtc_probe(struct platform_device *pdev) | |||
| 	struct rtc_time rtc_tm; | ||||
| 	struct resource *res; | ||||
| 	int ret; | ||||
| 	int tmp; | ||||
| 
 | ||||
| 	info = devm_kzalloc(&pdev->dev, sizeof(*info), GFP_KERNEL); | ||||
| 	if (!info) | ||||
|  | @ -477,7 +453,11 @@ static int s3c_rtc_probe(struct platform_device *pdev) | |||
| 	} | ||||
| 
 | ||||
| 	info->dev = &pdev->dev; | ||||
| 	info->cpu_type = s3c_rtc_get_driver_data(pdev); | ||||
| 	info->data = s3c_rtc_get_data(pdev); | ||||
| 	if (!info->data) { | ||||
| 		dev_err(&pdev->dev, "failed getting s3c_rtc_data\n"); | ||||
| 		return -EINVAL; | ||||
| 	} | ||||
| 	spin_lock_init(&info->pie_lock); | ||||
| 	spin_lock_init(&info->alarm_clk_lock); | ||||
| 
 | ||||
|  | @ -506,7 +486,8 @@ static int s3c_rtc_probe(struct platform_device *pdev) | |||
| 	clk_prepare_enable(info->rtc_clk); | ||||
| 
 | ||||
| 	/* check to see if everything is setup correctly */ | ||||
| 	s3c_rtc_enable(info, 1); | ||||
| 	if (info->data->enable) | ||||
| 		info->data->enable(info); | ||||
| 
 | ||||
| 	dev_dbg(&pdev->dev, "s3c2410_rtc: RTCCON=%02x\n", | ||||
| 		 readw(info->base + S3C2410_RTCCON)); | ||||
|  | @ -552,16 +533,8 @@ static int s3c_rtc_probe(struct platform_device *pdev) | |||
| 		dev_warn(&pdev->dev, "warning: invalid RTC value so initializing it\n"); | ||||
| 	} | ||||
| 
 | ||||
| 	if (info->cpu_type != TYPE_S3C2410) | ||||
| 		info->rtc->max_user_freq = 32768; | ||||
| 	else | ||||
| 		info->rtc->max_user_freq = 128; | ||||
| 
 | ||||
| 	if (info->cpu_type == TYPE_S3C2416 || info->cpu_type == TYPE_S3C2443) { | ||||
| 		tmp = readw(info->base + S3C2410_RTCCON); | ||||
| 		tmp |= S3C2443_RTCCON_TICSEL; | ||||
| 		writew(tmp, info->base + S3C2410_RTCCON); | ||||
| 	} | ||||
| 	if (info->data->select_tick_clk) | ||||
| 		info->data->select_tick_clk(info); | ||||
| 
 | ||||
| 	s3c_rtc_setfreq(info, 1); | ||||
| 
 | ||||
|  | @ -570,7 +543,8 @@ static int s3c_rtc_probe(struct platform_device *pdev) | |||
| 	return 0; | ||||
| 
 | ||||
|  err_nortc: | ||||
| 	s3c_rtc_enable(info, 0); | ||||
| 	if (info->data->disable) | ||||
| 		info->data->disable(info); | ||||
| 	clk_disable_unprepare(info->rtc_clk); | ||||
| 
 | ||||
| 	return ret; | ||||
|  | @ -583,15 +557,13 @@ static int s3c_rtc_suspend(struct device *dev) | |||
| 	struct s3c_rtc *info = dev_get_drvdata(dev); | ||||
| 
 | ||||
| 	clk_enable(info->rtc_clk); | ||||
| 
 | ||||
| 	/* save TICNT for anyone using periodic interrupts */ | ||||
| 	if (info->cpu_type == TYPE_S3C64XX) { | ||||
| 		info->ticnt_en_save = readw(info->base + S3C2410_RTCCON); | ||||
| 		info->ticnt_en_save &= S3C64XX_RTCCON_TICEN; | ||||
| 		info->ticnt_save = readl(info->base + S3C2410_TICNT); | ||||
| 	} else { | ||||
| 		info->ticnt_save = readb(info->base + S3C2410_TICNT); | ||||
| 	} | ||||
| 	s3c_rtc_enable(info, 0); | ||||
| 	if (info->data->save_tick_cnt) | ||||
| 		info->data->save_tick_cnt(info); | ||||
| 
 | ||||
| 	if (info->data->disable) | ||||
| 		info->data->disable(info); | ||||
| 
 | ||||
| 	if (device_may_wakeup(dev) && !info->wake_en) { | ||||
| 		if (enable_irq_wake(info->irq_alarm) == 0) | ||||
|  | @ -599,6 +571,7 @@ static int s3c_rtc_suspend(struct device *dev) | |||
| 		else | ||||
| 			dev_err(dev, "enable_irq_wake failed\n"); | ||||
| 	} | ||||
| 
 | ||||
| 	clk_disable(info->rtc_clk); | ||||
| 
 | ||||
| 	return 0; | ||||
|  | @ -607,25 +580,20 @@ static int s3c_rtc_suspend(struct device *dev) | |||
| static int s3c_rtc_resume(struct device *dev) | ||||
| { | ||||
| 	struct s3c_rtc *info = dev_get_drvdata(dev); | ||||
| 	unsigned int tmp; | ||||
| 
 | ||||
| 	clk_enable(info->rtc_clk); | ||||
| 	s3c_rtc_enable(info, 1); | ||||
| 	if (info->cpu_type == TYPE_S3C64XX) { | ||||
| 		writel(info->ticnt_save, info->base + S3C2410_TICNT); | ||||
| 		if (info->ticnt_en_save) { | ||||
| 			tmp = readw(info->base + S3C2410_RTCCON); | ||||
| 			writew(tmp | info->ticnt_en_save, | ||||
| 					info->base + S3C2410_RTCCON); | ||||
| 		} | ||||
| 	} else { | ||||
| 		writeb(info->ticnt_save, info->base + S3C2410_TICNT); | ||||
| 	} | ||||
| 
 | ||||
| 	if (info->data->enable) | ||||
| 		info->data->enable(info); | ||||
| 
 | ||||
| 	if (info->data->restore_tick_cnt) | ||||
| 		info->data->restore_tick_cnt(info); | ||||
| 
 | ||||
| 	if (device_may_wakeup(dev) && info->wake_en) { | ||||
| 		disable_irq_wake(info->irq_alarm); | ||||
| 		info->wake_en = false; | ||||
| 	} | ||||
| 
 | ||||
| 	clk_disable(info->rtc_clk); | ||||
| 
 | ||||
| 	return 0; | ||||
|  | @ -633,56 +601,206 @@ static int s3c_rtc_resume(struct device *dev) | |||
| #endif | ||||
| static SIMPLE_DEV_PM_OPS(s3c_rtc_pm_ops, s3c_rtc_suspend, s3c_rtc_resume); | ||||
| 
 | ||||
| #ifdef CONFIG_OF | ||||
| static struct s3c_rtc_drv_data s3c_rtc_drv_data_array[] = { | ||||
| 	[TYPE_S3C2410] = { TYPE_S3C2410 }, | ||||
| 	[TYPE_S3C2416] = { TYPE_S3C2416 }, | ||||
| 	[TYPE_S3C2443] = { TYPE_S3C2443 }, | ||||
| 	[TYPE_S3C64XX] = { TYPE_S3C64XX }, | ||||
| static void s3c24xx_rtc_irq(struct s3c_rtc *info, int mask) | ||||
| { | ||||
| 	clk_enable(info->rtc_clk); | ||||
| 	rtc_update_irq(info->rtc, 1, RTC_AF | RTC_IRQF); | ||||
| 	clk_disable(info->rtc_clk); | ||||
| 
 | ||||
| 	s3c_rtc_alarm_clk_enable(info, false); | ||||
| } | ||||
| 
 | ||||
| static void s3c6410_rtc_irq(struct s3c_rtc *info, int mask) | ||||
| { | ||||
| 	clk_enable(info->rtc_clk); | ||||
| 	rtc_update_irq(info->rtc, 1, RTC_AF | RTC_IRQF); | ||||
| 	writeb(mask, info->base + S3C2410_INTP); | ||||
| 	clk_disable(info->rtc_clk); | ||||
| 
 | ||||
| 	s3c_rtc_alarm_clk_enable(info, false); | ||||
| } | ||||
| 
 | ||||
| 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; | ||||
| 	tmp |= val; | ||||
| 
 | ||||
| 	writel(tmp, info->base + S3C2410_TICNT); | ||||
| } | ||||
| 
 | ||||
| static void s3c2416_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; | ||||
| 
 | ||||
| 	tmp |= S3C2443_TICNT_PART(val); | ||||
| 	writel(S3C2443_TICNT1_PART(val), info->base + S3C2443_TICNT1); | ||||
| 
 | ||||
| 	writel(S3C2416_TICNT2_PART(val), info->base + S3C2416_TICNT2); | ||||
| 
 | ||||
| 	writel(tmp, info->base + S3C2410_TICNT); | ||||
| } | ||||
| 
 | ||||
| static void s3c2443_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; | ||||
| 
 | ||||
| 	tmp |= S3C2443_TICNT_PART(val); | ||||
| 	writel(S3C2443_TICNT1_PART(val), info->base + S3C2443_TICNT1); | ||||
| 
 | ||||
| 	writel(tmp, info->base + S3C2410_TICNT); | ||||
| } | ||||
| 
 | ||||
| static void s3c6410_rtc_setfreq(struct s3c_rtc *info, int freq) | ||||
| { | ||||
| 	int val; | ||||
| 
 | ||||
| 	val = (info->rtc->max_user_freq / freq) - 1; | ||||
| 	writel(val, info->base + S3C2410_TICNT); | ||||
| } | ||||
| 
 | ||||
| static void s3c24xx_rtc_enable_tick(struct s3c_rtc *info, struct seq_file *seq) | ||||
| { | ||||
| 	unsigned int ticnt; | ||||
| 
 | ||||
| 	ticnt = readb(info->base + S3C2410_TICNT); | ||||
| 	ticnt &= S3C2410_TICNT_ENABLE; | ||||
| 
 | ||||
| 	seq_printf(seq, "periodic_IRQ\t: %s\n", ticnt  ? "yes" : "no"); | ||||
| } | ||||
| 
 | ||||
| static void s3c2416_rtc_select_tick_clk(struct s3c_rtc *info) | ||||
| { | ||||
| 	unsigned int con; | ||||
| 
 | ||||
| 	con = readw(info->base + S3C2410_RTCCON); | ||||
| 	con |= S3C2443_RTCCON_TICSEL; | ||||
| 	writew(con, info->base + S3C2410_RTCCON); | ||||
| } | ||||
| 
 | ||||
| static void s3c6410_rtc_enable_tick(struct s3c_rtc *info, struct seq_file *seq) | ||||
| { | ||||
| 	unsigned int ticnt; | ||||
| 
 | ||||
| 	ticnt = readw(info->base + S3C2410_RTCCON); | ||||
| 	ticnt &= S3C64XX_RTCCON_TICEN; | ||||
| 
 | ||||
| 	seq_printf(seq, "periodic_IRQ\t: %s\n", ticnt  ? "yes" : "no"); | ||||
| } | ||||
| 
 | ||||
| static void s3c24xx_rtc_save_tick_cnt(struct s3c_rtc *info) | ||||
| { | ||||
| 	info->ticnt_save = readb(info->base + S3C2410_TICNT); | ||||
| } | ||||
| 
 | ||||
| static void s3c24xx_rtc_restore_tick_cnt(struct s3c_rtc *info) | ||||
| { | ||||
| 	writeb(info->ticnt_save, info->base + S3C2410_TICNT); | ||||
| } | ||||
| 
 | ||||
| static void s3c6410_rtc_save_tick_cnt(struct s3c_rtc *info) | ||||
| { | ||||
| 	info->ticnt_en_save = readw(info->base + S3C2410_RTCCON); | ||||
| 	info->ticnt_en_save &= S3C64XX_RTCCON_TICEN; | ||||
| 	info->ticnt_save = readl(info->base + S3C2410_TICNT); | ||||
| } | ||||
| 
 | ||||
| static void s3c6410_rtc_restore_tick_cnt(struct s3c_rtc *info) | ||||
| { | ||||
| 	unsigned int con; | ||||
| 
 | ||||
| 	writel(info->ticnt_save, info->base + S3C2410_TICNT); | ||||
| 	if (info->ticnt_en_save) { | ||||
| 		con = readw(info->base + S3C2410_RTCCON); | ||||
| 		writew(con | info->ticnt_en_save, | ||||
| 				info->base + S3C2410_RTCCON); | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| static struct s3c_rtc_data const s3c2410_rtc_data = { | ||||
| 	.max_user_freq		= 128, | ||||
| 	.irq_handler		= s3c24xx_rtc_irq, | ||||
| 	.set_freq		= s3c2410_rtc_setfreq, | ||||
| 	.enable_tick		= s3c24xx_rtc_enable_tick, | ||||
| 	.save_tick_cnt		= s3c24xx_rtc_save_tick_cnt, | ||||
| 	.restore_tick_cnt	= s3c24xx_rtc_restore_tick_cnt, | ||||
| 	.enable			= s3c24xx_rtc_enable, | ||||
| 	.disable		= s3c24xx_rtc_disable, | ||||
| }; | ||||
| 
 | ||||
| static struct s3c_rtc_data const s3c2416_rtc_data = { | ||||
| 	.max_user_freq		= 32768, | ||||
| 	.irq_handler		= s3c24xx_rtc_irq, | ||||
| 	.set_freq		= s3c2416_rtc_setfreq, | ||||
| 	.enable_tick		= s3c24xx_rtc_enable_tick, | ||||
| 	.select_tick_clk	= s3c2416_rtc_select_tick_clk, | ||||
| 	.save_tick_cnt		= s3c24xx_rtc_save_tick_cnt, | ||||
| 	.restore_tick_cnt	= s3c24xx_rtc_restore_tick_cnt, | ||||
| 	.enable			= s3c24xx_rtc_enable, | ||||
| 	.disable		= s3c24xx_rtc_disable, | ||||
| }; | ||||
| 
 | ||||
| static struct s3c_rtc_data const s3c2443_rtc_data = { | ||||
| 	.max_user_freq		= 32768, | ||||
| 	.irq_handler		= s3c24xx_rtc_irq, | ||||
| 	.set_freq		= s3c2443_rtc_setfreq, | ||||
| 	.enable_tick		= s3c24xx_rtc_enable_tick, | ||||
| 	.select_tick_clk	= s3c2416_rtc_select_tick_clk, | ||||
| 	.save_tick_cnt		= s3c24xx_rtc_save_tick_cnt, | ||||
| 	.restore_tick_cnt	= s3c24xx_rtc_restore_tick_cnt, | ||||
| 	.enable			= s3c24xx_rtc_enable, | ||||
| 	.disable		= s3c24xx_rtc_disable, | ||||
| }; | ||||
| 
 | ||||
| static struct s3c_rtc_data const s3c6410_rtc_data = { | ||||
| 	.max_user_freq		= 32768, | ||||
| 	.irq_handler		= s3c6410_rtc_irq, | ||||
| 	.set_freq		= s3c6410_rtc_setfreq, | ||||
| 	.enable_tick		= s3c6410_rtc_enable_tick, | ||||
| 	.save_tick_cnt		= s3c6410_rtc_save_tick_cnt, | ||||
| 	.restore_tick_cnt	= s3c6410_rtc_restore_tick_cnt, | ||||
| 	.enable			= s3c24xx_rtc_enable, | ||||
| 	.disable		= s3c6410_rtc_disable, | ||||
| }; | ||||
| 
 | ||||
| static const struct of_device_id s3c_rtc_dt_match[] = { | ||||
| 	{ | ||||
| 		.compatible = "samsung,s3c2410-rtc", | ||||
| 		.data = &s3c_rtc_drv_data_array[TYPE_S3C2410], | ||||
| 		.data = (void *)&s3c2410_rtc_data, | ||||
| 	}, { | ||||
| 		.compatible = "samsung,s3c2416-rtc", | ||||
| 		.data = &s3c_rtc_drv_data_array[TYPE_S3C2416], | ||||
| 		.data = (void *)&s3c2416_rtc_data, | ||||
| 	}, { | ||||
| 		.compatible = "samsung,s3c2443-rtc", | ||||
| 		.data = &s3c_rtc_drv_data_array[TYPE_S3C2443], | ||||
| 		.data = (void *)&s3c2443_rtc_data, | ||||
| 	}, { | ||||
| 		.compatible = "samsung,s3c6410-rtc", | ||||
| 		.data = &s3c_rtc_drv_data_array[TYPE_S3C64XX], | ||||
| 		.data = (void *)&s3c6410_rtc_data, | ||||
| 	}, | ||||
| 	{}, | ||||
| 	{ /* sentinel */ }, | ||||
| }; | ||||
| MODULE_DEVICE_TABLE(of, s3c_rtc_dt_match); | ||||
| #endif | ||||
| 
 | ||||
| static struct platform_device_id s3c_rtc_driver_ids[] = { | ||||
| 	{ | ||||
| 		.name		= "s3c2410-rtc", | ||||
| 		.driver_data	= TYPE_S3C2410, | ||||
| 	}, { | ||||
| 		.name		= "s3c2416-rtc", | ||||
| 		.driver_data	= TYPE_S3C2416, | ||||
| 	}, { | ||||
| 		.name		= "s3c2443-rtc", | ||||
| 		.driver_data	= TYPE_S3C2443, | ||||
| 	}, { | ||||
| 		.name		= "s3c64xx-rtc", | ||||
| 		.driver_data	= TYPE_S3C64XX, | ||||
| 	}, | ||||
| 	{ } | ||||
| }; | ||||
| 
 | ||||
| MODULE_DEVICE_TABLE(platform, s3c_rtc_driver_ids); | ||||
| 
 | ||||
| static struct platform_driver s3c_rtc_driver = { | ||||
| 	.probe		= s3c_rtc_probe, | ||||
| 	.remove		= s3c_rtc_remove, | ||||
| 	.id_table	= s3c_rtc_driver_ids, | ||||
| 	.driver		= { | ||||
| 		.name	= "s3c-rtc", | ||||
| 		.owner	= THIS_MODULE, | ||||
|  | @ -690,7 +808,6 @@ static struct platform_driver s3c_rtc_driver = { | |||
| 		.of_match_table	= of_match_ptr(s3c_rtc_dt_match), | ||||
| 	}, | ||||
| }; | ||||
| 
 | ||||
| module_platform_driver(s3c_rtc_driver); | ||||
| 
 | ||||
| MODULE_DESCRIPTION("Samsung S3C RTC Driver"); | ||||
|  |  | |||
		Loading…
	
		Reference in a new issue
	
	 Chanwoo Choi
						Chanwoo Choi