⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 rtc-sh.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 2 页
字号:
		tm->tm_year = (yr100 * 100 + BCD2BIN(yr)) - 1900;		sec2 = readb(rtc->regbase + R64CNT);		cf_bit = readb(rtc->regbase + RCR1) & RCR1_CF;		spin_unlock_irq(&rtc->lock);	} while (cf_bit != 0 || ((sec128 ^ sec2) & RTC_BIT_INVERTED) != 0);#if RTC_BIT_INVERTED != 0	if ((sec128 & RTC_BIT_INVERTED))		tm->tm_sec--;#endif	dev_dbg(dev, "%s: tm is secs=%d, mins=%d, hours=%d, "		"mday=%d, mon=%d, year=%d, wday=%d\n",		__FUNCTION__,		tm->tm_sec, tm->tm_min, tm->tm_hour,		tm->tm_mday, tm->tm_mon + 1, tm->tm_year, tm->tm_wday);	if (rtc_valid_tm(tm) < 0) {		dev_err(dev, "invalid date\n");		rtc_time_to_tm(0, tm);	}	return 0;}static int sh_rtc_set_time(struct device *dev, struct rtc_time *tm){	struct platform_device *pdev = to_platform_device(dev);	struct sh_rtc *rtc = platform_get_drvdata(pdev);	unsigned int tmp;	int year;	spin_lock_irq(&rtc->lock);	/* Reset pre-scaler & stop RTC */	tmp = readb(rtc->regbase + RCR2);	tmp |= RCR2_RESET;	tmp &= ~RCR2_START;	writeb(tmp, rtc->regbase + RCR2);	writeb(BIN2BCD(tm->tm_sec),  rtc->regbase + RSECCNT);	writeb(BIN2BCD(tm->tm_min),  rtc->regbase + RMINCNT);	writeb(BIN2BCD(tm->tm_hour), rtc->regbase + RHRCNT);	writeb(BIN2BCD(tm->tm_wday), rtc->regbase + RWKCNT);	writeb(BIN2BCD(tm->tm_mday), rtc->regbase + RDAYCNT);	writeb(BIN2BCD(tm->tm_mon + 1), rtc->regbase + RMONCNT);	if (rtc->capabilities & RTC_CAP_4_DIGIT_YEAR) {		year = (BIN2BCD((tm->tm_year + 1900) / 100) << 8) |			BIN2BCD(tm->tm_year % 100);		writew(year, rtc->regbase + RYRCNT);	} else {		year = tm->tm_year % 100;		writeb(BIN2BCD(year), rtc->regbase + RYRCNT);	}	/* Start RTC */	tmp = readb(rtc->regbase + RCR2);	tmp &= ~RCR2_RESET;	tmp |= RCR2_RTCEN | RCR2_START;	writeb(tmp, rtc->regbase + RCR2);	spin_unlock_irq(&rtc->lock);	return 0;}static inline int sh_rtc_read_alarm_value(struct sh_rtc *rtc, int reg_off){	unsigned int byte;	int value = 0xff;	/* return 0xff for ignored values */	byte = readb(rtc->regbase + reg_off);	if (byte & AR_ENB) {		byte &= ~AR_ENB;	/* strip the enable bit */		value = BCD2BIN(byte);	}	return value;}static int sh_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *wkalrm){	struct platform_device *pdev = to_platform_device(dev);	struct sh_rtc *rtc = platform_get_drvdata(pdev);	struct rtc_time* tm = &wkalrm->time;	spin_lock_irq(&rtc->lock);	tm->tm_sec	= sh_rtc_read_alarm_value(rtc, RSECAR);	tm->tm_min	= sh_rtc_read_alarm_value(rtc, RMINAR);	tm->tm_hour	= sh_rtc_read_alarm_value(rtc, RHRAR);	tm->tm_wday	= sh_rtc_read_alarm_value(rtc, RWKAR);	tm->tm_mday	= sh_rtc_read_alarm_value(rtc, RDAYAR);	tm->tm_mon	= sh_rtc_read_alarm_value(rtc, RMONAR);	if (tm->tm_mon > 0)		tm->tm_mon -= 1; /* RTC is 1-12, tm_mon is 0-11 */	tm->tm_year     = 0xffff;	wkalrm->enabled = (readb(rtc->regbase + RCR1) & RCR1_AIE) ? 1 : 0;	spin_unlock_irq(&rtc->lock);	return 0;}static inline void sh_rtc_write_alarm_value(struct sh_rtc *rtc,					    int value, int reg_off){	/* < 0 for a value that is ignored */	if (value < 0)		writeb(0, rtc->regbase + reg_off);	else		writeb(BIN2BCD(value) | AR_ENB,  rtc->regbase + reg_off);}static int sh_rtc_check_alarm(struct rtc_time* tm){	/*	 * The original rtc says anything > 0xc0 is "don't care" or "match	 * all" - most users use 0xff but rtc-dev uses -1 for the same thing.	 * The original rtc doesn't support years - some things use -1 and	 * some 0xffff. We use -1 to make out tests easier.	 */	if (tm->tm_year == 0xffff)		tm->tm_year = -1;	if (tm->tm_mon >= 0xff)		tm->tm_mon = -1;	if (tm->tm_mday >= 0xff)		tm->tm_mday = -1;	if (tm->tm_wday >= 0xff)		tm->tm_wday = -1;	if (tm->tm_hour >= 0xff)		tm->tm_hour = -1;	if (tm->tm_min >= 0xff)		tm->tm_min = -1;	if (tm->tm_sec >= 0xff)		tm->tm_sec = -1;	if (tm->tm_year > 9999 ||		tm->tm_mon >= 12 ||		tm->tm_mday == 0 || tm->tm_mday >= 32 ||		tm->tm_wday >= 7 ||		tm->tm_hour >= 24 ||		tm->tm_min >= 60 ||		tm->tm_sec >= 60)		return -EINVAL;	return 0;}static int sh_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *wkalrm){	struct platform_device *pdev = to_platform_device(dev);	struct sh_rtc *rtc = platform_get_drvdata(pdev);	unsigned int rcr1;	struct rtc_time *tm = &wkalrm->time;	int mon, err;	err = sh_rtc_check_alarm(tm);	if (unlikely(err < 0))		return err;	spin_lock_irq(&rtc->lock);	/* disable alarm interrupt and clear the alarm flag */	rcr1 = readb(rtc->regbase + RCR1);	rcr1 &= ~(RCR1_AF|RCR1_AIE);	writeb(rcr1, rtc->regbase + RCR1);	rtc->rearm_aie = 0;	/* set alarm time */	sh_rtc_write_alarm_value(rtc, tm->tm_sec,  RSECAR);	sh_rtc_write_alarm_value(rtc, tm->tm_min,  RMINAR);	sh_rtc_write_alarm_value(rtc, tm->tm_hour, RHRAR);	sh_rtc_write_alarm_value(rtc, tm->tm_wday, RWKAR);	sh_rtc_write_alarm_value(rtc, tm->tm_mday, RDAYAR);	mon = tm->tm_mon;	if (mon >= 0)		mon += 1;	sh_rtc_write_alarm_value(rtc, mon, RMONAR);	if (wkalrm->enabled) {		rcr1 |= RCR1_AIE;		writeb(rcr1, rtc->regbase + RCR1);	}	spin_unlock_irq(&rtc->lock);	return 0;}static struct rtc_class_ops sh_rtc_ops = {	.open		= sh_rtc_open,	.release	= sh_rtc_release,	.ioctl		= sh_rtc_ioctl,	.read_time	= sh_rtc_read_time,	.set_time	= sh_rtc_set_time,	.read_alarm	= sh_rtc_read_alarm,	.set_alarm	= sh_rtc_set_alarm,	.proc		= sh_rtc_proc,};static int __devinit sh_rtc_probe(struct platform_device *pdev){	struct sh_rtc *rtc;	struct resource *res;	int ret = -ENOENT;	rtc = kzalloc(sizeof(struct sh_rtc), GFP_KERNEL);	if (unlikely(!rtc))		return -ENOMEM;	spin_lock_init(&rtc->lock);	rtc->periodic_irq = platform_get_irq(pdev, 0);	if (unlikely(rtc->periodic_irq < 0)) {		dev_err(&pdev->dev, "No IRQ for period\n");		goto err_badres;	}	rtc->carry_irq = platform_get_irq(pdev, 1);	if (unlikely(rtc->carry_irq < 0)) {		dev_err(&pdev->dev, "No IRQ for carry\n");		goto err_badres;	}	rtc->alarm_irq = platform_get_irq(pdev, 2);	if (unlikely(rtc->alarm_irq < 0)) {		dev_err(&pdev->dev, "No IRQ for alarm\n");		goto err_badres;	}	res = platform_get_resource(pdev, IORESOURCE_IO, 0);	if (unlikely(res == NULL)) {		dev_err(&pdev->dev, "No IO resource\n");		goto err_badres;	}	rtc->regsize = res->end - res->start + 1;	rtc->res = request_mem_region(res->start, rtc->regsize, pdev->name);	if (unlikely(!rtc->res)) {		ret = -EBUSY;		goto err_badres;	}	rtc->regbase = (void __iomem *)rtc->res->start;	if (unlikely(!rtc->regbase)) {		ret = -EINVAL;		goto err_badmap;	}	rtc->rtc_dev = rtc_device_register("sh", &pdev->dev,					   &sh_rtc_ops, THIS_MODULE);	if (IS_ERR(rtc->rtc_dev)) {		ret = PTR_ERR(rtc->rtc_dev);		goto err_badmap;	}	rtc->capabilities = RTC_DEF_CAPABILITIES;	if (pdev->dev.platform_data) {		struct sh_rtc_platform_info *pinfo = pdev->dev.platform_data;		/*		 * Some CPUs have special capabilities in addition to the		 * default set. Add those in here.		 */		rtc->capabilities |= pinfo->capabilities;	}	platform_set_drvdata(pdev, rtc);	return 0;err_badmap:	release_resource(rtc->res);err_badres:	kfree(rtc);	return ret;}static int __devexit sh_rtc_remove(struct platform_device *pdev){	struct sh_rtc *rtc = platform_get_drvdata(pdev);	if (likely(rtc->rtc_dev))		rtc_device_unregister(rtc->rtc_dev);	sh_rtc_setpie(&pdev->dev, 0);	sh_rtc_setaie(&pdev->dev, 0);	release_resource(rtc->res);	platform_set_drvdata(pdev, NULL);	kfree(rtc);	return 0;}static struct platform_driver sh_rtc_platform_driver = {	.driver		= {		.name	= DRV_NAME,		.owner	= THIS_MODULE,	},	.probe		= sh_rtc_probe,	.remove		= __devexit_p(sh_rtc_remove),};static int __init sh_rtc_init(void){	return platform_driver_register(&sh_rtc_platform_driver);}static void __exit sh_rtc_exit(void){	platform_driver_unregister(&sh_rtc_platform_driver);}module_init(sh_rtc_init);module_exit(sh_rtc_exit);MODULE_DESCRIPTION("SuperH on-chip RTC driver");MODULE_VERSION(DRV_VERSION);MODULE_AUTHOR("Paul Mundt <lethal@linux-sh.org>, Jamie Lenehan <lenehan@twibble.org>");MODULE_LICENSE("GPL");

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -