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

📄 rtc8025.c

📁 i2c接口的实时时钟芯片rx8025的linux驱动程序
💻 C
📖 第 1 页 / 共 2 页
字号:
	char wb;
	void __user *uarg = (void __user *)arg;
	int ret = -EINVAL;
	
	switch(cmd){
	case RTC_RD_TIME:
		ret = rx8025_get_rtctime(&tm);
		if (ret)
			break;
		ret = copy_to_user(uarg, &tm, sizeof(tm));
		if (ret)
			ret = -EFAULT;
		break;

	case RTC_SET_TIME:
		if (!capable(CAP_SYS_TIME)) {
			ret = -EACCES;
			break;
		}
		ret = copy_from_user(&tm, uarg, sizeof(tm));
		if (ret) {
			ret = -EFAULT;
			break;
		}
		ret = rx8025_set_rtctime(&tm);
		break;
		
	case RTC_RD_WB:
		ret = rx8025_get_wb(&wb);
		if (ret)
			break;
		//printk(KERN_ALERT "read wb is 0x%x\n", wb);
		ret = copy_to_user(uarg, &wb, sizeof(wb));
		if (ret)
			ret = -EFAULT;
		break;
		
	case RTC_SET_WB:
		ret = copy_from_user(&wb, uarg, sizeof(wb));
		//printk(KERN_ALERT "ioctl set is 0x%x\n", wb);	
		if (ret) {
			ret = -EFAULT;
			break;
		}	
		ret = rx8025_set_wb(&wb);
		break;	
	}
	return ret;
}

static struct file_operations rx8025_fops = {
	.owner		= THIS_MODULE,
	.ioctl		= rx8025_ioctl,
};

static struct miscdevice rx8025_miscdev = {
	.minor		= RTC8025_MINOR,
	.name		= RTC8025_NAME,
	.fops		= &rx8025_fops,
};
// a by xjr 2007.1.26 e

//  m by xjr 2007.1.26 b
/*
static struct rtc_ops rx8025_rtc_ops = {
	.owner = THIS_MODULE,
	.read_time   = rx8025_get_rtctime,
	.set_time   = rx8025_set_rtctime,
};
*/
//  m by xjr 2007.1.26 e

static int rx8025_attach_adapter(struct i2c_adapter *adapter)
{
	return i2c_probe(adapter, &addr_data, &rx8025_detect);
}

static int rx8025_detect(struct i2c_adapter *adapter, int address, int kind)
{
	int err = 0;
	struct rx8025_data *data;
	struct i2c_client *new_client;
	
	if (!i2c_check_functionality(adapter, I2C_FUNC_I2C)) {
		dev_dbg(&adapter->dev, "doesn't support full I2C\n");
		goto errout;
	}

	if (!(data = kzalloc(sizeof(*data), GFP_KERNEL))) {
		dev_dbg(&adapter->dev, "failed to alloc memory\n");
		err = -ENOMEM;
		goto errout;
	}

	new_client = &data->client;
	i2c_set_clientdata(new_client, data);
	new_client->addr = address;
	new_client->adapter = adapter;
	new_client->driver = &rx8025_driver;
	new_client->flags = 0;

	INIT_LIST_HEAD(&data->list);

	if (kind == 0)
		kind = rx8025;

	if (kind < 0) {
		u8 command = RX8025_REG_SEC << 4 | 0x08;
		u8 result[8] ;
		int err;

		/* a by cui 200704012 */
		/* fisrt read register RX8025_REG_MONTH 
		    if bit 7 isn't "0" then clear it*/
		result[0] = RX8025_REG_MONTH<<4 | 0x08;
		result[1] = 0xff;
		struct i2c_msg msg1[] = {
			{
				.addr	= address,
				.len	= 1,
				.buf	= result,
			}, {
				.addr	= address,
				.flags	= I2C_M_RD,
				.len	= 1,
				.buf	= result + 1,
			}
		};

		if ( (err = i2c_transfer(adapter, msg1, 2)) < 2) {
			err = err >= 0 ? 0 : err;
			goto errout_free;
		}
		
		if(result[1] &0x80) {
			result[0] = RX8025_REG_MONTH<<4 | 0x08;
			result[1] &= 0x7f;
			msg1[0].addr = address;
			msg1[0].len = 2;
			msg1[0].buf=result;
			msg1[0].flags = 0;

			if ( (err = i2c_transfer(adapter, msg1, 1)) < 1) {
				err = err >= 0 ? 0 : err;
				goto errout_free;
			}
		}

		/* fisrt read register RX8025_REG_DIGOFF 
		    if bit 7 isn't "0" then clear it*/
		result[0] = RX8025_REG_DIGOFF<<4 | 0x08;
		result[1] = 0xff;
		struct i2c_msg msg2[] = {
			{
				.addr	= address,
				.len	= 1,
				.buf	= result,
			}, {
				.addr	= address,
				.flags	= I2C_M_RD,
				.len	= 1,
				.buf	= result + 1,
			}
		};

		if ( (err = i2c_transfer(adapter, msg2, 2)) < 2) {
			err = err >= 0 ? 0 : err;
			goto errout_free;
		}
		
		if(result[1] &0x80) {
			result[0] = RX8025_REG_DIGOFF<<4 | 0x08;
			result[1] &= 0x7f;
			msg1[0].addr = address;
			msg1[0].len = 2;
			msg1[0].buf=result;
			msg1[0].flags = 0;

			if ( (err = i2c_transfer(adapter, msg2, 1)) < 1) {
				err = err >= 0 ? 0 : err;
				goto errout_free;
			}
		}


		/* continue detect */
		struct i2c_msg msg[] = {
			{
				.addr	= address,
				.len	= 1,
				.buf	= &command,
			}, {
				.addr	= address,
				.flags	= I2C_M_RD,
				.len	= ARRAY_SIZE(result),
				.buf	= result,
			}
		};

		if ((err = i2c_transfer(adapter, msg, ARRAY_SIZE(msg)))
				< ARRAY_SIZE(msg)) {
			err = err >= 0 ? 0 : err;
			goto errout_free;
		}

		/* bits 7 of RX8025_REG_MONTH and RX8025_REG_DIGOFF
		 * "should be set as "0".  Their value when read will be "0""
		 *
		 * There are serveral more read-only bits who's "value when
		 * read is always "0"" according to the spec, but setting them
		 * yields a "1" sometimes.
		 */
		if (((result[RX8025_REG_MONTH] | result[RX8025_REG_DIGOFF])
					& 0x80)) {
			dev_dbg(&adapter->dev, "RX8025_REG_MONTH = %x, "
					"RX8025_REG_DIGOFF = %x\n",
					result[RX8025_REG_MONTH],
					result[RX8025_REG_DIGOFF]);
			goto errout_free;
		}

		kind = rx8025;
	}

	BUG_ON(kind != rx8025);

	strlcpy(new_client->name, "rx8025", I2C_NAME_SIZE);

	if(down_interruptible(&rx8025_lock)) {
		err = -ERESTARTSYS;
		goto errout_free;
	}

	if ((err = i2c_attach_client(new_client)))
		goto errout_unlock;

	list_add(&data->list, &rx8025_clients);

	if ((err = rx8025_init_client(new_client)))
		goto errout_detach;

	if (!rx8025_rtcclient) {
		rx8025_rtcclient = new_client;
		//  m by xjr 2007.1.26 b
		/*
		if ((err = register_rtc(&rx8025_rtc_ops))) {
			rx8025_rtcclient = NULL;
			printk(KERN_ERR "Failed to register rtc device\n");
		}
		*/
		if ((err = misc_register(&rx8025_miscdev))){
			rx8025_rtcclient = NULL;
			printk(KERN_ERR "Failed to register rtc8025 device\n");
		}
		//  m by xjr 2007.1.26 e
	}
	up(&rx8025_lock);

	printk(KERN_INFO "loaded driver for RX-8025 SA/NB on addr %d\n",
	       address);

	return 0;

errout_detach:
	rx8025_detach_client(new_client);

errout_unlock:
	up(&rx8025_lock);

errout_free:
	kfree(data);

errout:
	dev_dbg(&adapter->dev, "Failed to detect rx8025\n");
	return err;
}

static int rx8025_init_client(struct i2c_client *client)
{
	u8 command[3] = { RX8025_REG_CTRL1 << 4 | 0x08, };
	int err;

	struct i2c_msg msg[] = {
		{
			.addr	= client->addr,
			.len	= 1,
			.buf	= command,
		}, {
			.addr	= client->addr,
			.flags	= I2C_M_RD,
			.len	= ARRAY_SIZE(command) - 1,
			.buf	= command + 1,
		}
	};

	if ((err = i2c_transfer(client->adapter, msg, 2)) < 2) {
		err = err >= 0 ? -EIO : err;
		goto errout;
	}

	/* Assert 24-hour mode */
	command[1] |= RX8025_BIT_CTRL1_1224;

	/* disable Alarm D and Alarm W */
	command[1] &= ~(RX8025_BIT_CTRL1_DALE | RX8025_BIT_CTRL1_WALE);

	if (command[2] & RX8025_BIT_CTRL2_PON)
		dev_warn(&client->dev, "power-on reset was detected, "
				"you may have to readjust the clock\n");

	if (command[2] & RX8025_BIT_CTRL2_VDET)
		dev_warn(&client->dev, "a power voltage drop was detected, "
				"you may have to readjust the clock\n");

	command[2] &= ~(RX8025_BIT_CTRL2_PON | RX8025_BIT_CTRL2_VDET);

	command[0] = RX8025_REG_CTRL1 << 4;
	msg[0].len = ARRAY_SIZE(command);

	if ((err = i2c_transfer(client->adapter, msg, 1)) < 1) {
		err = err >= 0 ? -EIO : err;
		goto errout;
	}

	return 0;

errout:
	return err;
}

static int rx8025_detach_client(struct i2c_client *client)
{
	int err;
	struct rx8025_data *data = i2c_get_clientdata(client);

	if(down_interruptible(&rx8025_lock))
		return -ERESTARTSYS;

	BUG_ON(list_empty(&rx8025_clients));

	if (rx8025_rtcclient == client) {
		struct list_head *lh = rx8025_clients.next;


		if (list_entry(lh, struct rx8025_data, list) == data)
			lh = lh->next;

		if (lh == &rx8025_clients) {
			//  m by xjr 2007.1.26 b
			//unregister_rtc(&rx8025_rtc_ops);
			misc_deregister(&rx8025_miscdev);
			// m by xjr 2007.1.26 e
			rx8025_rtcclient = NULL;
		} else
			rx8025_rtcclient = &data->client;
	}

	if ((err = i2c_detach_client(client))) {
		up(&rx8025_lock);
		return err;
	}

	list_del(&data->list);

	up(&rx8025_lock);
	kfree(data);
	return 0;
}

static int __init rx8025_init(void)
{
	printk("rx8025_init\n");
		
	return i2c_add_driver(&rx8025_driver);
}

static void __exit rx8025_exit(void)
{
	i2c_del_driver(&rx8025_driver);
}

MODULE_AUTHOR("arming <xjr555@sina.com>");
MODULE_DESCRIPTION("EPSON RX8025 RTC Driver");
MODULE_LICENSE("GPL");

module_init(rx8025_init);
module_exit(rx8025_exit);

⌨️ 快捷键说明

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