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

📄 x1205.c

📁 linux-2.6.15.6
💻 C
📖 第 1 页 / 共 2 页
字号:
	s8 atr;	static unsigned char atr_addr[2] = { 0, X1205_REG_ATR };	struct i2c_msg msgs[] = {		{ client->addr, 0, 2, atr_addr },	/* setup read ptr */		{ client->addr, I2C_M_RD, 1, &atr }, 	/* read atr */	};	/* read atr register */	if ((i2c_transfer(client->adapter, &msgs[0], 2)) != 2) {		dev_err(&client->dev, "%s: read error\n", __FUNCTION__);		return -EIO;	}	dev_dbg(&client->dev, "%s: raw atr=%x\n", __FUNCTION__, atr);	/* atr is a two's complement value on 6 bits,	 * perform sign extension. The formula is	 * Catr = (atr * 0.25pF) + 11.00pF.	 */	if (atr & 0x20)		atr |= 0xC0;	dev_dbg(&client->dev, "%s: raw atr=%x (%d)\n", __FUNCTION__, atr, atr);	*trim = (atr * 250) + 11000;	dev_dbg(&client->dev, "%s: real=%d\n", __FUNCTION__, *trim);	return 0;}static int x1205_hctosys(struct i2c_client *client){	int err;	struct rtc_time tm;	struct timespec tv;	err = x1205_command(client, X1205_CMD_GETDATETIME, &tm);	if (err) {		dev_err(&client->dev,			"Unable to set the system clock\n");		return err;	}	/* IMPORTANT: the RTC only stores whole seconds. It is arbitrary	 * whether it stores the most close value or the value with partial	 * seconds truncated. However, it is important that we use it to store	 * the truncated value. This is because otherwise it is necessary,	 * in an rtc sync function, to read both xtime.tv_sec and	 * xtime.tv_nsec. On some processors (i.e. ARM), an atomic read	 * of >32bits is not possible. So storing the most close value would	 * slow down the sync API. So here we have the truncated value and	 * the best guess is to add 0.5s.	 */	tv.tv_nsec = NSEC_PER_SEC >> 1;	/* WARNING: this is not the C library 'mktime' call, it is a built in	 * inline function from include/linux/time.h.  It expects (requires)	 * the month to be in the range 1-12	 */	tv.tv_sec  = mktime(tm.tm_year + 1900, tm.tm_mon + 1,				tm.tm_mday, tm.tm_hour,				tm.tm_min, tm.tm_sec);	do_settimeofday(&tv);	dev_info(&client->dev,		"setting the system clock to %d-%d-%d %d:%d:%d\n",		tm.tm_year + 1900, tm.tm_mon + 1,		tm.tm_mday, tm.tm_hour, tm.tm_min,		tm.tm_sec);	return 0;}struct x1205_limit{	unsigned char reg;	unsigned char mask;	unsigned char min;	unsigned char max;};static int x1205_validate_client(struct i2c_client *client){	int i, xfer;	/* Probe array. We will read the register at the specified	 * address and check if the given bits are zero.	 */	static const unsigned char probe_zero_pattern[] = {		/* register, mask */		X1205_REG_SR,	0x18,		X1205_REG_DTR,	0xF8,		X1205_REG_ATR,	0xC0,		X1205_REG_INT,	0x18,		X1205_REG_0,	0xFF,	};	static const struct x1205_limit probe_limits_pattern[] = {		/* register, mask, min, max */		{ X1205_REG_Y2K,	0xFF,	19,	20	},		{ X1205_REG_DW,		0xFF,	0,	6	},		{ X1205_REG_YR,		0xFF,	0,	99	},		{ X1205_REG_MO,		0xFF,	0,	12	},		{ X1205_REG_DT,		0xFF,	0,	31	},		{ X1205_REG_HR,		0x7F,	0,	23	},		{ X1205_REG_MN,		0xFF,	0,	59	},		{ X1205_REG_SC,		0xFF,	0,	59	},		{ X1205_REG_Y2K1,	0xFF,	19,	20	},		{ X1205_REG_Y2K0,	0xFF,	19,	20	},	};	/* check that registers have bits a 0 where expected */	for (i = 0; i < ARRAY_SIZE(probe_zero_pattern); i += 2) {		unsigned char buf;		unsigned char addr[2] = { 0, probe_zero_pattern[i] };		struct i2c_msg msgs[2] = {			{ client->addr, 0, 2, addr },			{ client->addr, I2C_M_RD, 1, &buf },		};		xfer = i2c_transfer(client->adapter, msgs, 2);		if (xfer != 2) {			dev_err(&client->adapter->dev,				"%s: could not read register %x\n",				__FUNCTION__, addr[1]);			return -EIO;		}		if ((buf & probe_zero_pattern[i+1]) != 0) {			dev_err(&client->adapter->dev,				"%s: register=%02x, zero pattern=%d, value=%x\n",				__FUNCTION__, addr[1], i, buf);			return -ENODEV;		}	}	/* check limits (only registers with bcd values) */	for (i = 0; i < ARRAY_SIZE(probe_limits_pattern); i++) {		unsigned char reg, value;		unsigned char addr[2] = { 0, probe_limits_pattern[i].reg };		struct i2c_msg msgs[2] = {			{ client->addr, 0, 2, addr },			{ client->addr, I2C_M_RD, 1, &reg },		};		xfer = i2c_transfer(client->adapter, msgs, 2);		if (xfer != 2) {			dev_err(&client->adapter->dev,				"%s: could not read register %x\n",				__FUNCTION__, addr[1]);			return -EIO;		}		value = BCD2BIN(reg & probe_limits_pattern[i].mask);		if (value > probe_limits_pattern[i].max ||			value < probe_limits_pattern[i].min) {			dev_dbg(&client->adapter->dev,				"%s: register=%x, lim pattern=%d, value=%d\n",				__FUNCTION__, addr[1], i, value);			return -ENODEV;		}	}	return 0;}static int x1205_attach(struct i2c_adapter *adapter){	dev_dbg(&adapter->dev, "%s\n", __FUNCTION__);	return i2c_probe(adapter, &addr_data, x1205_probe);}int x1205_direct_attach(int adapter_id,	struct i2c_client_address_data *address_data){	int err;	struct i2c_adapter *adapter = i2c_get_adapter(adapter_id);	if (adapter) {		err = i2c_probe(adapter,			address_data, x1205_probe);		i2c_put_adapter(adapter);		return err;	}	return -ENODEV;}static int x1205_probe(struct i2c_adapter *adapter, int address, int kind){	struct i2c_client *client;	struct x1205_data *data;	int err = 0;	dev_dbg(&adapter->dev, "%s\n", __FUNCTION__);	if (!i2c_check_functionality(adapter, I2C_FUNC_I2C)) {		err = -ENODEV;		goto exit;	}	if (!(data = kzalloc(sizeof(struct x1205_data), GFP_KERNEL))) {		err = -ENOMEM;		goto exit;	}	/* Initialize our structures */	data->epoch = 2000;	client = &data->client;	client->addr = address;	client->driver = &x1205_driver;	client->adapter	= adapter;	strlcpy(client->name, "x1205", I2C_NAME_SIZE);	i2c_set_clientdata(client, data);	/* Verify the chip is really an X1205 */	if (kind < 0) {		if (x1205_validate_client(client) < 0) {			err = -ENODEV;			goto exit_kfree;		}	}	/* Inform the i2c layer */	if ((err = i2c_attach_client(client)))		goto exit_kfree;	list_add(&data->list, &x1205_clients);	dev_info(&client->dev, "chip found, driver version " DRV_VERSION "\n");	/* If requested, set the system time */	if (hctosys)		x1205_hctosys(client);	return 0;exit_kfree:	kfree(data);exit:	return err;}static int x1205_detach(struct i2c_client *client){	int err;	struct x1205_data *data = i2c_get_clientdata(client);	dev_dbg(&client->dev, "%s\n", __FUNCTION__);	if ((err = i2c_detach_client(client)))		return err;	list_del(&data->list);	kfree(data);	return 0;}static int x1205_command(struct i2c_client *client, unsigned int cmd,	void *param){	if (param == NULL)		return -EINVAL;	if (!capable(CAP_SYS_TIME))		return -EACCES;	dev_dbg(&client->dev, "%s: cmd=%d\n", __FUNCTION__, cmd);	switch (cmd) {	case X1205_CMD_GETDATETIME:		return x1205_get_datetime(client, param, X1205_CCR_BASE);	case X1205_CMD_SETTIME:		return x1205_set_datetime(client, param, 0,				X1205_CCR_BASE);	case X1205_CMD_SETDATETIME:		return x1205_set_datetime(client, param, 1,				X1205_CCR_BASE);	case X1205_CMD_GETALARM:		return x1205_get_datetime(client, param, X1205_ALM0_BASE);	case X1205_CMD_SETALARM:		return x1205_set_datetime(client, param, 1,				X1205_ALM0_BASE);	case X1205_CMD_GETDTRIM:		return x1205_get_dtrim(client, param);	case X1205_CMD_GETATRIM:		return x1205_get_atrim(client, param);	default:		return -EINVAL;	}}static int __init x1205_init(void){	return i2c_add_driver(&x1205_driver);}static void __exit x1205_exit(void){	i2c_del_driver(&x1205_driver);}MODULE_AUTHOR(	"Karen Spearel <kas11@tampabay.rr.com>, "	"Alessandro Zummo <a.zummo@towertech.it>");MODULE_DESCRIPTION("Xicor X1205 RTC driver");MODULE_LICENSE("GPL");MODULE_VERSION(DRV_VERSION);EXPORT_SYMBOL_GPL(x1205_do_command);EXPORT_SYMBOL_GPL(x1205_direct_attach);module_init(x1205_init);module_exit(x1205_exit);

⌨️ 快捷键说明

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