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

📄 rtc-rs5c372.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 2 页
字号:
	t->time.tm_hour = rs5c_reg2hr(rs5c, rs5c->regs[RS5C_REG_ALARM_A_HOURS]);	t->time.tm_mday = -1;	t->time.tm_mon = -1;	t->time.tm_year = -1;	t->time.tm_wday = -1;	t->time.tm_yday = -1;	t->time.tm_isdst = -1;	/* ... and status */	t->enabled = !!(rs5c->regs[RS5C_REG_CTRL1] & RS5C_CTRL1_AALE);	t->pending = !!(rs5c->regs[RS5C_REG_CTRL2] & RS5C_CTRL2_AAFG);	return 0;}static int rs5c_set_alarm(struct device *dev, struct rtc_wkalrm *t){	struct i2c_client	*client = to_i2c_client(dev);	struct rs5c372		*rs5c = i2c_get_clientdata(client);	int			status;	unsigned char		buf[4];	/* only handle up to 24 hours in the future, like RTC_ALM_SET */	if (t->time.tm_mday != -1			|| t->time.tm_mon != -1			|| t->time.tm_year != -1)		return -EINVAL;	/* REVISIT: round up tm_sec */	/* if needed, disable irq (clears pending status) */	status = rs5c_get_regs(rs5c);	if (status < 0)		return status;	if (rs5c->regs[RS5C_REG_CTRL1] & RS5C_CTRL1_AALE) {		buf[0] = RS5C_ADDR(RS5C_REG_CTRL1);		buf[1] = rs5c->regs[RS5C_REG_CTRL1] & ~RS5C_CTRL1_AALE;		if (i2c_master_send(client, buf, 2) != 2) {			pr_debug("%s: can't disable alarm\n", rs5c->rtc->name);			return -EIO;		}		rs5c->regs[RS5C_REG_CTRL1] = buf[1];	}	/* set alarm */	buf[0] = RS5C_ADDR(RS5C_REG_ALARM_A_MIN);	buf[1] = BIN2BCD(t->time.tm_min);	buf[2] = rs5c_hr2reg(rs5c, t->time.tm_hour);	buf[3] = 0x7f;	/* any/all days */	if ((i2c_master_send(client, buf, 4)) != 4) {		pr_debug("%s: can't set alarm time\n", rs5c->rtc->name);		return -EIO;	}	/* ... and maybe enable its irq */	if (t->enabled) {		buf[0] = RS5C_ADDR(RS5C_REG_CTRL1);		buf[1] = rs5c->regs[RS5C_REG_CTRL1] | RS5C_CTRL1_AALE;		if ((i2c_master_send(client, buf, 2)) != 2)			printk(KERN_WARNING "%s: can't enable alarm\n",				rs5c->rtc->name);		rs5c->regs[RS5C_REG_CTRL1] = buf[1];	}	return 0;}#if defined(CONFIG_RTC_INTF_PROC) || defined(CONFIG_RTC_INTF_PROC_MODULE)static int rs5c372_rtc_proc(struct device *dev, struct seq_file *seq){	int err, osc, trim;	err = rs5c372_get_trim(to_i2c_client(dev), &osc, &trim);	if (err == 0) {		seq_printf(seq, "crystal\t\t: %d.%03d KHz\n",				osc / 1000, osc % 1000);		seq_printf(seq, "trim\t\t: %d\n", trim);	}	return 0;}#else#define	rs5c372_rtc_proc	NULL#endifstatic const struct rtc_class_ops rs5c372_rtc_ops = {	.proc		= rs5c372_rtc_proc,	.ioctl		= rs5c_rtc_ioctl,	.read_time	= rs5c372_rtc_read_time,	.set_time	= rs5c372_rtc_set_time,	.read_alarm	= rs5c_read_alarm,	.set_alarm	= rs5c_set_alarm,};#if defined(CONFIG_RTC_INTF_SYSFS) || defined(CONFIG_RTC_INTF_SYSFS_MODULE)static ssize_t rs5c372_sysfs_show_trim(struct device *dev,				struct device_attribute *attr, char *buf){	int err, trim;	err = rs5c372_get_trim(to_i2c_client(dev), NULL, &trim);	if (err)		return err;	return sprintf(buf, "%d\n", trim);}static DEVICE_ATTR(trim, S_IRUGO, rs5c372_sysfs_show_trim, NULL);static ssize_t rs5c372_sysfs_show_osc(struct device *dev,				struct device_attribute *attr, char *buf){	int err, osc;	err = rs5c372_get_trim(to_i2c_client(dev), &osc, NULL);	if (err)		return err;	return sprintf(buf, "%d.%03d KHz\n", osc / 1000, osc % 1000);}static DEVICE_ATTR(osc, S_IRUGO, rs5c372_sysfs_show_osc, NULL);static int rs5c_sysfs_register(struct device *dev){	int err;	err = device_create_file(dev, &dev_attr_trim);	if (err)		return err;	err = device_create_file(dev, &dev_attr_osc);	if (err)		device_remove_file(dev, &dev_attr_trim);	return err;}static void rs5c_sysfs_unregister(struct device *dev){	device_remove_file(dev, &dev_attr_trim);	device_remove_file(dev, &dev_attr_osc);}#elsestatic int rs5c_sysfs_register(struct device *dev){	return 0;}static void rs5c_sysfs_unregister(struct device *dev){	/* nothing */}#endif	/* SYSFS */static struct i2c_driver rs5c372_driver;static int rs5c372_probe(struct i2c_client *client){	int err = 0;	struct rs5c372 *rs5c372;	struct rtc_time tm;	dev_dbg(&client->dev, "%s\n", __FUNCTION__);	if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {		err = -ENODEV;		goto exit;	}	if (!(rs5c372 = kzalloc(sizeof(struct rs5c372), GFP_KERNEL))) {		err = -ENOMEM;		goto exit;	}	/* we read registers 0x0f then 0x00-0x0f; skip the first one */	rs5c372->regs=&rs5c372->buf[1];	rs5c372->client = client;	i2c_set_clientdata(client, rs5c372);	err = rs5c_get_regs(rs5c372);	if (err < 0)		goto exit_kfree;	if (strcmp(client->name, "rs5c372a") == 0)		rs5c372->type = rtc_rs5c372a;	else if (strcmp(client->name, "rs5c372b") == 0)		rs5c372->type = rtc_rs5c372b;	else if (strcmp(client->name, "rv5c386") == 0)		rs5c372->type = rtc_rv5c386;	else if (strcmp(client->name, "rv5c387a") == 0)		rs5c372->type = rtc_rv5c387a;	else {		rs5c372->type = rtc_rs5c372b;		dev_warn(&client->dev, "assuming rs5c372b\n");	}	/* clock may be set for am/pm or 24 hr time */	switch (rs5c372->type) {	case rtc_rs5c372a:	case rtc_rs5c372b:		/* alarm uses ALARM_A; and nINTRA on 372a, nINTR on 372b.		 * so does periodic irq, except some 327a modes.		 */		if (rs5c372->regs[RS5C_REG_CTRL2] & RS5C372_CTRL2_24)			rs5c372->time24 = 1;		break;	case rtc_rv5c386:	case rtc_rv5c387a:		if (rs5c372->regs[RS5C_REG_CTRL1] & RV5C387_CTRL1_24)			rs5c372->time24 = 1;		/* alarm uses ALARM_W; and nINTRB for alarm and periodic		 * irq, on both 386 and 387		 */		break;	default:		dev_err(&client->dev, "unknown RTC type\n");		goto exit_kfree;	}	/* if the oscillator lost power and no other software (like	 * the bootloader) set it up, do it here.	 */	if (rs5c372->regs[RS5C_REG_CTRL2] & RS5C_CTRL2_XSTP) {		unsigned char buf[3];		rs5c372->regs[RS5C_REG_CTRL2] &= ~RS5C_CTRL2_XSTP;		buf[0] = RS5C_ADDR(RS5C_REG_CTRL1);		buf[1] = rs5c372->regs[RS5C_REG_CTRL1];		buf[2] = rs5c372->regs[RS5C_REG_CTRL2];		/* use 24hr mode */		switch (rs5c372->type) {		case rtc_rs5c372a:		case rtc_rs5c372b:			buf[2] |= RS5C372_CTRL2_24;			rs5c372->time24 = 1;			break;		case rtc_rv5c386:		case rtc_rv5c387a:			buf[1] |= RV5C387_CTRL1_24;			rs5c372->time24 = 1;			break;		default:			/* impossible */			break;		}		if ((i2c_master_send(client, buf, 3)) != 3) {			dev_err(&client->dev, "setup error\n");			goto exit_kfree;		}		rs5c372->regs[RS5C_REG_CTRL1] = buf[1];		rs5c372->regs[RS5C_REG_CTRL2] = buf[2];	}	if (rs5c372_get_datetime(client, &tm) < 0)		dev_warn(&client->dev, "clock needs to be set\n");	dev_info(&client->dev, "%s found, %s, driver version " DRV_VERSION "\n",			({ char *s; switch (rs5c372->type) {			case rtc_rs5c372a:	s = "rs5c372a"; break;			case rtc_rs5c372b:	s = "rs5c372b"; break;			case rtc_rv5c386:	s = "rv5c386"; break;			case rtc_rv5c387a:	s = "rv5c387a"; break;			default:		s = "chip"; break;			}; s;}),			rs5c372->time24 ? "24hr" : "am/pm"			);	/* REVISIT use client->irq to register alarm irq ... */	rs5c372->rtc = rtc_device_register(rs5c372_driver.driver.name,				&client->dev, &rs5c372_rtc_ops, THIS_MODULE);	if (IS_ERR(rs5c372->rtc)) {		err = PTR_ERR(rs5c372->rtc);		goto exit_kfree;	}	err = rs5c_sysfs_register(&client->dev);	if (err)		goto exit_devreg;	return 0;exit_devreg:	rtc_device_unregister(rs5c372->rtc);exit_kfree:	kfree(rs5c372);exit:	return err;}static int rs5c372_remove(struct i2c_client *client){	struct rs5c372 *rs5c372 = i2c_get_clientdata(client);	rtc_device_unregister(rs5c372->rtc);	rs5c_sysfs_unregister(&client->dev);	kfree(rs5c372);	return 0;}static struct i2c_driver rs5c372_driver = {	.driver		= {		.name	= "rtc-rs5c372",	},	.probe		= rs5c372_probe,	.remove		= rs5c372_remove,};static __init int rs5c372_init(void){	return i2c_add_driver(&rs5c372_driver);}static __exit void rs5c372_exit(void){	i2c_del_driver(&rs5c372_driver);}module_init(rs5c372_init);module_exit(rs5c372_exit);MODULE_AUTHOR(		"Pavel Mironchik <pmironchik@optifacio.net>, "		"Alessandro Zummo <a.zummo@towertech.it>");MODULE_DESCRIPTION("Ricoh RS5C372 RTC driver");MODULE_LICENSE("GPL");MODULE_VERSION(DRV_VERSION);

⌨️ 快捷键说明

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