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

📄 adm1031.c

📁 《linux驱动程序设计从入门到精通》一书中所有的程序代码含驱动和相应的应用程序
💻 C
📖 第 1 页 / 共 2 页
字号:
	value = trust_fan_readings(data, nr) ? FAN_FROM_REG(data->fan[nr],				 FAN_DIV_FROM_REG(data->fan_div[nr])) : 0;	return sprintf(buf, "%d\n", value);}static ssize_t show_fan_div(struct device *dev, char *buf, int nr){	struct adm1031_data *data = adm1031_update_device(dev);	return sprintf(buf, "%d\n", FAN_DIV_FROM_REG(data->fan_div[nr]));}static ssize_t show_fan_min(struct device *dev, char *buf, int nr){	struct adm1031_data *data = adm1031_update_device(dev);	return sprintf(buf, "%d\n",		       FAN_FROM_REG(data->fan_min[nr],				    FAN_DIV_FROM_REG(data->fan_div[nr])));}static ssize_tset_fan_min(struct device *dev, const char *buf, size_t count, int nr){	struct i2c_client *client = to_i2c_client(dev);	struct adm1031_data *data = i2c_get_clientdata(client);	int val;	down(&data->update_lock);	val = simple_strtol(buf, NULL, 10);	if (val) {		data->fan_min[nr] = 			FAN_TO_REG(val, FAN_DIV_FROM_REG(data->fan_div[nr]));	} else {		data->fan_min[nr] = 0xff;	}	adm1031_write_value(client, ADM1031_REG_FAN_MIN(nr), data->fan_min[nr]);	up(&data->update_lock);	return count;}static ssize_tset_fan_div(struct device *dev, const char *buf, size_t count, int nr){	struct i2c_client *client = to_i2c_client(dev);	struct adm1031_data *data = i2c_get_clientdata(client);	int val;	u8 tmp;	int old_div = FAN_DIV_FROM_REG(data->fan_div[nr]);	int new_min;	val = simple_strtol(buf, NULL, 10);	tmp = val == 8 ? 0xc0 :	      val == 4 ? 0x80 :	      val == 2 ? 0x40 :		      val == 1 ? 0x00 :  	      0xff;	if (tmp == 0xff)		return -EINVAL;	down(&data->update_lock);	data->fan_div[nr] = (tmp & 0xC0) | (0x3f & data->fan_div[nr]);	new_min = data->fan_min[nr] * old_div / 		FAN_DIV_FROM_REG(data->fan_div[nr]);	data->fan_min[nr] = new_min > 0xff ? 0xff : new_min;	data->fan[nr] = data->fan[nr] * old_div / 		FAN_DIV_FROM_REG(data->fan_div[nr]);	adm1031_write_value(client, ADM1031_REG_FAN_DIV(nr), 			    data->fan_div[nr]);	adm1031_write_value(client, ADM1031_REG_FAN_MIN(nr), 			    data->fan_min[nr]);	up(&data->update_lock);	return count;}#define fan_offset(offset)						\static ssize_t show_fan_##offset (struct device *dev, char *buf)	\{									\	return show_fan(dev, buf, 0x##offset - 1);			\}									\static ssize_t show_fan_##offset##_min (struct device *dev, char *buf)	\{									\	return show_fan_min(dev, buf, 0x##offset - 1);			\}									\static ssize_t show_fan_##offset##_div (struct device *dev, char *buf)	\{									\	return show_fan_div(dev, buf, 0x##offset - 1);			\}									\static ssize_t set_fan_##offset##_min (struct device *dev,		\	const char *buf, size_t count)					\{									\	return set_fan_min(dev, buf, count, 0x##offset - 1);		\}									\static ssize_t set_fan_##offset##_div (struct device *dev,		\	const char *buf, size_t count)					\{									\	return set_fan_div(dev, buf, count, 0x##offset - 1);		\}									\static DEVICE_ATTR(fan##offset##_input, S_IRUGO, show_fan_##offset,	\		   NULL);						\static DEVICE_ATTR(fan##offset##_min, S_IRUGO | S_IWUSR,		\		   show_fan_##offset##_min, set_fan_##offset##_min);	\static DEVICE_ATTR(fan##offset##_div, S_IRUGO | S_IWUSR,		\		   show_fan_##offset##_div, set_fan_##offset##_div);	\static DEVICE_ATTR(auto_fan##offset##_min_pwm, S_IRUGO | S_IWUSR,	\		   show_pwm_##offset, set_pwm_##offset)fan_offset(1);fan_offset(2);/* Temps */static ssize_t show_temp(struct device *dev, char *buf, int nr){	struct adm1031_data *data = adm1031_update_device(dev);	int ext;	ext = nr == 0 ?	    ((data->ext_temp[nr] >> 6) & 0x3) * 2 :	    (((data->ext_temp[nr] >> ((nr - 1) * 3)) & 7));	return sprintf(buf, "%d\n", TEMP_FROM_REG_EXT(data->temp[nr], ext));}static ssize_t show_temp_min(struct device *dev, char *buf, int nr){	struct adm1031_data *data = adm1031_update_device(dev);	return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp_min[nr]));}static ssize_t show_temp_max(struct device *dev, char *buf, int nr){	struct adm1031_data *data = adm1031_update_device(dev);	return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp_max[nr]));}static ssize_t show_temp_crit(struct device *dev, char *buf, int nr){	struct adm1031_data *data = adm1031_update_device(dev);	return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp_crit[nr]));}static ssize_tset_temp_min(struct device *dev, const char *buf, size_t count, int nr){	struct i2c_client *client = to_i2c_client(dev);	struct adm1031_data *data = i2c_get_clientdata(client);	int val;	val = simple_strtol(buf, NULL, 10);	val = SENSORS_LIMIT(val, -55000, nr == 0 ? 127750 : 127875);	down(&data->update_lock);	data->temp_min[nr] = TEMP_TO_REG(val);	adm1031_write_value(client, ADM1031_REG_TEMP_MIN(nr),			    data->temp_min[nr]);	up(&data->update_lock);	return count;}static ssize_tset_temp_max(struct device *dev, const char *buf, size_t count, int nr){	struct i2c_client *client = to_i2c_client(dev);	struct adm1031_data *data = i2c_get_clientdata(client);	int val;	val = simple_strtol(buf, NULL, 10);	val = SENSORS_LIMIT(val, -55000, nr == 0 ? 127750 : 127875);	down(&data->update_lock);	data->temp_max[nr] = TEMP_TO_REG(val);	adm1031_write_value(client, ADM1031_REG_TEMP_MAX(nr),			    data->temp_max[nr]);	up(&data->update_lock);	return count;}static ssize_tset_temp_crit(struct device *dev, const char *buf, size_t count, int nr){	struct i2c_client *client = to_i2c_client(dev);	struct adm1031_data *data = i2c_get_clientdata(client);	int val;	val = simple_strtol(buf, NULL, 10);	val = SENSORS_LIMIT(val, -55000, nr == 0 ? 127750 : 127875);	down(&data->update_lock);	data->temp_crit[nr] = TEMP_TO_REG(val);	adm1031_write_value(client, ADM1031_REG_TEMP_CRIT(nr),			    data->temp_crit[nr]);	up(&data->update_lock);	return count;}#define temp_reg(offset)							\static ssize_t show_temp_##offset (struct device *dev, char *buf)		\{										\	return show_temp(dev, buf, 0x##offset - 1);				\}										\static ssize_t show_temp_##offset##_min (struct device *dev, char *buf)		\{										\	return show_temp_min(dev, buf, 0x##offset - 1);				\}										\static ssize_t show_temp_##offset##_max (struct device *dev, char *buf)		\{										\	return show_temp_max(dev, buf, 0x##offset - 1);				\}										\static ssize_t show_temp_##offset##_crit (struct device *dev, char *buf)	\{										\	return show_temp_crit(dev, buf, 0x##offset - 1);			\}										\static ssize_t set_temp_##offset##_min (struct device *dev,			\					const char *buf, size_t count)		\{										\	return set_temp_min(dev, buf, count, 0x##offset - 1);			\}										\static ssize_t set_temp_##offset##_max (struct device *dev,			\					const char *buf, size_t count)		\{										\	return set_temp_max(dev, buf, count, 0x##offset - 1);			\}										\static ssize_t set_temp_##offset##_crit (struct device *dev,			\					 const char *buf, size_t count)		\{										\	return set_temp_crit(dev, buf, count, 0x##offset - 1);			\}										\static DEVICE_ATTR(temp##offset##_input, S_IRUGO, show_temp_##offset,		\		   NULL);							\static DEVICE_ATTR(temp##offset##_min, S_IRUGO | S_IWUSR,			\		   show_temp_##offset##_min, set_temp_##offset##_min);		\static DEVICE_ATTR(temp##offset##_max, S_IRUGO | S_IWUSR,			\		   show_temp_##offset##_max, set_temp_##offset##_max);		\static DEVICE_ATTR(temp##offset##_crit, S_IRUGO | S_IWUSR,			\		   show_temp_##offset##_crit, set_temp_##offset##_crit)temp_reg(1);temp_reg(2);temp_reg(3);/* Alarms */static ssize_t show_alarms(struct device *dev, char *buf){	struct adm1031_data *data = adm1031_update_device(dev);	return sprintf(buf, "%d\n", data->alarm);}static DEVICE_ATTR(alarms, S_IRUGO, show_alarms, NULL);static int adm1031_attach_adapter(struct i2c_adapter *adapter){	if (!(adapter->class & I2C_CLASS_HWMON))		return 0;	return i2c_detect(adapter, &addr_data, adm1031_detect);}/* This function is called by i2c_detect */static int adm1031_detect(struct i2c_adapter *adapter, int address, int kind){	struct i2c_client *new_client;	struct adm1031_data *data;	int err = 0;	const char *name = "";	if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))		goto exit;	if (!(data = kmalloc(sizeof(struct adm1031_data), GFP_KERNEL))) {		err = -ENOMEM;		goto exit;	}	memset(data, 0, sizeof(struct adm1031_data));	new_client = &data->client;	i2c_set_clientdata(new_client, data);	new_client->addr = address;	new_client->adapter = adapter;	new_client->driver = &adm1031_driver;	new_client->flags = 0;	if (kind < 0) {		int id, co;		id = i2c_smbus_read_byte_data(new_client, 0x3d);		co = i2c_smbus_read_byte_data(new_client, 0x3e);		if (!((id == 0x31 || id == 0x30) && co == 0x41))			goto exit_free;		kind = (id == 0x30) ? adm1030 : adm1031;	}	if (kind <= 0)		kind = adm1031;	/* Given the detected chip type, set the chip name and the	 * auto fan control helper table. */	if (kind == adm1030) {		name = "adm1030";		data->chan_select_table = &auto_channel_select_table_adm1030;	} else if (kind == adm1031) {		name = "adm1031";		data->chan_select_table = &auto_channel_select_table_adm1031;	}	data->chip_type = kind;	strlcpy(new_client->name, name, I2C_NAME_SIZE);	new_client->id = adm1031_id++;	data->valid = 0;	init_MUTEX(&data->update_lock);	/* Tell the I2C layer a new client has arrived */	if ((err = i2c_attach_client(new_client)))		goto exit_free;	/* Initialize the ADM1031 chip */	adm1031_init_client(new_client);	/* Register sysfs hooks */	device_create_file(&new_client->dev, &dev_attr_fan1_input);	device_create_file(&new_client->dev, &dev_attr_fan1_div);	device_create_file(&new_client->dev, &dev_attr_fan1_min);	device_create_file(&new_client->dev, &dev_attr_fan1_pwm);	device_create_file(&new_client->dev, &dev_attr_auto_fan1_channel);	device_create_file(&new_client->dev, &dev_attr_temp1_input);	device_create_file(&new_client->dev, &dev_attr_temp1_min);	device_create_file(&new_client->dev, &dev_attr_temp1_max);	device_create_file(&new_client->dev, &dev_attr_temp1_crit);	device_create_file(&new_client->dev, &dev_attr_temp2_input);	device_create_file(&new_client->dev, &dev_attr_temp2_min);	device_create_file(&new_client->dev, &dev_attr_temp2_max);	device_create_file(&new_client->dev, &dev_attr_temp2_crit);	device_create_file(&new_client->dev, &dev_attr_auto_temp1_off);	device_create_file(&new_client->dev, &dev_attr_auto_temp1_min);	device_create_file(&new_client->dev, &dev_attr_auto_temp1_max);	device_create_file(&new_client->dev, &dev_attr_auto_temp2_off);	device_create_file(&new_client->dev, &dev_attr_auto_temp2_min);	device_create_file(&new_client->dev, &dev_attr_auto_temp2_max);	device_create_file(&new_client->dev, &dev_attr_auto_fan1_min_pwm);	device_create_file(&new_client->dev, &dev_attr_alarms);	if (kind == adm1031) {		device_create_file(&new_client->dev, &dev_attr_fan2_input);		device_create_file(&new_client->dev, &dev_attr_fan2_div);		device_create_file(&new_client->dev, &dev_attr_fan2_min);		device_create_file(&new_client->dev, &dev_attr_fan2_pwm);		device_create_file(&new_client->dev,				   &dev_attr_auto_fan2_channel);		device_create_file(&new_client->dev, &dev_attr_temp3_input);		device_create_file(&new_client->dev, &dev_attr_temp3_min);		device_create_file(&new_client->dev, &dev_attr_temp3_max);		device_create_file(&new_client->dev, &dev_attr_temp3_crit);		device_create_file(&new_client->dev, &dev_attr_auto_temp3_off);		device_create_file(&new_client->dev, &dev_attr_auto_temp3_min);		device_create_file(&new_client->dev, &dev_attr_auto_temp3_max);		device_create_file(&new_client->dev, &dev_attr_auto_fan2_min_pwm);	}	return 0;exit_free:	kfree(new_client);exit:	return err;}static int adm1031_detach_client(struct i2c_client *client){	int ret;	if ((ret = i2c_detach_client(client)) != 0) {		return ret;	}	kfree(client);	return 0;}static void adm1031_init_client(struct i2c_client *client){	unsigned int read_val;	unsigned int mask;	struct adm1031_data *data = i2c_get_clientdata(client);	mask = (ADM1031_CONF2_PWM1_ENABLE | ADM1031_CONF2_TACH1_ENABLE);	if (data->chip_type == adm1031) {		mask |= (ADM1031_CONF2_PWM2_ENABLE |			ADM1031_CONF2_TACH2_ENABLE);	} 	/* Initialize the ADM1031 chip (enables fan speed reading ) */	read_val = adm1031_read_value(client, ADM1031_REG_CONF2);	if ((read_val | mask) != read_val) {	    adm1031_write_value(client, ADM1031_REG_CONF2, read_val | mask);	}	read_val = adm1031_read_value(client, ADM1031_REG_CONF1);	if ((read_val | ADM1031_CONF1_MONITOR_ENABLE) != read_val) {	    adm1031_write_value(client, ADM1031_REG_CONF1, read_val |				ADM1031_CONF1_MONITOR_ENABLE);	}}static struct adm1031_data *adm1031_update_device(struct device *dev){	struct i2c_client *client = to_i2c_client(dev);	struct adm1031_data *data = i2c_get_clientdata(client);	int chan;	down(&data->update_lock);	if ((jiffies - data->last_updated > HZ + HZ / 2) ||	    (jiffies < data->last_updated) || !data->valid) {		dev_dbg(&client->dev, "Starting adm1031 update\n");		for (chan = 0;		     chan < ((data->chip_type == adm1031) ? 3 : 2); chan++) {			u8 oldh, newh;			oldh =			    adm1031_read_value(client, ADM1031_REG_TEMP(chan));			data->ext_temp[chan] =			    adm1031_read_value(client, ADM1031_REG_EXT_TEMP);			newh =			    adm1031_read_value(client, ADM1031_REG_TEMP(chan));			if (newh != oldh) {				data->ext_temp[chan] =				    adm1031_read_value(client,						       ADM1031_REG_EXT_TEMP);#ifdef DEBUG				oldh =				    adm1031_read_value(client,						       ADM1031_REG_TEMP(chan));				/* oldh is actually newer */				if (newh != oldh)					dev_warn(&client->dev,						 "Remote temperature may be "						 "wrong.\n");#endif			}			data->temp[chan] = newh;			data->temp_min[chan] =			    adm1031_read_value(client,					       ADM1031_REG_TEMP_MIN(chan));			data->temp_max[chan] =			    adm1031_read_value(client,					       ADM1031_REG_TEMP_MAX(chan));			data->temp_crit[chan] =			    adm1031_read_value(client,					       ADM1031_REG_TEMP_CRIT(chan));			data->auto_temp[chan] =			    adm1031_read_value(client,					       ADM1031_REG_AUTO_TEMP(chan));		}		data->conf1 = adm1031_read_value(client, ADM1031_REG_CONF1);		data->conf2 = adm1031_read_value(client, ADM1031_REG_CONF2);		data->alarm = adm1031_read_value(client, ADM1031_REG_STATUS(0))			     | (adm1031_read_value(client, ADM1031_REG_STATUS(1))				<< 8);		if (data->chip_type == adm1030) {			data->alarm &= 0xc0ff;		}				for (chan=0; chan<(data->chip_type == adm1030 ? 1 : 2); chan++) {			data->fan_div[chan] =			    adm1031_read_value(client, ADM1031_REG_FAN_DIV(chan));			data->fan_min[chan] =			    adm1031_read_value(client, ADM1031_REG_FAN_MIN(chan));			data->fan[chan] =			    adm1031_read_value(client, ADM1031_REG_FAN_SPEED(chan));			data->pwm[chan] =			    0xf & (adm1031_read_value(client, ADM1031_REG_PWM) >> 				   (4*chan));		}		data->last_updated = jiffies;		data->valid = 1;	}	up(&data->update_lock);	return data;}static int __init sensors_adm1031_init(void){	return i2c_add_driver(&adm1031_driver);}static void __exit sensors_adm1031_exit(void){	i2c_del_driver(&adm1031_driver);}MODULE_AUTHOR("Alexandre d'Alton <alex@alexdalton.org>");MODULE_DESCRIPTION("ADM1031/ADM1030 driver");MODULE_LICENSE("GPL");module_init(sensors_adm1031_init);module_exit(sensors_adm1031_exit);

⌨️ 快捷键说明

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