📄 w83781d.c
字号:
}static ssize_tstore_rt_reg(struct device *dev, const char *buf, size_t count, int nr){ struct i2c_client *client = to_i2c_client(dev); struct w83781d_data *data = i2c_get_clientdata(client); u32 val, i; for (i = 0; i < count; i++) { val = simple_strtoul(buf + count, NULL, 10); /* fixme: no bounds checking 0-255 */ data->rt[nr - 1][i] = val & 0xff; w83781d_write_value(client, W83781D_REG_RT_IDX, i); w83781d_write_value(client, W83781D_REG_RT_VAL, data->rt[nr - 1][i]); } return count;}#define sysfs_rt(offset) \static ssize_t show_regs_rt_##offset (struct device *dev, char *buf) \{ \ return show_rt_reg(dev, buf, offset); \} \static ssize_t store_regs_rt_##offset (struct device *dev, const char *buf, size_t count) \{ \ return store_rt_reg(dev, buf, count, offset); \} \static DEVICE_ATTR(rt##offset, S_IRUGO | S_IWUSR, show_regs_rt_##offset, store_regs_rt_##offset);sysfs_rt(1);sysfs_rt(2);sysfs_rt(3);#define device_create_file_rt(client, offset) \do { \device_create_file(&client->dev, &dev_attr_rt##offset); \} while (0)#endif /* ifdef W83781D_RT *//* This function is called when: * w83781d_driver is inserted (when this module is loaded), for each available adapter * when a new adapter is inserted (and w83781d_driver is still present) */static intw83781d_attach_adapter(struct i2c_adapter *adapter){ if (!(adapter->class & I2C_CLASS_HWMON)) return 0; return i2c_detect(adapter, &addr_data, w83781d_detect);}/* Assumes that adapter is of I2C, not ISA variety. * OTHERWISE DON'T CALL THIS */static intw83781d_detect_subclients(struct i2c_adapter *adapter, int address, int kind, struct i2c_client *new_client){ int i, val1 = 0, id; int err; const char *client_name = ""; struct w83781d_data *data = i2c_get_clientdata(new_client); data->lm75[0] = kmalloc(sizeof(struct i2c_client), GFP_KERNEL); if (!(data->lm75[0])) { err = -ENOMEM; goto ERROR_SC_0; } memset(data->lm75[0], 0x00, sizeof (struct i2c_client)); 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(&new_client->dev, "Invalid subclient " "address %d; must be 0x48-0x4f\n", force_subclients[i]); err = -EINVAL; goto ERROR_SC_1; } } w83781d_write_value(new_client, W83781D_REG_I2C_SUBADDR, (force_subclients[2] & 0x07) | ((force_subclients[3] & 0x07) << 4)); data->lm75[0]->addr = force_subclients[2]; } else { val1 = w83781d_read_value(new_client, W83781D_REG_I2C_SUBADDR); data->lm75[0]->addr = 0x48 + (val1 & 0x07); } if (kind != w83783s) { data->lm75[1] = kmalloc(sizeof(struct i2c_client), GFP_KERNEL); if (!(data->lm75[1])) { err = -ENOMEM; goto ERROR_SC_1; } memset(data->lm75[1], 0x0, sizeof(struct i2c_client)); if (force_subclients[0] == id && force_subclients[1] == address) { data->lm75[1]->addr = force_subclients[3]; } else { data->lm75[1]->addr = 0x48 + ((val1 >> 4) & 0x07); } if (data->lm75[0]->addr == data->lm75[1]->addr) { dev_err(&new_client->dev, "Duplicate addresses 0x%x for subclients.\n", data->lm75[0]->addr); err = -EBUSY; goto ERROR_SC_2; } } if (kind == w83781d) client_name = "w83781d subclient"; else if (kind == w83782d) client_name = "w83782d subclient"; else if (kind == w83783s) client_name = "w83783s subclient"; else if (kind == w83627hf) client_name = "w83627hf subclient"; else if (kind == as99127f) client_name = "as99127f subclient"; for (i = 0; i <= 1; i++) { /* store all data in w83781d */ i2c_set_clientdata(data->lm75[i], NULL); data->lm75[i]->adapter = adapter; data->lm75[i]->driver = &w83781d_driver; data->lm75[i]->flags = 0; strlcpy(data->lm75[i]->name, client_name, I2C_NAME_SIZE); if ((err = i2c_attach_client(data->lm75[i]))) { dev_err(&new_client->dev, "Subclient %d " "registration at address 0x%x " "failed.\n", i, data->lm75[i]->addr); if (i == 1) goto ERROR_SC_3; goto ERROR_SC_2; } if (kind == w83783s) break; } return 0;/* Undo inits in case of errors */ERROR_SC_3: i2c_detach_client(data->lm75[0]);ERROR_SC_2: if (NULL != data->lm75[1]) kfree(data->lm75[1]);ERROR_SC_1: if (NULL != data->lm75[0]) kfree(data->lm75[0]);ERROR_SC_0: return err;}static intw83781d_detect(struct i2c_adapter *adapter, int address, int kind){ int i = 0, val1 = 0, val2; struct i2c_client *new_client; struct w83781d_data *data; int err; const char *client_name = ""; int is_isa = i2c_is_isa_adapter(adapter); enum vendor { winbond, asus } vendid; if (!is_isa && !i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) { err = -EINVAL; goto ERROR0; } /* Prevent users from forcing a kind for a bus it isn't supposed to possibly be on */ if (is_isa && (kind == as99127f || kind == w83783s)) { dev_err(&adapter->dev, "Cannot force I2C-only chip for ISA address 0x%02x.\n", address); err = -EINVAL; goto ERROR0; } if (!is_isa && kind == w83697hf) { dev_err(&adapter->dev, "Cannot force ISA-only chip for I2C address 0x%02x.\n", address); err = -EINVAL; goto ERROR0; } if (is_isa) if (!request_region(address, W83781D_EXTENT, "w83781d")) { err = -EBUSY; goto ERROR0; } /* Probe whether there is anything available on this address. Already done for SMBus clients */ if (kind < 0) { if (is_isa) {#define REALLY_SLOW_IO /* We need the timeouts for at least some LM78-like chips. But only if we read 'undefined' registers. */ i = inb_p(address + 1); if (inb_p(address + 2) != i) { err = -ENODEV; goto ERROR1; } if (inb_p(address + 3) != i) { err = -ENODEV; goto ERROR1; } if (inb_p(address + 7) != i) { err = -ENODEV; goto ERROR1; }#undef REALLY_SLOW_IO /* Let's just hope nothing breaks here */ i = inb_p(address + 5) & 0x7f; outb_p(~i & 0x7f, address + 5); if ((inb_p(address + 5) & 0x7f) != (~i & 0x7f)) { outb_p(i, address + 5); err = -ENODEV; goto ERROR1; } } } /* 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 w83781d_{read,write}_value. */ if (!(data = kmalloc(sizeof(struct w83781d_data), GFP_KERNEL))) { err = -ENOMEM; goto ERROR1; } memset(data, 0, sizeof(struct w83781d_data)); new_client = &data->client; i2c_set_clientdata(new_client, data); new_client->addr = address; init_MUTEX(&data->lock); new_client->adapter = adapter; new_client->driver = &w83781d_driver; new_client->flags = 0; /* Now, we do the remaining detection. */ /* The w8378?d may be stuck in some other bank than bank 0. This may make reading other information impossible. Specify a force=... or force_*=... parameter, and the Winbond will be reset to the right bank. */ if (kind < 0) { if (w83781d_read_value(new_client, W83781D_REG_CONFIG) & 0x80){ err = -ENODEV; goto ERROR2; } val1 = w83781d_read_value(new_client, W83781D_REG_BANK); val2 = w83781d_read_value(new_client, W83781D_REG_CHIPMAN); /* Check for Winbond or Asus ID if in bank 0 */ if ((!(val1 & 0x07)) && (((!(val1 & 0x80)) && (val2 != 0xa3) && (val2 != 0xc3)) || ((val1 & 0x80) && (val2 != 0x5c) && (val2 != 0x12)))) { err = -ENODEV; goto ERROR2; } /* If Winbond SMBus, check address at 0x48. Asus doesn't support, except for as99127f rev.2 */ if ((!is_isa) && (((!(val1 & 0x80)) && (val2 == 0xa3)) || ((val1 & 0x80) && (val2 == 0x5c)))) { if (w83781d_read_value (new_client, W83781D_REG_I2C_ADDR) != address) { err = -ENODEV; goto ERROR2; } } } /* We have either had a force parameter, or we have already detected the Winbond. Put it now into bank 0 and Vendor ID High Byte */ w83781d_write_value(new_client, W83781D_REG_BANK, (w83781d_read_value(new_client, W83781D_REG_BANK) & 0x78) | 0x80); /* Determine the chip type. */ if (kind <= 0) { /* get vendor ID */ val2 = w83781d_read_value(new_client, W83781D_REG_CHIPMAN); if (val2 == 0x5c) vendid = winbond; else if (val2 == 0x12) vendid = asus; else { err = -ENODEV; goto ERROR2; } val1 = w83781d_read_value(new_client, W83781D_REG_WCHIPID); if ((val1 == 0x10 || val1 == 0x11) && vendid == winbond) kind = w83781d; else if (val1 == 0x30 && vendid == winbond) kind = w83782d; else if (val1 == 0x40 && vendid == winbond && !is_isa && address == 0x2d) kind = w83783s; else if ((val1 == 0x21 || val1 == 0x90) && vendid == winbond) kind = w83627hf; else if (val1 == 0x31 && !is_isa && address >= 0x28) kind = as99127f; else if (val1 == 0x60 && vendid == winbond && is_isa) kind = w83697hf; else { if (kind == 0) dev_warn(&new_client->dev, "Ignoring 'force' parameter for unknown chip at" "adapter %d, address 0x%02x\n", i2c_adapter_id(adapter), address); err = -EINVAL; goto ERROR2; } } if (kind == w83781d) { client_name = "w83781d"; } else if (kind == w83782d) { client_name = "w83782d"; } else if (kind == w83783s) { client_name = "w83783s"; } else if (kind == w83627hf) { if (val1 == 0x90) client_name = "w83627thf"; else client_name = "w83627hf"; } else if (kind == as99127f) { client_name = "as99127f"; } else if (kind == w83697hf) { client_name = "w83697hf"; } /* Fill in the remaining client fields and put into the global list */ strlcpy(new_client->name, client_name, I2C_NAME_SIZE); data->type = kind; 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 ERROR2; /* attach secondary i2c lm75-like clients */ if (!is_isa) { if ((err = w83781d_detect_subclients(adapter, address, kind, new_client))) goto ERROR3; } else { data->lm75[0] = NULL; data->lm75[1] = NULL; } /* Initialize the chip */ w83781d_init_client(new_client); /* A few vars need to be filled upon startup */ for (i = 1; i <= 3; i++) { data->fan_min[i - 1] = w83781d_read_value(new_client, W83781D_REG_FAN_MIN(i)); } if (kind != w83781d && kind != as99127f) for (i = 0; i < 4; i++) data->pwmenable[i] = 1; /* Register sysfs hooks */ device_create_file_in(new_client, 0); if (kind != w83783s && kind != w83697hf) device_create_file_in(new_client, 1); device_create_file_in(new_client, 2); device_create_file_in(new_client, 3); device_create_file_in(new_client, 4); device_create_file_in(new_client, 5); device_create_file_in(new_client, 6); if (kind != as99127f && kind != w83781d && kind != w83783s) { device_create_file_in(new_client, 7); device_create_file_in(new_client, 8); } device_create_file_fan(new_client, 1); device_create_file_fan(new_client, 2); if (kind != w83697hf) device_create_file_fan(new_client, 3); device_create_file_temp(new_client, 1); device_create_file_temp(new_client, 2); if (kind != w83783s && kind != w83697hf) device_create_file_temp(new_client, 3); if (kind != w83697hf) device_create_file_vid(new_client); if (kind != w83697hf) device_create_file_vrm(new_client); device_create_file_fan_div(new_client, 1); device_create_file_fan_div(new_client, 2); if (kind != w83697hf) device_create_file_fan_div(new_client, 3); device_create_file_alarms(new_client); device_create_file_beep(new_client); if (kind != w83781d && kind != as99127f) { device_create_file_pwm(new_client, 1); device_create_file_pwm(new_client, 2); device_create_file_pwmenable(new_client, 2); } if (kind == w83782d && !is_isa) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -