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

📄 rtc8025.c

📁 i2c接口的实时时钟芯片rx8025的linux驱动程序
💻 C
📖 第 1 页 / 共 2 页
字号:
/*
 *  linux/drivers/i2c/chips/rtc8025.c
 *
 *  Copyright (C) 2007 arming
 *
 *	based on linux/drivers/i2c/chips/rtc8564.c
 *  Copyright (C) 2002-2004 Stefan Eletzhofer
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2 as
 * published by the Free Software Foundation.
 *
 * Driver for system3's EPSON RTC 8025 chip
 */
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/bcd.h>
#include <linux/i2c.h>
#include <linux/init.h>
#include <linux/list.h>
#include <linux/rtc.h>
#include <linux/spinlock.h>
#include <linux/fs.h>
#include <asm/uaccess.h>

#include <asm/rtc.h>
#include <asm/mach/time.h>

#include "rtc8025.h"
//#define RTC_RD_WB 0x13
//#define RTC_SET_WB 0x14
//#define DEBUG	1

static unsigned short normal_i2c[] = { 0x32, I2C_CLIENT_END };
I2C_CLIENT_INSMOD_1(rx8025);

static int rx8025_attach_adapter(struct i2c_adapter *adapter);
static int rx8025_detect(struct i2c_adapter *adapter, int address, int kind);
static int rx8025_init_client(struct i2c_client *client);
static int rx8025_detach_client(struct i2c_client *client);

static struct i2c_driver rx8025_driver = {
	.owner = THIS_MODULE,
	.name = "rx8025-rtc",
	.id		= I2C_DRIVERID_RTC8025,
	.flags		= I2C_DF_NOTIFY,
	.attach_adapter = &rx8025_attach_adapter,
	.detach_client = &rx8025_detach_client,
};

static struct i2c_client *rx8025_rtcclient = NULL;

struct rx8025_data {
	struct i2c_client client;
	struct list_head list;
};

static LIST_HEAD(rx8025_clients);
static DECLARE_MUTEX(rx8025_lock);

static int rx8025_get_wb(char *val)
{
	u8 command[2] = { RX8025_REG_DIGOFF << 4 | 0x08, 4};
	int err;
	struct i2c_msg msg[] = {
		{	
			.addr 	= rx8025_rtcclient->addr,
			.len	= 1,
			.buf	= command,
		}, {
			.addr	= rx8025_rtcclient->addr,
			.flags	= I2C_M_RD,
			.len	= ARRAY_SIZE(command) - 1,
			.buf	= command + 1,
		}
	};

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

	if (!rx8025_rtcclient) {
		err = -EIO;
		goto errout_unlock;
	}

	if (!val) {
		dev_err(&rx8025_rtcclient->dev,
			"rx8025_get_rtctime: passed in wb == NULL\n");
		err = -EINVAL;
		goto errout_unlock;
	}

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

	up(&rx8025_lock);

	dev_dbg(&rx8025_rtcclient->dev,
			"rx8025_get_wb: read 0x%02x\n", command[1]);

	//printk("wb addr is 0x%x\n", command[0]);

	//printk("read from wb is 0x%x\n", command[1]);
	(*val) = command[1];
	
	dev_dbg(&rx8025_rtcclient->dev,
			"rx8025_get_wb: result: 0x%02x\n", *val);

	return 0;

errout_unlock:
	up(&rx8025_lock);
	return err;
}

static int rx8025_set_wb(char *val)
{
	u8 command[2] = { RX8025_REG_DIGOFF << 4, };
	int err;
	struct i2c_msg msg = {
		.addr	= rx8025_rtcclient->addr,
		.len    = 2,
		.buf    = command,
	};

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

	if (!rx8025_rtcclient) {
		err = -EIO;
		goto errout_unlock;
	}

	if (!val) {
                dev_err(&rx8025_rtcclient->dev,
                        "rx8025_get_rtctime: passed in wb == NULL\n");
                err = -EINVAL;
                goto errout_unlock;
        }
	
	//printk("set wb value before write is 0x%x\n",(*val));
	/*if ((*val)<0 || (*val)>127) {
		dev_err(&rx8025_rtcclient->dev,
			"rx8025_set_wb: passed in wb outof range\n");
		err = -EINVAL;
		goto errout_unlock;
	}*/
	
	command[1] = *val;
	//printk("the wb set is 0x%x", command[1]);
	
	dev_dbg(&rx8025_rtcclient->dev,
			"rx8025_set_wb: send 0x%02x 0x%02x\n", command[0], command[1]);

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

	up(&rx8025_lock);

	return 0;

errout_unlock:
	up(&rx8025_lock);
	return err;
}

static int rx8025_get_rtctime(struct rtc_time *dt)
{
	u8 command = RX8025_REG_CTRL1 << 4 | 0x08;
	u8 result[9] = { 0, };
	int i, err;

	struct i2c_msg msg[] = {
		{
			.len	= 1,
			.buf	= &command,
		}, {
			.flags	= I2C_M_RD,
			.len	= ARRAY_SIZE(result),
			.buf	= result,
		}
	};

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

	if (!rx8025_rtcclient) {
		err = -EIO;
		goto errout_unlock;
	}

	if (!dt) {
		dev_err(&rx8025_rtcclient->dev,
			"rx8025_get_rtctime: passed in dt == NULL\n");
		err = -EINVAL;
		goto errout_unlock;
	}

	for (i = 0; i < ARRAY_SIZE(msg); ++i)
		msg[i].addr = rx8025_rtcclient->addr;

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

	up(&rx8025_lock);

	dev_dbg(&rx8025_rtcclient->dev,
			"rx8025_get_rtctime: read 0x%02x 0x%02x 0x%02x 0x%02x"
			" 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x\n", result[0],
			result[1], result[2], result[3], result[4], result[5],
			result[6], result[7], result[8]);

	dt->tm_sec = BCD2BIN(result[2 + RX8025_REG_SEC]);
	dt->tm_min = BCD2BIN(result[2 + RX8025_REG_MIN]);
	if (result[0] | RX8025_BIT_CTRL1_1224)
		dt->tm_hour = BCD2BIN(result[2 + RX8025_REG_HOUR]);
	else
		dt->tm_hour = BCD2BIN(result[2 + RX8025_REG_HOUR] & 0x1f) % 12
			+ (result[2 + RX8025_REG_HOUR] & 0x20 ? 12 : 0);

	dt->tm_wday = BCD2BIN(result[2 + RX8025_REG_WDAY]);
	dt->tm_mday = BCD2BIN(result[2 + RX8025_REG_MDAY]);
	dt->tm_mon = BCD2BIN(result[2 + RX8025_REG_MONTH]) - 1;
	dt->tm_year = BCD2BIN(result[2 + RX8025_REG_YEAR]);

	if (dt->tm_year < 70)
		dt->tm_year += 100;

	dev_dbg(&rx8025_rtcclient->dev,
			"rx8025_get_rtctime: "
			"result: %ds %dm %dh %dwd %dmd %dm %dy\n",
			dt->tm_sec, dt->tm_min, dt->tm_hour, dt->tm_wday,
			dt->tm_mday, dt->tm_mon, dt->tm_year);

	return 0;

errout_unlock:
	up(&rx8025_lock);
	return err;
}

static int rx8025_set_rtctime(struct rtc_time *dt)
{
	u8 command[8] = { RX8025_REG_SEC << 4, };
	int err;
	s32 ctrl1;

	struct i2c_msg msg = {
		.len    = 8,
		.buf    = command,
	};

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

	if (!rx8025_rtcclient) {
		err = -EIO;
		goto errout_unlock;
	}

	if (!dt) {
		dev_err(&rx8025_rtcclient->dev,
			"rx8025_set_rtctime: passed in dt == NULL\n");
		err = -EINVAL;
		goto errout_unlock;
	}

	if (dt->tm_sec < 0 || dt->tm_sec >= 60) {
		dev_err(&rx8025_rtcclient->dev,
			"rx8025_set_rtctime: seconds out of range: %d\n",
			dt->tm_sec);
		err = -EINVAL;
		goto errout_unlock;
	}

	if (dt->tm_min < 0 || dt->tm_min >= 60) {
		dev_err(&rx8025_rtcclient->dev,
			"rx8025_set_rtctime: minutes out of range: %d\n",
			dt->tm_min);
		err = -EINVAL;
		goto errout_unlock;
	}

	if (dt->tm_hour < 0 || dt->tm_hour >= 24) {
		dev_err(&rx8025_rtcclient->dev,
			"rx8025_set_rtctime: hours out of range: %d\n",
			dt->tm_hour);
		err = -EINVAL;
		goto errout_unlock;
	}

	if (dt->tm_wday < 0 || dt->tm_wday >= 7) {
		dev_err(&rx8025_rtcclient->dev,
			"rx8025_set_rtctime: hours out of range: %d\n",
			dt->tm_wday);
		err = -EINVAL;
		goto errout_unlock;
	}

	if (dt->tm_mon < 0 || dt->tm_mon >= 12) {
		dev_err(&rx8025_rtcclient->dev,
			"rx8025_set_rtctime: month out of range: %d\n",
			dt->tm_mon);
		err = -EINVAL;
		goto errout_unlock;
	}

	if (dt->tm_year < 70 || dt->tm_year >= 170) {
		dev_err(&rx8025_rtcclient->dev,
			"rx8025_set_rtctime: year out of range: %d\n",
			dt->tm_year);
		err = -EINVAL;
		goto errout_unlock;
	}

	if (dt->tm_mday > 31 ||
			((dt->tm_mon == 3 || dt->tm_mon == 5 ||
			  dt->tm_mon == 8 || dt->tm_mon == 10)
			 && dt->tm_mday > 30) ||
			(dt->tm_mon == 1 && dt->tm_mday > 28 +
			 (dt->tm_year & 3 ? 0 : 1))) {
		dev_err(&rx8025_rtcclient->dev,
			"rx8025_set_rtctime: day out of range (with month=%d, "
			"year=%d): %d\n", dt->tm_mon, dt->tm_year, dt->tm_mon);
		err = -EINVAL;
		goto errout_unlock;
	}

	if ((ctrl1 = i2c_smbus_read_byte_data(rx8025_rtcclient,
					RX8025_REG_CTRL1 << 4)) < 0) {
		dev_err(&rx8025_rtcclient->dev,
				"rx8025_set_rtctime: failed to read out "
				"RX8025_REG_CTRL1\n");
		err = -EINVAL;
		goto errout_unlock;
	}

	dev_dbg(&rx8025_rtcclient->dev,
			"rx8025_set_rtctime: ctrl1=0x%x\n", ctrl1);
	/*
	 * Here the read-only bits are written as "0".  I'm not sure if that
	 * is sound.
	 */
	command[1 + RX8025_REG_SEC] = BIN2BCD(dt->tm_sec);
	command[1 + RX8025_REG_MIN] = BIN2BCD(dt->tm_min);
	if (ctrl1 & RX8025_BIT_CTRL1_1224)
		command[1 + RX8025_REG_HOUR] = BIN2BCD(dt->tm_hour);
	else
		command[1 + RX8025_REG_HOUR] = (dt->tm_hour >= 12 ? 1 << 5 : 0) |
			BIN2BCD((dt->tm_hour + 11) % 12 + 1);

	command[1 + RX8025_REG_WDAY] = BIN2BCD(dt->tm_wday);
	command[1 + RX8025_REG_MDAY] = BIN2BCD(dt->tm_mday);
	command[1 + RX8025_REG_MONTH] = BIN2BCD(dt->tm_mon + 1);
	command[1 + RX8025_REG_YEAR] = BIN2BCD(dt->tm_year % 100);

	msg.addr = rx8025_rtcclient->addr;

	dev_dbg(&rx8025_rtcclient->dev,
			"rx8025_set_rtctime: send 0x%02x 0x%02x 0x%02x 0x%02x"
			" 0x%02x 0x%02x 0x%02x 0x%02x\n", command[0],
			command[1], command[2], command[3], command[4],
			command[5], command[6], command[7]);

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

	up(&rx8025_lock);

	return 0;

errout_unlock:
	up(&rx8025_lock);
	return err;
}

// a by xjr 2007.1.26 b
static int rx8025_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
		     unsigned long arg)
{
	struct rtc_time tm;

⌨️ 快捷键说明

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