📄 adm1025.c
字号:
* Real code */static int adm1025_attach_adapter(struct i2c_adapter *adapter){ if (!(adapter->class & I2C_CLASS_HWMON)) return 0; return i2c_probe(adapter, &addr_data, adm1025_detect);}static struct attribute *adm1025_attributes[] = { &dev_attr_in0_input.attr, &dev_attr_in1_input.attr, &dev_attr_in2_input.attr, &dev_attr_in3_input.attr, &dev_attr_in5_input.attr, &dev_attr_in0_min.attr, &dev_attr_in1_min.attr, &dev_attr_in2_min.attr, &dev_attr_in3_min.attr, &dev_attr_in5_min.attr, &dev_attr_in0_max.attr, &dev_attr_in1_max.attr, &dev_attr_in2_max.attr, &dev_attr_in3_max.attr, &dev_attr_in5_max.attr, &dev_attr_temp1_input.attr, &dev_attr_temp2_input.attr, &dev_attr_temp1_min.attr, &dev_attr_temp2_min.attr, &dev_attr_temp1_max.attr, &dev_attr_temp2_max.attr, &dev_attr_alarms.attr, &dev_attr_cpu0_vid.attr, &dev_attr_vrm.attr, NULL};static const struct attribute_group adm1025_group = { .attrs = adm1025_attributes,};static struct attribute *adm1025_attributes_opt[] = { &dev_attr_in4_input.attr, &dev_attr_in4_min.attr, &dev_attr_in4_max.attr, NULL};static const struct attribute_group adm1025_group_opt = { .attrs = adm1025_attributes_opt,};/* * The following function does more than just detection. If detection * succeeds, it also registers the new chip. */static int adm1025_detect(struct i2c_adapter *adapter, int address, int kind){ struct i2c_client *new_client; struct adm1025_data *data; int err = 0; const char *name = ""; u8 config; if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) goto exit; if (!(data = kzalloc(sizeof(struct adm1025_data), GFP_KERNEL))) { err = -ENOMEM; goto exit; } /* The common I2C client data is placed right before the ADM1025-specific data. */ new_client = &data->client; i2c_set_clientdata(new_client, data); new_client->addr = address; new_client->adapter = adapter; new_client->driver = &adm1025_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. */ config = i2c_smbus_read_byte_data(new_client, ADM1025_REG_CONFIG); if (kind < 0) { /* detection */ if ((config & 0x80) != 0x00 || (i2c_smbus_read_byte_data(new_client, ADM1025_REG_STATUS1) & 0xC0) != 0x00 || (i2c_smbus_read_byte_data(new_client, ADM1025_REG_STATUS2) & 0xBC) != 0x00) { dev_dbg(&adapter->dev, "ADM1025 detection failed at 0x%02x.\n", address); goto exit_free; } } if (kind <= 0) { /* identification */ u8 man_id, chip_id; man_id = i2c_smbus_read_byte_data(new_client, ADM1025_REG_MAN_ID); chip_id = i2c_smbus_read_byte_data(new_client, ADM1025_REG_CHIP_ID); if (man_id == 0x41) { /* Analog Devices */ if ((chip_id & 0xF0) == 0x20) { /* ADM1025/ADM1025A */ kind = adm1025; } } else if (man_id == 0xA1) { /* Philips */ if (address != 0x2E && (chip_id & 0xF0) == 0x20) { /* NE1619 */ kind = ne1619; } } if (kind <= 0) { /* identification failed */ dev_info(&adapter->dev, "Unsupported chip (man_id=0x%02X, " "chip_id=0x%02X).\n", man_id, chip_id); goto exit_free; } } if (kind == adm1025) { name = "adm1025"; } else if (kind == ne1619) { name = "ne1619"; } /* We can fill in the remaining client fields */ strlcpy(new_client->name, name, I2C_NAME_SIZE); data->valid = 0; mutex_init(&data->update_lock); /* Tell the I2C layer a new client has arrived */ if ((err = i2c_attach_client(new_client))) goto exit_free; /* Initialize the ADM1025 chip */ adm1025_init_client(new_client); /* Register sysfs hooks */ if ((err = sysfs_create_group(&new_client->dev.kobj, &adm1025_group))) goto exit_detach; /* Pin 11 is either in4 (+12V) or VID4 */ if (!(config & 0x20)) { if ((err = device_create_file(&new_client->dev, &dev_attr_in4_input)) || (err = device_create_file(&new_client->dev, &dev_attr_in4_min)) || (err = device_create_file(&new_client->dev, &dev_attr_in4_max))) goto exit_remove; } data->hwmon_dev = hwmon_device_register(&new_client->dev); if (IS_ERR(data->hwmon_dev)) { err = PTR_ERR(data->hwmon_dev); goto exit_remove; } return 0;exit_remove: sysfs_remove_group(&new_client->dev.kobj, &adm1025_group); sysfs_remove_group(&new_client->dev.kobj, &adm1025_group_opt);exit_detach: i2c_detach_client(new_client);exit_free: kfree(data);exit: return err;}static void adm1025_init_client(struct i2c_client *client){ u8 reg; struct adm1025_data *data = i2c_get_clientdata(client); int i; data->vrm = vid_which_vrm(); /* * Set high limits * Usually we avoid setting limits on driver init, but it happens * that the ADM1025 comes with stupid default limits (all registers * set to 0). In case the chip has not gone through any limit * setting yet, we better set the high limits to the max so that * no alarm triggers. */ for (i=0; i<6; i++) { reg = i2c_smbus_read_byte_data(client, ADM1025_REG_IN_MAX(i)); if (reg == 0) i2c_smbus_write_byte_data(client, ADM1025_REG_IN_MAX(i), 0xFF); } for (i=0; i<2; i++) { reg = i2c_smbus_read_byte_data(client, ADM1025_REG_TEMP_HIGH(i)); if (reg == 0) i2c_smbus_write_byte_data(client, ADM1025_REG_TEMP_HIGH(i), 0x7F); } /* * Start the conversions */ reg = i2c_smbus_read_byte_data(client, ADM1025_REG_CONFIG); if (!(reg & 0x01)) i2c_smbus_write_byte_data(client, ADM1025_REG_CONFIG, (reg&0x7E)|0x01);}static int adm1025_detach_client(struct i2c_client *client){ struct adm1025_data *data = i2c_get_clientdata(client); int err; hwmon_device_unregister(data->hwmon_dev); sysfs_remove_group(&client->dev.kobj, &adm1025_group); sysfs_remove_group(&client->dev.kobj, &adm1025_group_opt); if ((err = i2c_detach_client(client))) return err; kfree(data); return 0;}static struct adm1025_data *adm1025_update_device(struct device *dev){ struct i2c_client *client = to_i2c_client(dev); struct adm1025_data *data = i2c_get_clientdata(client); mutex_lock(&data->update_lock); if (time_after(jiffies, data->last_updated + HZ * 2) || !data->valid) { int i; dev_dbg(&client->dev, "Updating data.\n"); for (i=0; i<6; i++) { data->in[i] = i2c_smbus_read_byte_data(client, ADM1025_REG_IN(i)); data->in_min[i] = i2c_smbus_read_byte_data(client, ADM1025_REG_IN_MIN(i)); data->in_max[i] = i2c_smbus_read_byte_data(client, ADM1025_REG_IN_MAX(i)); } for (i=0; i<2; i++) { data->temp[i] = i2c_smbus_read_byte_data(client, ADM1025_REG_TEMP(i)); data->temp_min[i] = i2c_smbus_read_byte_data(client, ADM1025_REG_TEMP_LOW(i)); data->temp_max[i] = i2c_smbus_read_byte_data(client, ADM1025_REG_TEMP_HIGH(i)); } data->alarms = i2c_smbus_read_byte_data(client, ADM1025_REG_STATUS1) | (i2c_smbus_read_byte_data(client, ADM1025_REG_STATUS2) << 8); data->vid = (i2c_smbus_read_byte_data(client, ADM1025_REG_VID) & 0x0f) | ((i2c_smbus_read_byte_data(client, ADM1025_REG_VID4) & 0x01) << 4); data->last_updated = jiffies; data->valid = 1; } mutex_unlock(&data->update_lock); return data;}static int __init sensors_adm1025_init(void){ return i2c_add_driver(&adm1025_driver);}static void __exit sensors_adm1025_exit(void){ i2c_del_driver(&adm1025_driver);}MODULE_AUTHOR("Jean Delvare <khali@linux-fr.org>");MODULE_DESCRIPTION("ADM1025 driver");MODULE_LICENSE("GPL");module_init(sensors_adm1025_init);module_exit(sensors_adm1025_exit);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -