📄 w83627hf.c
字号:
superio_exit(); return 0;}int w83627hf_detect(struct i2c_adapter *adapter, int address, int kind){ int val; struct i2c_client *new_client; struct w83627hf_data *data; int err = 0; const char *client_name = ""; if (!i2c_is_isa_adapter(adapter)) { err = -ENODEV; goto ERROR0; } if(force_addr) address = force_addr & ~(WINB_EXTENT - 1); if (!request_region(address, WINB_EXTENT, "w83627hf")) { err = -EBUSY; goto ERROR0; } if(force_addr) { printk("w83627hf.o: forcing ISA address 0x%04X\n", address); superio_enter(); superio_select(W83627HF_LD_HWM); superio_outb(WINB_BASE_REG, address >> 8); superio_outb(WINB_BASE_REG+1, address & 0xff); superio_exit(); } superio_enter(); val= superio_inb(DEVID); if(val == W627_DEVID) kind = w83627hf; else if(val == W697_DEVID) kind = w83697hf; else if(val == W627THF_DEVID) kind = w83627thf; else if(val == W637_DEVID) kind = w83637hf; else { dev_info(&adapter->dev, "Unsupported chip (dev_id=0x%02X).\n", val); goto ERROR1; } superio_select(W83627HF_LD_HWM); if((val = 0x01 & superio_inb(WINB_ACT_REG)) == 0) superio_outb(WINB_ACT_REG, 1); superio_exit(); /* 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 w83627hf_{read,write}_value. */ if (!(data = kmalloc(sizeof(struct w83627hf_data), GFP_KERNEL))) { err = -ENOMEM; goto ERROR1; } memset(data, 0, sizeof(struct w83627hf_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 = &w83627hf_driver; new_client->flags = 0; if (kind == w83627hf) { client_name = "w83627hf"; } else if (kind == w83627thf) { client_name = "w83627thf"; } else if (kind == w83697hf) { client_name = "w83697hf"; } else if (kind == w83637hf) { client_name = "w83637hf"; } /* 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; data->lm75 = NULL; /* Initialize the chip */ w83627hf_init_client(new_client); /* A few vars need to be filled upon startup */ data->fan_min[0] = w83627hf_read_value(new_client, W83781D_REG_FAN_MIN(1)); data->fan_min[1] = w83627hf_read_value(new_client, W83781D_REG_FAN_MIN(2)); data->fan_min[2] = w83627hf_read_value(new_client, W83781D_REG_FAN_MIN(3)); /* Register sysfs hooks */ device_create_file_in(new_client, 0); if (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); if (kind != w83627thf && kind != w83637hf) { device_create_file_in(new_client, 5); device_create_file_in(new_client, 6); } 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 != 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); device_create_file_pwm(new_client, 1); device_create_file_pwm(new_client, 2); if (kind == w83627thf || kind == w83637hf) device_create_file_pwm(new_client, 3); device_create_file_sensor(new_client, 1); device_create_file_sensor(new_client, 2); if (kind != w83697hf) device_create_file_sensor(new_client, 3); return 0; ERROR2: kfree(data); ERROR1: release_region(address, WINB_EXTENT); ERROR0: return err;}static int w83627hf_detach_client(struct i2c_client *client){ int err; if ((err = i2c_detach_client(client))) { dev_err(&client->dev, "Client deregistration failed, client not detached.\n"); return err; } release_region(client->addr, WINB_EXTENT); kfree(i2c_get_clientdata(client)); return 0;}/* ISA access must always be locked explicitly! We ignore the W83781D BUSY flag at this moment - it could lead to deadlocks, would slow down the W83781D access and should not be necessary. There are some ugly typecasts here, but the good news is - they should nowhere else be necessary! */static int w83627hf_read_value(struct i2c_client *client, u16 reg){ struct w83627hf_data *data = i2c_get_clientdata(client); int res, word_sized; down(&data->lock); word_sized = (((reg & 0xff00) == 0x100) || ((reg & 0xff00) == 0x200)) && (((reg & 0x00ff) == 0x50) || ((reg & 0x00ff) == 0x53) || ((reg & 0x00ff) == 0x55)); if (reg & 0xff00) { outb_p(W83781D_REG_BANK, client->addr + W83781D_ADDR_REG_OFFSET); outb_p(reg >> 8, client->addr + W83781D_DATA_REG_OFFSET); } outb_p(reg & 0xff, client->addr + W83781D_ADDR_REG_OFFSET); res = inb_p(client->addr + W83781D_DATA_REG_OFFSET); if (word_sized) { outb_p((reg & 0xff) + 1, client->addr + W83781D_ADDR_REG_OFFSET); res = (res << 8) + inb_p(client->addr + W83781D_DATA_REG_OFFSET); } if (reg & 0xff00) { outb_p(W83781D_REG_BANK, client->addr + W83781D_ADDR_REG_OFFSET); outb_p(0, client->addr + W83781D_DATA_REG_OFFSET); } up(&data->lock); return res;}static int w83627thf_read_gpio5(struct i2c_client *client){ struct w83627hf_data *data = i2c_get_clientdata(client); int res, inv; down(&data->lock); superio_enter(); superio_select(W83627HF_LD_GPIO5); res = superio_inb(W83627THF_GPIO5_DR); inv = superio_inb(W83627THF_GPIO5_INVR); superio_exit(); up(&data->lock); return res;}static int w83627hf_write_value(struct i2c_client *client, u16 reg, u16 value){ struct w83627hf_data *data = i2c_get_clientdata(client); int word_sized; down(&data->lock); word_sized = (((reg & 0xff00) == 0x100) || ((reg & 0xff00) == 0x200)) && (((reg & 0x00ff) == 0x53) || ((reg & 0x00ff) == 0x55)); if (reg & 0xff00) { outb_p(W83781D_REG_BANK, client->addr + W83781D_ADDR_REG_OFFSET); outb_p(reg >> 8, client->addr + W83781D_DATA_REG_OFFSET); } outb_p(reg & 0xff, client->addr + W83781D_ADDR_REG_OFFSET); if (word_sized) { outb_p(value >> 8, client->addr + W83781D_DATA_REG_OFFSET); outb_p((reg & 0xff) + 1, client->addr + W83781D_ADDR_REG_OFFSET); } outb_p(value & 0xff, client->addr + W83781D_DATA_REG_OFFSET); if (reg & 0xff00) { outb_p(W83781D_REG_BANK, client->addr + W83781D_ADDR_REG_OFFSET); outb_p(0, client->addr + W83781D_DATA_REG_OFFSET); } up(&data->lock); return 0;}/* Called when we have found a new W83781D. It should set limits, etc. */static void w83627hf_init_client(struct i2c_client *client){ struct w83627hf_data *data = i2c_get_clientdata(client); int i; int type = data->type; u8 tmp; if(init) { /* save this register */ i = w83627hf_read_value(client, W83781D_REG_BEEP_CONFIG); /* Reset all except Watchdog values and last conversion values This sets fan-divs to 2, among others */ w83627hf_write_value(client, W83781D_REG_CONFIG, 0x80); /* Restore the register and disable power-on abnormal beep. This saves FAN 1/2/3 input/output values set by BIOS. */ w83627hf_write_value(client, W83781D_REG_BEEP_CONFIG, i | 0x80); /* Disable master beep-enable (reset turns it on). Individual beeps should be reset to off but for some reason disabling this bit helps some people not get beeped */ w83627hf_write_value(client, W83781D_REG_BEEP_INTS2, 0); } /* Minimize conflicts with other winbond i2c-only clients... */ /* disable i2c subclients... how to disable main i2c client?? */ /* force i2c address to relatively uncommon address */ w83627hf_write_value(client, W83781D_REG_I2C_SUBADDR, 0x89); w83627hf_write_value(client, W83781D_REG_I2C_ADDR, force_i2c); /* Read VID only once */ if (w83627hf == data->type || w83637hf == data->type) { int lo = w83627hf_read_value(client, W83781D_REG_VID_FANDIV); int hi = w83627hf_read_value(client, W83781D_REG_CHIPID); data->vid = (lo & 0x0f) | ((hi & 0x01) << 4); } else if (w83627thf == data->type) { data->vid = w83627thf_read_gpio5(client) & 0x1f; } /* Read VRM & OVT Config only once */ if (w83627thf == data->type || w83637hf == data->type) { data->vrm_ovt = w83627hf_read_value(client, W83627THF_REG_VRM_OVT_CFG); data->vrm = (data->vrm_ovt & 0x01) ? 90 : 82; } else { /* Convert VID to voltage based on default VRM */ data->vrm = DEFAULT_VRM; } tmp = w83627hf_read_value(client, W83781D_REG_SCFG1); for (i = 1; i <= 3; i++) { if (!(tmp & BIT_SCFG1[i - 1])) { data->sens[i - 1] = W83781D_DEFAULT_BETA; } else { if (w83627hf_read_value (client, W83781D_REG_SCFG2) & BIT_SCFG2[i - 1]) data->sens[i - 1] = 1; else data->sens[i - 1] = 2; } if ((type == w83697hf) && (i == 2)) break; } data->pwmenable[0] = 1; data->pwmenable[1] = 1; data->pwmenable[2] = 1; if(init) { if (type == w83627hf) { /* enable PWM2 control (can't hurt since PWM reg should have been reset to 0xff) */ w83627hf_write_value(client, W83627HF_REG_PWMCLK12, 0x19); } /* enable comparator mode for temp2 and temp3 so alarm indication will work correctly */ i = w83627hf_read_value(client, W83781D_REG_IRQ); if (!(i & 0x40)) w83627hf_write_value(client, W83781D_REG_IRQ, i | 0x40); } /* Start monitoring */ w83627hf_write_value(client, W83781D_REG_CONFIG, (w83627hf_read_value(client, W83781D_REG_CONFIG) & 0xf7) | 0x01);}static struct w83627hf_data *w83627hf_update_device(struct device *dev){ struct i2c_client *client = to_i2c_client(dev); struct w83627hf_data *data = i2c_get_clientdata(client); int i; down(&data->update_lock); if ((jiffies - data->last_updated > HZ + HZ / 2) || (jiffies < data->last_updated) || !data->valid) { for (i = 0; i <= 8; i++) { /* skip missing sensors */ if (((data->type == w83697hf) && (i == 1)) || ((data->type == w83627thf || data->type == w83637hf) && (i == 4 || i == 5))) continue; data->in[i] = w83627hf_read_value(client, W83781D_REG_IN(i)); data->in_min[i] = w83627hf_read_value(client, W83781D_REG_IN_MIN(i)); data->in_max[i] = w83627hf_read_value(client, W83781D_REG_IN_MAX(i)); } for (i = 1; i <= 3; i++) { data->fan[i - 1] = w83627hf_read_value(client, W83781D_REG_FAN(i)); data->fan_min[i - 1] = w83627hf_read_value(client, W83781D_REG_FAN_MIN(i)); } for (i = 1; i <= 3; i++) { u8 tmp = w83627hf_read_value(client, W836X7HF_REG_PWM(data->type, i)); /* bits 0-3 are reserved in 627THF */ if (data->type == w83627thf) tmp &= 0xf0; data->pwm[i - 1] = tmp; if(i == 2 && (data->type == w83627hf || data->type == w83697hf)) break; } data->temp = w83627hf_read_value(client, W83781D_REG_TEMP(1)); data->temp_max = w83627hf_read_value(client, W83781D_REG_TEMP_OVER(1)); data->temp_max_hyst = w83627hf_read_value(client, W83781D_REG_TEMP_HYST(1)); data->temp_add[0] = w83627hf_read_value(client, W83781D_REG_TEMP(2)); data->temp_max_add[0] = w83627hf_read_value(client, W83781D_REG_TEMP_OVER(2)); data->temp_max_hyst_add[0] = w83627hf_read_value(client, W83781D_REG_TEMP_HYST(2)); if (data->type != w83697hf) { data->temp_add[1] = w83627hf_read_value(client, W83781D_REG_TEMP(3)); data->temp_max_add[1] = w83627hf_read_value(client, W83781D_REG_TEMP_OVER(3)); data->temp_max_hyst_add[1] = w83627hf_read_value(client, W83781D_REG_TEMP_HYST(3)); } i = w83627hf_read_value(client, W83781D_REG_VID_FANDIV); data->fan_div[0] = (i >> 4) & 0x03; data->fan_div[1] = (i >> 6) & 0x03; if (data->type != w83697hf) { data->fan_div[2] = (w83627hf_read_value(client, W83781D_REG_PIN) >> 6) & 0x03; } i = w83627hf_read_value(client, W83781D_REG_VBAT); data->fan_div[0] |= (i >> 3) & 0x04; data->fan_div[1] |= (i >> 4) & 0x04; if (data->type != w83697hf) data->fan_div[2] |= (i >> 5) & 0x04; data->alarms = w83627hf_read_value(client, W83781D_REG_ALARM1) | (w83627hf_read_value(client, W83781D_REG_ALARM2) << 8) | (w83627hf_read_value(client, W83781D_REG_ALARM3) << 16); i = w83627hf_read_value(client, W83781D_REG_BEEP_INTS2); data->beep_enable = i >> 7; data->beep_mask = ((i & 0x7f) << 8) | w83627hf_read_value(client, W83781D_REG_BEEP_INTS1) | w83627hf_read_value(client, W83781D_REG_BEEP_INTS3) << 16; data->last_updated = jiffies; data->valid = 1; } up(&data->update_lock); return data;}static int __init sensors_w83627hf_init(void){ int addr; if (w83627hf_find(&addr)) { return -ENODEV; } normal_isa[0] = addr; return i2c_add_driver(&w83627hf_driver);}static void __exit sensors_w83627hf_exit(void){ i2c_del_driver(&w83627hf_driver);}MODULE_AUTHOR("Frodo Looijaard <frodol@dds.nl>, " "Philip Edelbrock <phil@netroedge.com>, " "and Mark Studebaker <mdsxyz123@yahoo.com>");MODULE_DESCRIPTION("W83627HF driver");MODULE_LICENSE("GPL");module_init(sensors_w83627hf_init);module_exit(sensors_w83627hf_exit);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -