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

📄 ds1337.c

📁 i2c-core.c - a device driver for the iic-bus interface
💻 C
字号:
/* *  linux/drivers/i2c/chips/ds1337.c * *  Copyright (C) 2005 James Chapman <jchapman@katalix.com> * *	based on linux/drivers/acorn/char/pcf8583.c *  Copyright (C) 2000 Russell King * * 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 Dallas Semiconductor DS1337 and DS1339 real time clock chip */#include <linux/module.h>#include <linux/init.h>#include <linux/slab.h>#include <linux/i2c.h>#include <linux/string.h>#include <linux/rtc.h>		/* get the user-level API */#include <linux/bcd.h>#include <linux/list.h>/* Device registers */#define DS1337_REG_HOUR		2#define DS1337_REG_DAY		3#define DS1337_REG_DATE		4#define DS1337_REG_MONTH	5#define DS1337_REG_CONTROL	14#define DS1337_REG_STATUS	15/* FIXME - how do we export these interface constants? */#define DS1337_GET_DATE		0#define DS1337_SET_DATE		1/* * Functions declaration */static unsigned short normal_i2c[] = { 0x68, I2C_CLIENT_END };I2C_CLIENT_INSMOD_1(ds1337);static int ds1337_attach_adapter(struct i2c_adapter *adapter);static int ds1337_detect(struct i2c_adapter *adapter, int address, int kind);static void ds1337_init_client(struct i2c_client *client);static int ds1337_detach_client(struct i2c_client *client);static int ds1337_command(struct i2c_client *client, unsigned int cmd,			  void *arg);/* * Driver data (common to all clients) */static struct i2c_driver ds1337_driver = {	.driver = {		.name	= "ds1337",	},	.attach_adapter	= ds1337_attach_adapter,	.detach_client	= ds1337_detach_client,	.command	= ds1337_command,};/* * Client data (each client gets its own) */struct ds1337_data {	struct i2c_client client;	struct list_head list;};/* * Internal variables */static LIST_HEAD(ds1337_clients);static inline int ds1337_read(struct i2c_client *client, u8 reg, u8 *value){	s32 tmp = i2c_smbus_read_byte_data(client, reg);	if (tmp < 0)		return -EIO;	*value = tmp;	return 0;}/* * Chip access functions */static int ds1337_get_datetime(struct i2c_client *client, struct rtc_time *dt){	int result;	u8 buf[7];	u8 val;	struct i2c_msg msg[2];	u8 offs = 0;	if (!dt) {		dev_dbg(&client->dev, "%s: EINVAL: dt=NULL\n", __FUNCTION__);		return -EINVAL;	}	msg[0].addr = client->addr;	msg[0].flags = 0;	msg[0].len = 1;	msg[0].buf = &offs;	msg[1].addr = client->addr;	msg[1].flags = I2C_M_RD;	msg[1].len = sizeof(buf);	msg[1].buf = &buf[0];	result = i2c_transfer(client->adapter, msg, 2);	dev_dbg(&client->dev, "%s: [%d] %02x %02x %02x %02x %02x %02x %02x\n",		__FUNCTION__, result, buf[0], buf[1], buf[2], buf[3],		buf[4], buf[5], buf[6]);	if (result == 2) {		dt->tm_sec = BCD2BIN(buf[0]);		dt->tm_min = BCD2BIN(buf[1]);		val = buf[2] & 0x3f;		dt->tm_hour = BCD2BIN(val);		dt->tm_wday = BCD2BIN(buf[3]) - 1;		dt->tm_mday = BCD2BIN(buf[4]);		val = buf[5] & 0x7f;		dt->tm_mon = BCD2BIN(val) - 1;		dt->tm_year = BCD2BIN(buf[6]);		if (buf[5] & 0x80)			dt->tm_year += 100;		dev_dbg(&client->dev, "%s: secs=%d, mins=%d, "			"hours=%d, mday=%d, mon=%d, year=%d, wday=%d\n",			__FUNCTION__, dt->tm_sec, dt->tm_min,			dt->tm_hour, dt->tm_mday,			dt->tm_mon, dt->tm_year, dt->tm_wday);		return 0;	}	dev_err(&client->dev, "error reading data! %d\n", result);	return -EIO;}static int ds1337_set_datetime(struct i2c_client *client, struct rtc_time *dt){	int result;	u8 buf[8];	u8 val;	struct i2c_msg msg[1];	if (!dt) {		dev_dbg(&client->dev, "%s: EINVAL: dt=NULL\n", __FUNCTION__);		return -EINVAL;	}	dev_dbg(&client->dev, "%s: secs=%d, mins=%d, hours=%d, "		"mday=%d, mon=%d, year=%d, wday=%d\n", __FUNCTION__,		dt->tm_sec, dt->tm_min, dt->tm_hour,		dt->tm_mday, dt->tm_mon, dt->tm_year, dt->tm_wday);	buf[0] = 0;		/* reg offset */	buf[1] = BIN2BCD(dt->tm_sec);	buf[2] = BIN2BCD(dt->tm_min);	buf[3] = BIN2BCD(dt->tm_hour);	buf[4] = BIN2BCD(dt->tm_wday + 1);	buf[5] = BIN2BCD(dt->tm_mday);	buf[6] = BIN2BCD(dt->tm_mon + 1);	val = dt->tm_year;	if (val >= 100) {		val -= 100;		buf[6] |= (1 << 7);	}	buf[7] = BIN2BCD(val);	msg[0].addr = client->addr;	msg[0].flags = 0;	msg[0].len = sizeof(buf);	msg[0].buf = &buf[0];	result = i2c_transfer(client->adapter, msg, 1);	if (result == 1)		return 0;	dev_err(&client->dev, "error writing data! %d\n", result);	return -EIO;}static int ds1337_command(struct i2c_client *client, unsigned int cmd,			  void *arg){	dev_dbg(&client->dev, "%s: cmd=%d\n", __FUNCTION__, cmd);	switch (cmd) {	case DS1337_GET_DATE:		return ds1337_get_datetime(client, arg);	case DS1337_SET_DATE:		return ds1337_set_datetime(client, arg);	default:		return -EINVAL;	}}/* * Public API for access to specific device. Useful for low-level * RTC access from kernel code. */int ds1337_do_command(int bus, int cmd, void *arg){	struct list_head *walk;	struct list_head *tmp;	struct ds1337_data *data;	list_for_each_safe(walk, tmp, &ds1337_clients) {		data = list_entry(walk, struct ds1337_data, list);		if (data->client.adapter->nr == bus)			return ds1337_command(&data->client, cmd, arg);	}	return -ENODEV;}static int ds1337_attach_adapter(struct i2c_adapter *adapter){	return i2c_probe(adapter, &addr_data, ds1337_detect);}/* * The following function does more than just detection. If detection * succeeds, it also registers the new chip. */static int ds1337_detect(struct i2c_adapter *adapter, int address, int kind){	struct i2c_client *new_client;	struct ds1337_data *data;	int err = 0;	const char *name = "";	if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA |				     I2C_FUNC_I2C))		goto exit;	if (!(data = kzalloc(sizeof(struct ds1337_data), GFP_KERNEL))) {		err = -ENOMEM;		goto exit;	}	INIT_LIST_HEAD(&data->list);	/* The common I2C client data is placed right before the	 * DS1337-specific data. 	 */	new_client = &data->client;	i2c_set_clientdata(new_client, data);	new_client->addr = address;	new_client->adapter = adapter;	new_client->driver = &ds1337_driver;	new_client->flags = 0;	/*	 * Now we do the remaining detection. A negative kind means that	 * the driver was loaded with no force parameter (default), so we	 * must both detect and identify the chip. A zero kind means that	 * the driver was loaded with the force parameter, the detection	 * step shall be skipped. A positive kind means that the driver	 * was loaded with the force parameter and a given kind of chip is	 * requested, so both the detection and the identification steps	 * are skipped.	 *	 * For detection, we read registers that are most likely to cause	 * detection failure, i.e. those that have more bits with fixed	 * or reserved values.	 */	/* Default to an DS1337 if forced */	if (kind == 0)		kind = ds1337;	if (kind < 0) {		/* detection and identification */		u8 data;		/* Check that status register bits 6-2 are zero */		if ((ds1337_read(new_client, DS1337_REG_STATUS, &data) < 0) ||		    (data & 0x7c))			goto exit_free;		/* Check for a valid day register value */		if ((ds1337_read(new_client, DS1337_REG_DAY, &data) < 0) ||		    (data == 0) || (data & 0xf8))			goto exit_free;		/* Check for a valid date register value */		if ((ds1337_read(new_client, DS1337_REG_DATE, &data) < 0) ||		    (data == 0) || (data & 0xc0) || ((data & 0x0f) > 9) ||		    (data >= 0x32))			goto exit_free;		/* Check for a valid month register value */		if ((ds1337_read(new_client, DS1337_REG_MONTH, &data) < 0) ||		    (data == 0) || (data & 0x60) || ((data & 0x0f) > 9) ||		    ((data >= 0x13) && (data <= 0x19)))			goto exit_free;		/* Check that control register bits 6-5 are zero */		if ((ds1337_read(new_client, DS1337_REG_CONTROL, &data) < 0) ||		    (data & 0x60))			goto exit_free;		kind = ds1337;	}	if (kind == ds1337)		name = "ds1337";	/* We can fill in the remaining client fields */	strlcpy(new_client->name, name, I2C_NAME_SIZE);	/* Tell the I2C layer a new client has arrived */	if ((err = i2c_attach_client(new_client)))		goto exit_free;	/* Initialize the DS1337 chip */	ds1337_init_client(new_client);	/* Add client to local list */	list_add(&data->list, &ds1337_clients);	return 0;exit_free:	kfree(data);exit:	return err;}static void ds1337_init_client(struct i2c_client *client){	u8 status, control;	/* On some boards, the RTC isn't configured by boot firmware.	 * Handle that case by starting/configuring the RTC now.	 */	status = i2c_smbus_read_byte_data(client, DS1337_REG_STATUS);	control = i2c_smbus_read_byte_data(client, DS1337_REG_CONTROL);	if ((status & 0x80) || (control & 0x80)) {		/* RTC not running */		u8 buf[16];		struct i2c_msg msg[1];		dev_dbg(&client->dev, "%s: RTC not running!\n", __FUNCTION__);		/* Initialize all, including STATUS and CONTROL to zero */		memset(buf, 0, sizeof(buf));		msg[0].addr = client->addr;		msg[0].flags = 0;		msg[0].len = sizeof(buf);		msg[0].buf = &buf[0];		i2c_transfer(client->adapter, msg, 1);	} else {		/* Running: ensure that device is set in 24-hour mode */		s32 val;		val = i2c_smbus_read_byte_data(client, DS1337_REG_HOUR);		if ((val >= 0) && (val & (1 << 6)))			i2c_smbus_write_byte_data(client, DS1337_REG_HOUR,						  val & 0x3f);	}}static int ds1337_detach_client(struct i2c_client *client){	int err;	struct ds1337_data *data = i2c_get_clientdata(client);	if ((err = i2c_detach_client(client)))		return err;	list_del(&data->list);	kfree(data);	return 0;}static int __init ds1337_init(void){	return i2c_add_driver(&ds1337_driver);}static void __exit ds1337_exit(void){	i2c_del_driver(&ds1337_driver);}MODULE_AUTHOR("James Chapman <jchapman@katalix.com>");MODULE_DESCRIPTION("DS1337 RTC driver");MODULE_LICENSE("GPL");EXPORT_SYMBOL_GPL(ds1337_do_command);module_init(ds1337_init);module_exit(ds1337_exit);

⌨️ 快捷键说明

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