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

📄 max6650.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 2 页
字号:
	i2c_smbus_write_byte_data(client, MAX6650_REG_CONFIG, data->config);	mutex_unlock(&data->update_lock);	return count;}/* * Read/write functions for fan1_div sysfs file. The MAX6650 has no such * divider. We handle this by converting between divider and counttime: * * (counttime == k) <==> (divider == 2^k), k = 0, 1, 2, or 3 * * Lower values of k allow to connect a faster fan without the risk of * counter overflow. The price is lower resolution. You can also set counttime * using the module parameter. Note that the module parameter "prescaler" also * influences the behaviour. Unfortunately, there's no sysfs attribute * defined for that. See the data sheet for details. */static ssize_t get_div(struct device *dev, struct device_attribute *devattr,		       char *buf){	struct max6650_data *data = max6650_update_device(dev);	return sprintf(buf, "%d\n", DIV_FROM_REG(data->count));}static ssize_t set_div(struct device *dev, struct device_attribute *devattr,		       const char *buf, size_t count){	struct i2c_client *client = to_i2c_client(dev);	struct max6650_data *data = i2c_get_clientdata(client);	int div = simple_strtoul(buf, NULL, 10);	mutex_lock(&data->update_lock);	switch (div) {	case 1:		data->count = 0;		break;	case 2:		data->count = 1;		break;	case 4:		data->count = 2;		break;	case 8:		data->count = 3;		break;	default:		dev_err(&client->dev,			"illegal value for fan divider (%d)\n", div);		return -EINVAL;	}	i2c_smbus_write_byte_data(client, MAX6650_REG_COUNT, data->count);	mutex_unlock(&data->update_lock);	return count;}static SENSOR_DEVICE_ATTR(fan1_input, S_IRUGO, get_fan, NULL, 0);static SENSOR_DEVICE_ATTR(fan2_input, S_IRUGO, get_fan, NULL, 1);static SENSOR_DEVICE_ATTR(fan3_input, S_IRUGO, get_fan, NULL, 2);static SENSOR_DEVICE_ATTR(fan4_input, S_IRUGO, get_fan, NULL, 3);static DEVICE_ATTR(fan1_target, S_IWUSR | S_IRUGO, get_target, set_target);static DEVICE_ATTR(fan1_div, S_IWUSR | S_IRUGO, get_div, set_div);static DEVICE_ATTR(pwm1_enable, S_IWUSR | S_IRUGO, get_enable, set_enable);static DEVICE_ATTR(pwm1, S_IWUSR | S_IRUGO, get_pwm, set_pwm);static struct attribute *max6650_attrs[] = {	&sensor_dev_attr_fan1_input.dev_attr.attr,	&sensor_dev_attr_fan2_input.dev_attr.attr,	&sensor_dev_attr_fan3_input.dev_attr.attr,	&sensor_dev_attr_fan4_input.dev_attr.attr,	&dev_attr_fan1_target.attr,	&dev_attr_fan1_div.attr,	&dev_attr_pwm1_enable.attr,	&dev_attr_pwm1.attr,	NULL};static struct attribute_group max6650_attr_grp = {	.attrs = max6650_attrs,};/* * Real code */static int max6650_attach_adapter(struct i2c_adapter *adapter){	if (!(adapter->class & I2C_CLASS_HWMON)) {		dev_dbg(&adapter->dev,			"FATAL: max6650_attach_adapter class HWMON not set\n");		return 0;	}	return i2c_probe(adapter, &addr_data, max6650_detect);}/* * The following function does more than just detection. If detection * succeeds, it also registers the new chip. */static int max6650_detect(struct i2c_adapter *adapter, int address, int kind){	struct i2c_client *client;	struct max6650_data *data;	int err = -ENODEV;	dev_dbg(&adapter->dev, "max6650_detect called, kind = %d\n", kind);	if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) {		dev_dbg(&adapter->dev, "max6650: I2C bus doesn't support "					"byte read mode, skipping.\n");		return 0;	}	if (!(data = kzalloc(sizeof(struct max6650_data), GFP_KERNEL))) {		dev_err(&adapter->dev, "max6650: out of memory.\n");		return -ENOMEM;	}	client = &data->client;	i2c_set_clientdata(client, data);	client->addr = address;	client->adapter = adapter;	client->driver = &max6650_driver;	/*	 * 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 (actually there is only	 * one possible kind of chip for now, max6650). 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.	 *	 * Currently I can find no way to distinguish between a MAX6650 and	 * a MAX6651. This driver has only been tried on the former.	 */	if ((kind < 0) &&	   (  (i2c_smbus_read_byte_data(client, MAX6650_REG_CONFIG) & 0xC0)	    ||(i2c_smbus_read_byte_data(client, MAX6650_REG_GPIO_STAT) & 0xE0)	    ||(i2c_smbus_read_byte_data(client, MAX6650_REG_ALARM_EN) & 0xE0)	    ||(i2c_smbus_read_byte_data(client, MAX6650_REG_ALARM) & 0xE0)	    ||(i2c_smbus_read_byte_data(client, MAX6650_REG_COUNT) & 0xFC))) {		dev_dbg(&adapter->dev,			"max6650: detection failed at 0x%02x.\n", address);		goto err_free;	}	dev_info(&adapter->dev, "max6650: chip found at 0x%02x.\n", address);	strlcpy(client->name, "max6650", I2C_NAME_SIZE);	mutex_init(&data->update_lock);	if ((err = i2c_attach_client(client))) {		dev_err(&adapter->dev, "max6650: failed to attach client.\n");		goto err_free;	}	/*	 * Initialize the max6650 chip	 */	if (max6650_init_client(client))		goto err_detach;	err = sysfs_create_group(&client->dev.kobj, &max6650_attr_grp);	if (err)		goto err_detach;	data->hwmon_dev = hwmon_device_register(&client->dev);	if (!IS_ERR(data->hwmon_dev))		return 0;	err = PTR_ERR(data->hwmon_dev);	dev_err(&client->dev, "error registering hwmon device.\n");	sysfs_remove_group(&client->dev.kobj, &max6650_attr_grp);err_detach:	i2c_detach_client(client);err_free:	kfree(data);	return err;}static int max6650_detach_client(struct i2c_client *client){	struct max6650_data *data = i2c_get_clientdata(client);	int err;	sysfs_remove_group(&client->dev.kobj, &max6650_attr_grp);	hwmon_device_unregister(data->hwmon_dev);	err = i2c_detach_client(client);	if (!err)		kfree(data);	return err;}static int max6650_init_client(struct i2c_client *client){	struct max6650_data *data = i2c_get_clientdata(client);	int config;	int err = -EIO;	config = i2c_smbus_read_byte_data(client, MAX6650_REG_CONFIG);	if (config < 0) {		dev_err(&client->dev, "Error reading config, aborting.\n");		return err;	}	switch (fan_voltage) {		case 0:			break;		case 5:			config &= ~MAX6650_CFG_V12;			break;		case 12:			config |= MAX6650_CFG_V12;			break;		default:			dev_err(&client->dev,				"illegal value for fan_voltage (%d)\n",				fan_voltage);	}	dev_info(&client->dev, "Fan voltage is set to %dV.\n",		 (config & MAX6650_CFG_V12) ? 12 : 5);	switch (prescaler) {		case 0:			break;		case 1:			config &= ~MAX6650_CFG_PRESCALER_MASK;			break;		case 2:			config = (config & ~MAX6650_CFG_PRESCALER_MASK)				 | MAX6650_CFG_PRESCALER_2;			break;		case  4:			config = (config & ~MAX6650_CFG_PRESCALER_MASK)				 | MAX6650_CFG_PRESCALER_4;			break;		case  8:			config = (config & ~MAX6650_CFG_PRESCALER_MASK)				 | MAX6650_CFG_PRESCALER_8;			break;		case 16:			config = (config & ~MAX6650_CFG_PRESCALER_MASK)				 | MAX6650_CFG_PRESCALER_16;			break;		default:			dev_err(&client->dev,				"illegal value for prescaler (%d)\n",				prescaler);	}	dev_info(&client->dev, "Prescaler is set to %d.\n",		 1 << (config & MAX6650_CFG_PRESCALER_MASK));	/* If mode is set to "full off", we change it to "open loop" and	 * set DAC to 255, which has the same effect. We do this because	 * there's no "full off" mode defined in hwmon specifcations.	 */	if ((config & MAX6650_CFG_MODE_MASK) == MAX6650_CFG_MODE_OFF) {		dev_dbg(&client->dev, "Change mode to open loop, full off.\n");		config = (config & ~MAX6650_CFG_MODE_MASK)			 | MAX6650_CFG_MODE_OPEN_LOOP;		if (i2c_smbus_write_byte_data(client, MAX6650_REG_DAC, 255)) {			dev_err(&client->dev, "DAC write error, aborting.\n");			return err;		}	}	if (i2c_smbus_write_byte_data(client, MAX6650_REG_CONFIG, config)) {		dev_err(&client->dev, "Config write error, aborting.\n");		return err;	}	data->config = config;	data->count = i2c_smbus_read_byte_data(client, MAX6650_REG_COUNT);	return 0;}static const u8 tach_reg[] = {	MAX6650_REG_TACH0,	MAX6650_REG_TACH1,	MAX6650_REG_TACH2,	MAX6650_REG_TACH3,};static struct max6650_data *max6650_update_device(struct device *dev){	int i;	struct i2c_client *client = to_i2c_client(dev);	struct max6650_data *data = i2c_get_clientdata(client);	mutex_lock(&data->update_lock);	if (time_after(jiffies, data->last_updated + HZ) || !data->valid) {		data->speed = i2c_smbus_read_byte_data(client,						       MAX6650_REG_SPEED);		data->config = i2c_smbus_read_byte_data(client,							MAX6650_REG_CONFIG);		for (i = 0; i < 4; i++) {			data->tach[i] = i2c_smbus_read_byte_data(client,								 tach_reg[i]);		}		data->count = i2c_smbus_read_byte_data(client,							MAX6650_REG_COUNT);		data->dac = i2c_smbus_read_byte_data(client, MAX6650_REG_DAC);		data->last_updated = jiffies;		data->valid = 1;	}	mutex_unlock(&data->update_lock);	return data;}static int __init sensors_max6650_init(void){	return i2c_add_driver(&max6650_driver);}static void __exit sensors_max6650_exit(void){	i2c_del_driver(&max6650_driver);}MODULE_AUTHOR("Hans J. Koch");MODULE_DESCRIPTION("MAX6650 sensor driver");MODULE_LICENSE("GPL");module_init(sensors_max6650_init);module_exit(sensors_max6650_exit);

⌨️ 快捷键说明

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