📄 max6650.c
字号:
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 + -