📄 w83791d.c
字号:
sub_client->addr = 0x48 + addr; i2c_set_clientdata(sub_client, NULL); sub_client->adapter = adapter; sub_client->driver = &w83791d_driver; strlcpy(sub_client->name, "w83791d subclient", I2C_NAME_SIZE); if ((err = i2c_attach_client(sub_client))) { dev_err(&client->dev, "subclient registration " "at address 0x%x failed\n", sub_client->addr); kfree(sub_client); return err; } return 0;}static int w83791d_detect_subclients(struct i2c_adapter *adapter, int address, int kind, struct i2c_client *client){ struct w83791d_data *data = i2c_get_clientdata(client); int i, id, err; u8 val; id = i2c_adapter_id(adapter); if (force_subclients[0] == id && force_subclients[1] == address) { for (i = 2; i <= 3; i++) { if (force_subclients[i] < 0x48 || force_subclients[i] > 0x4f) { dev_err(&client->dev, "invalid subclient " "address %d; must be 0x48-0x4f\n", force_subclients[i]); err = -ENODEV; goto error_sc_0; } } w83791d_write(client, W83791D_REG_I2C_SUBADDR, (force_subclients[2] & 0x07) | ((force_subclients[3] & 0x07) << 4)); } val = w83791d_read(client, W83791D_REG_I2C_SUBADDR); if (!(val & 0x08)) { err = w83791d_create_subclient(adapter, client, val & 0x7, &data->lm75[0]); if (err < 0) goto error_sc_0; } if (!(val & 0x80)) { if ((data->lm75[0] != NULL) && ((val & 0x7) == ((val >> 4) & 0x7))) { dev_err(&client->dev, "duplicate addresses 0x%x, " "use force_subclient\n", data->lm75[0]->addr); err = -ENODEV; goto error_sc_1; } err = w83791d_create_subclient(adapter, client, (val >> 4) & 0x7, &data->lm75[1]); if (err < 0) goto error_sc_1; } return 0;/* Undo inits in case of errors */error_sc_1: if (data->lm75[0] != NULL) { i2c_detach_client(data->lm75[0]); kfree(data->lm75[0]); }error_sc_0: return err;}static int w83791d_detect(struct i2c_adapter *adapter, int address, int kind){ struct i2c_client *client; struct device *dev; struct w83791d_data *data; int i, val1, val2; int err = 0; const char *client_name = ""; if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) { goto error0; } /* OK. For now, we presume we have a valid client. We now create the client structure, even though we cannot fill it completely yet. But it allows us to access w83791d_{read,write}_value. */ if (!(data = kzalloc(sizeof(struct w83791d_data), GFP_KERNEL))) { err = -ENOMEM; goto error0; } client = &data->client; dev = &client->dev; i2c_set_clientdata(client, data); client->addr = address; client->adapter = adapter; client->driver = &w83791d_driver; mutex_init(&data->update_lock); /* Now, we do the remaining detection. */ /* The w83791d may be stuck in some other bank than bank 0. This may make reading other information impossible. Specify a force=... parameter, and the Winbond will be reset to the right bank. */ if (kind < 0) { if (w83791d_read(client, W83791D_REG_CONFIG) & 0x80) { dev_dbg(dev, "Detection failed at step 1\n"); goto error1; } val1 = w83791d_read(client, W83791D_REG_BANK); val2 = w83791d_read(client, W83791D_REG_CHIPMAN); /* Check for Winbond ID if in bank 0 */ if (!(val1 & 0x07)) { /* yes it is Bank0 */ if (((!(val1 & 0x80)) && (val2 != 0xa3)) || ((val1 & 0x80) && (val2 != 0x5c))) { dev_dbg(dev, "Detection failed at step 2\n"); goto error1; } } /* If Winbond chip, address of chip and W83791D_REG_I2C_ADDR should match */ if (w83791d_read(client, W83791D_REG_I2C_ADDR) != address) { dev_dbg(dev, "Detection failed at step 3\n"); goto error1; } } /* We either have a force parameter or we have reason to believe it is a Winbond chip. Either way, we want bank 0 and Vendor ID high byte */ val1 = w83791d_read(client, W83791D_REG_BANK) & 0x78; w83791d_write(client, W83791D_REG_BANK, val1 | 0x80); /* Verify it is a Winbond w83791d */ if (kind <= 0) { /* get vendor ID */ val2 = w83791d_read(client, W83791D_REG_CHIPMAN); if (val2 != 0x5c) { /* the vendor is NOT Winbond */ dev_dbg(dev, "Detection failed at step 4\n"); goto error1; } val1 = w83791d_read(client, W83791D_REG_WCHIPID); if (val1 == 0x71) { kind = w83791d; } else { if (kind == 0) dev_warn(dev, "w83791d: Ignoring 'force' parameter " "for unknown chip at adapter %d, " "address 0x%02x\n", i2c_adapter_id(adapter), address); goto error1; } } if (kind == w83791d) { client_name = "w83791d"; } else { dev_err(dev, "w83791d: Internal error: unknown kind (%d)?!?\n", kind); goto error1; }#ifdef DEBUG val1 = w83791d_read(client, W83791D_REG_DID_VID4); dev_dbg(dev, "Device ID version: %d.%d (0x%02x)\n", (val1 >> 5) & 0x07, (val1 >> 1) & 0x0f, val1);#endif /* Fill in the remaining client fields and put into the global list */ strlcpy(client->name, client_name, I2C_NAME_SIZE); /* Tell the I2C layer a new client has arrived */ if ((err = i2c_attach_client(client))) goto error1; if ((err = w83791d_detect_subclients(adapter, address, kind, client))) goto error2; /* Initialize the chip */ w83791d_init_client(client); /* If the fan_div is changed, make sure there is a rational fan_min in place */ for (i = 0; i < NUMBER_OF_FANIN; i++) { data->fan_min[i] = w83791d_read(client, W83791D_REG_FAN_MIN[i]); } /* Register sysfs hooks */ if ((err = sysfs_create_group(&client->dev.kobj, &w83791d_group))) goto error3; /* Everything is ready, now register the working device */ data->hwmon_dev = hwmon_device_register(dev); if (IS_ERR(data->hwmon_dev)) { err = PTR_ERR(data->hwmon_dev); goto error4; } return 0;error4: sysfs_remove_group(&client->dev.kobj, &w83791d_group);error3: if (data->lm75[0] != NULL) { i2c_detach_client(data->lm75[0]); kfree(data->lm75[0]); } if (data->lm75[1] != NULL) { i2c_detach_client(data->lm75[1]); kfree(data->lm75[1]); }error2: i2c_detach_client(client);error1: kfree(data);error0: return err;}static int w83791d_detach_client(struct i2c_client *client){ struct w83791d_data *data = i2c_get_clientdata(client); int err; /* main client */ if (data) { hwmon_device_unregister(data->hwmon_dev); sysfs_remove_group(&client->dev.kobj, &w83791d_group); } if ((err = i2c_detach_client(client))) return err; /* main client */ if (data) kfree(data); /* subclient */ else kfree(client); return 0;}static void w83791d_init_client(struct i2c_client *client){ struct w83791d_data *data = i2c_get_clientdata(client); u8 tmp; u8 old_beep; /* The difference between reset and init is that reset does a hard reset of the chip via index 0x40, bit 7, but init simply forces certain registers to have "sane" values. The hope is that the BIOS has done the right thing (which is why the default is reset=0, init=0), but if not, reset is the hard hammer and init is the soft mallet both of which are trying to whack things into place... NOTE: The data sheet makes a distinction between "power on defaults" and "reset by MR". As far as I can tell, the hard reset puts everything into a power-on state so I'm not sure what "reset by MR" means or how it can happen. */ if (reset || init) { /* keep some BIOS settings when we... */ old_beep = w83791d_read(client, W83791D_REG_BEEP_CONFIG); if (reset) { /* ... reset the chip and ... */ w83791d_write(client, W83791D_REG_CONFIG, 0x80); } /* ... disable power-on abnormal beep */ w83791d_write(client, W83791D_REG_BEEP_CONFIG, old_beep | 0x80); /* disable the global beep (not done by hard reset) */ tmp = w83791d_read(client, W83791D_REG_BEEP_CTRL[1]); w83791d_write(client, W83791D_REG_BEEP_CTRL[1], tmp & 0xef); if (init) { /* Make sure monitoring is turned on for add-ons */ tmp = w83791d_read(client, W83791D_REG_TEMP2_CONFIG); if (tmp & 1) { w83791d_write(client, W83791D_REG_TEMP2_CONFIG, tmp & 0xfe); } tmp = w83791d_read(client, W83791D_REG_TEMP3_CONFIG); if (tmp & 1) { w83791d_write(client, W83791D_REG_TEMP3_CONFIG, tmp & 0xfe); } /* Start monitoring */ tmp = w83791d_read(client, W83791D_REG_CONFIG) & 0xf7; w83791d_write(client, W83791D_REG_CONFIG, tmp | 0x01); } } data->vrm = vid_which_vrm();}static struct w83791d_data *w83791d_update_device(struct device *dev){ struct i2c_client *client = to_i2c_client(dev); struct w83791d_data *data = i2c_get_clientdata(client); int i, j; u8 reg_array_tmp[3]; mutex_lock(&data->update_lock); if (time_after(jiffies, data->last_updated + (HZ * 3)) || !data->valid) { dev_dbg(dev, "Starting w83791d device update\n"); /* Update the voltages measured value and limits */ for (i = 0; i < NUMBER_OF_VIN; i++) { data->in[i] = w83791d_read(client, W83791D_REG_IN[i]); data->in_max[i] = w83791d_read(client, W83791D_REG_IN_MAX[i]); data->in_min[i] = w83791d_read(client, W83791D_REG_IN_MIN[i]); } /* Update the fan counts and limits */ for (i = 0; i < NUMBER_OF_FANIN; i++) { /* Update the Fan measured value and limits */ data->fan[i] = w83791d_read(client, W83791D_REG_FAN[i]); data->fan_min[i] = w83791d_read(client, W83791D_REG_FAN_MIN[i]); } /* Update the fan divisor */ for (i = 0; i < 3; i++) { reg_array_tmp[i] = w83791d_read(client, W83791D_REG_FAN_DIV[i]); } data->fan_div[0] = (reg_array_tmp[0] >> 4) & 0x03; data->fan_div[1] = (reg_array_tmp[0] >> 6) & 0x03; data->fan_div[2] = (reg_array_tmp[1] >> 6) & 0x03; data->fan_div[3] = reg_array_tmp[2] & 0x07; data->fan_div[4] = (reg_array_tmp[2] >> 4) & 0x07; /* Update the first temperature sensor */ for (i = 0; i < 3; i++) { data->temp1[i] = w83791d_read(client, W83791D_REG_TEMP1[i]); } /* Update the rest of the temperature sensors */ for (i = 0; i < 2; i++) { for (j = 0; j < 3; j++) { data->temp_add[i][j] = (w83791d_read(client, W83791D_REG_TEMP_ADD[i][j * 2]) << 8) | w83791d_read(client, W83791D_REG_TEMP_ADD[i][j * 2 + 1]); } } /* Update the realtime status */ data->alarms = w83791d_read(client, W83791D_REG_ALARM1) + (w83791d_read(client, W83791D_REG_ALARM2) << 8) + (w83791d_read(client, W83791D_REG_ALARM3) << 16); /* Update the beep configuration information */ data->beep_mask = w83791d_read(client, W83791D_REG_BEEP_CTRL[0]) + (w83791d_read(client, W83791D_REG_BEEP_CTRL[1]) << 8) + (w83791d_read(client, W83791D_REG_BEEP_CTRL[2]) << 16); /* Extract global beep enable flag */ data->beep_enable = (data->beep_mask >> GLOBAL_BEEP_ENABLE_SHIFT) & 0x01; /* Update the cpu voltage information */ i = w83791d_read(client, W83791D_REG_VID_FANDIV); data->vid = i & 0x0f; data->vid |= (w83791d_read(client, W83791D_REG_DID_VID4) & 0x01) << 4; data->last_updated = jiffies; data->valid = 1; } mutex_unlock(&data->update_lock);#ifdef DEBUG w83791d_print_debug(data, dev);#endif return data;}#ifdef DEBUGstatic void w83791d_print_debug(struct w83791d_data *data, struct device *dev){ int i = 0, j = 0; dev_dbg(dev, "======Start of w83791d debug values======\n"); dev_dbg(dev, "%d set of Voltages: ===>\n", NUMBER_OF_VIN); for (i = 0; i < NUMBER_OF_VIN; i++) { dev_dbg(dev, "vin[%d] is: 0x%02x\n", i, data->in[i]); dev_dbg(dev, "vin[%d] min is: 0x%02x\n", i, data->in_min[i]); dev_dbg(dev, "vin[%d] max is: 0x%02x\n", i, data->in_max[i]); } dev_dbg(dev, "%d set of Fan Counts/Divisors: ===>\n", NUMBER_OF_FANIN); for (i = 0; i < NUMBER_OF_FANIN; i++) { dev_dbg(dev, "fan[%d] is: 0x%02x\n", i, data->fan[i]); dev_dbg(dev, "fan[%d] min is: 0x%02x\n", i, data->fan_min[i]); dev_dbg(dev, "fan_div[%d] is: 0x%02x\n", i, data->fan_div[i]); } /* temperature math is signed, but only print out the bits that matter */ dev_dbg(dev, "%d set of Temperatures: ===>\n", NUMBER_OF_TEMPIN); for (i = 0; i < 3; i++) { dev_dbg(dev, "temp1[%d] is: 0x%02x\n", i, (u8) data->temp1[i]); } for (i = 0; i < 2; i++) { for (j = 0; j < 3; j++) { dev_dbg(dev, "temp_add[%d][%d] is: 0x%04x\n", i, j, (u16) data->temp_add[i][j]); } } dev_dbg(dev, "Misc Information: ===>\n"); dev_dbg(dev, "alarm is: 0x%08x\n", data->alarms); dev_dbg(dev, "beep_mask is: 0x%08x\n", data->beep_mask); dev_dbg(dev, "beep_enable is: %d\n", data->beep_enable); dev_dbg(dev, "vid is: 0x%02x\n", data->vid); dev_dbg(dev, "vrm is: 0x%02x\n", data->vrm); dev_dbg(dev, "=======End of w83791d debug values========\n"); dev_dbg(dev, "\n");}#endifstatic int __init sensors_w83791d_init(void){ return i2c_add_driver(&w83791d_driver);}static void __exit sensors_w83791d_exit(void){ i2c_del_driver(&w83791d_driver);}MODULE_AUTHOR("Charles Spirakis <bezaur@gmail.com>");MODULE_DESCRIPTION("W83791D driver");MODULE_LICENSE("GPL");module_init(sensors_w83791d_init);module_exit(sensors_w83791d_exit);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -