w83627hf.c
来自「linux 内核源代码」· C语言 代码 · 共 1,707 行 · 第 1/4 页
C
1,707 行
sysfs_remove_group(&pdev->dev.kobj, &w83627hf_group_opt); platform_set_drvdata(pdev, NULL); kfree(data); res = platform_get_resource(pdev, IORESOURCE_IO, 0); release_region(res->start, WINB_REGION_SIZE); return 0;}/* Registers 0x50-0x5f are banked */static inline void w83627hf_set_bank(struct w83627hf_data *data, u16 reg){ if ((reg & 0x00f0) == 0x50) { outb_p(W83781D_REG_BANK, data->addr + W83781D_ADDR_REG_OFFSET); outb_p(reg >> 8, data->addr + W83781D_DATA_REG_OFFSET); }}/* Not strictly necessary, but play it safe for now */static inline void w83627hf_reset_bank(struct w83627hf_data *data, u16 reg){ if (reg & 0xff00) { outb_p(W83781D_REG_BANK, data->addr + W83781D_ADDR_REG_OFFSET); outb_p(0, data->addr + W83781D_DATA_REG_OFFSET); }}static int w83627hf_read_value(struct w83627hf_data *data, u16 reg){ int res, word_sized; mutex_lock(&data->lock); word_sized = (((reg & 0xff00) == 0x100) || ((reg & 0xff00) == 0x200)) && (((reg & 0x00ff) == 0x50) || ((reg & 0x00ff) == 0x53) || ((reg & 0x00ff) == 0x55)); w83627hf_set_bank(data, reg); outb_p(reg & 0xff, data->addr + W83781D_ADDR_REG_OFFSET); res = inb_p(data->addr + W83781D_DATA_REG_OFFSET); if (word_sized) { outb_p((reg & 0xff) + 1, data->addr + W83781D_ADDR_REG_OFFSET); res = (res << 8) + inb_p(data->addr + W83781D_DATA_REG_OFFSET); } w83627hf_reset_bank(data, reg); mutex_unlock(&data->lock); return res;}static int __devinit w83627thf_read_gpio5(struct platform_device *pdev){ int res = 0xff, sel; superio_enter(); superio_select(W83627HF_LD_GPIO5); /* Make sure these GPIO pins are enabled */ if (!(superio_inb(W83627THF_GPIO5_EN) & (1<<3))) { dev_dbg(&pdev->dev, "GPIO5 disabled, no VID function\n"); goto exit; } /* Make sure the pins are configured for input There must be at least five (VRM 9), and possibly 6 (VRM 10) */ sel = superio_inb(W83627THF_GPIO5_IOSR) & 0x3f; if ((sel & 0x1f) != 0x1f) { dev_dbg(&pdev->dev, "GPIO5 not configured for VID " "function\n"); goto exit; } dev_info(&pdev->dev, "Reading VID from GPIO5\n"); res = superio_inb(W83627THF_GPIO5_DR) & sel;exit: superio_exit(); return res;}static int __devinit w83687thf_read_vid(struct platform_device *pdev){ int res = 0xff; superio_enter(); superio_select(W83627HF_LD_HWM); /* Make sure these GPIO pins are enabled */ if (!(superio_inb(W83687THF_VID_EN) & (1 << 2))) { dev_dbg(&pdev->dev, "VID disabled, no VID function\n"); goto exit; } /* Make sure the pins are configured for input */ if (!(superio_inb(W83687THF_VID_CFG) & (1 << 4))) { dev_dbg(&pdev->dev, "VID configured as output, " "no VID function\n"); goto exit; } res = superio_inb(W83687THF_VID_DATA) & 0x3f;exit: superio_exit(); return res;}static int w83627hf_write_value(struct w83627hf_data *data, u16 reg, u16 value){ int word_sized; mutex_lock(&data->lock); word_sized = (((reg & 0xff00) == 0x100) || ((reg & 0xff00) == 0x200)) && (((reg & 0x00ff) == 0x53) || ((reg & 0x00ff) == 0x55)); w83627hf_set_bank(data, reg); outb_p(reg & 0xff, data->addr + W83781D_ADDR_REG_OFFSET); if (word_sized) { outb_p(value >> 8, data->addr + W83781D_DATA_REG_OFFSET); outb_p((reg & 0xff) + 1, data->addr + W83781D_ADDR_REG_OFFSET); } outb_p(value & 0xff, data->addr + W83781D_DATA_REG_OFFSET); w83627hf_reset_bank(data, reg); mutex_unlock(&data->lock); return 0;}static void __devinit w83627hf_init_device(struct platform_device *pdev){ struct w83627hf_data *data = platform_get_drvdata(pdev); int i; enum chips type = data->type; u8 tmp; if (reset) { /* Resetting the chip has been the default for a long time, but repeatedly caused problems (fans going to full speed...) so it is now optional. It might even go away if nobody reports it as being useful, as I see very little reason why this would be needed at all. */ dev_info(&pdev->dev, "If reset=1 solved a problem you were " "having, please report!\n"); /* save this register */ i = w83627hf_read_value(data, W83781D_REG_BEEP_CONFIG); /* Reset all except Watchdog values and last conversion values This sets fan-divs to 2, among others */ w83627hf_write_value(data, 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(data, 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(data, 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(data, W83781D_REG_I2C_SUBADDR, 0x89); w83627hf_write_value(data, W83781D_REG_I2C_ADDR, force_i2c); /* Read VID only once */ if (type == w83627hf || type == w83637hf) { int lo = w83627hf_read_value(data, W83781D_REG_VID_FANDIV); int hi = w83627hf_read_value(data, W83781D_REG_CHIPID); data->vid = (lo & 0x0f) | ((hi & 0x01) << 4); } else if (type == w83627thf) { data->vid = w83627thf_read_gpio5(pdev); } else if (type == w83687thf) { data->vid = w83687thf_read_vid(pdev); } /* Read VRM & OVT Config only once */ if (type == w83627thf || type == w83637hf || type == w83687thf) { data->vrm_ovt = w83627hf_read_value(data, W83627THF_REG_VRM_OVT_CFG); } tmp = w83627hf_read_value(data, W83781D_REG_SCFG1); for (i = 1; i <= 3; i++) { if (!(tmp & BIT_SCFG1[i - 1])) { data->sens[i - 1] = 4; } else { if (w83627hf_read_value (data, W83781D_REG_SCFG2) & BIT_SCFG2[i - 1]) data->sens[i - 1] = 1; else data->sens[i - 1] = 2; } if ((type == w83697hf) && (i == 2)) break; } if(init) { /* Enable temp2 */ tmp = w83627hf_read_value(data, W83627HF_REG_TEMP2_CONFIG); if (tmp & 0x01) { dev_warn(&pdev->dev, "Enabling temp2, readings " "might not make sense\n"); w83627hf_write_value(data, W83627HF_REG_TEMP2_CONFIG, tmp & 0xfe); } /* Enable temp3 */ if (type != w83697hf) { tmp = w83627hf_read_value(data, W83627HF_REG_TEMP3_CONFIG); if (tmp & 0x01) { dev_warn(&pdev->dev, "Enabling temp3, " "readings might not make sense\n"); w83627hf_write_value(data, W83627HF_REG_TEMP3_CONFIG, tmp & 0xfe); } } } /* Start monitoring */ w83627hf_write_value(data, W83781D_REG_CONFIG, (w83627hf_read_value(data, W83781D_REG_CONFIG) & 0xf7) | 0x01);}static void w83627hf_update_fan_div(struct w83627hf_data *data){ int reg; reg = w83627hf_read_value(data, W83781D_REG_VID_FANDIV); data->fan_div[0] = (reg >> 4) & 0x03; data->fan_div[1] = (reg >> 6) & 0x03; if (data->type != w83697hf) { data->fan_div[2] = (w83627hf_read_value(data, W83781D_REG_PIN) >> 6) & 0x03; } reg = w83627hf_read_value(data, W83781D_REG_VBAT); data->fan_div[0] |= (reg >> 3) & 0x04; data->fan_div[1] |= (reg >> 4) & 0x04; if (data->type != w83697hf) data->fan_div[2] |= (reg >> 5) & 0x04;}static struct w83627hf_data *w83627hf_update_device(struct device *dev){ struct w83627hf_data *data = dev_get_drvdata(dev); int i, num_temps = (data->type == w83697hf) ? 2 : 3; mutex_lock(&data->update_lock); if (time_after(jiffies, data->last_updated + HZ + HZ / 2) || !data->valid) { for (i = 0; i <= 8; i++) { /* skip missing sensors */ if (((data->type == w83697hf) && (i == 1)) || ((data->type != w83627hf && data->type != w83697hf) && (i == 5 || i == 6))) continue; data->in[i] = w83627hf_read_value(data, W83781D_REG_IN(i)); data->in_min[i] = w83627hf_read_value(data, W83781D_REG_IN_MIN(i)); data->in_max[i] = w83627hf_read_value(data, W83781D_REG_IN_MAX(i)); } for (i = 0; i <= 2; i++) { data->fan[i] = w83627hf_read_value(data, W83627HF_REG_FAN(i)); data->fan_min[i] = w83627hf_read_value(data, W83627HF_REG_FAN_MIN(i)); } for (i = 0; i <= 2; i++) { u8 tmp = w83627hf_read_value(data, W836X7HF_REG_PWM(data->type, i)); /* bits 0-3 are reserved in 627THF */ if (data->type == w83627thf) tmp &= 0xf0; data->pwm[i] = tmp; if (i == 1 && (data->type == w83627hf || data->type == w83697hf)) break; } if (data->type == w83627hf) { u8 tmp = w83627hf_read_value(data, W83627HF_REG_PWM_FREQ); data->pwm_freq[0] = tmp & 0x07; data->pwm_freq[1] = (tmp >> 4) & 0x07; } else if (data->type != w83627thf) { for (i = 1; i <= 3; i++) { data->pwm_freq[i - 1] = w83627hf_read_value(data, W83637HF_REG_PWM_FREQ[i - 1]); if (i == 2 && (data->type == w83697hf)) break; } } for (i = 0; i < num_temps; i++) { data->temp[i] = w83627hf_read_value( data, w83627hf_reg_temp[i]); data->temp_max[i] = w83627hf_read_value( data, w83627hf_reg_temp_over[i]); data->temp_max_hyst[i] = w83627hf_read_value( data, w83627hf_reg_temp_hyst[i]); } w83627hf_update_fan_div(data); data->alarms = w83627hf_read_value(data, W83781D_REG_ALARM1) | (w83627hf_read_value(data, W83781D_REG_ALARM2) << 8) | (w83627hf_read_value(data, W83781D_REG_ALARM3) << 16); i = w83627hf_read_value(data, W83781D_REG_BEEP_INTS2); data->beep_enable = i >> 7; data->beep_mask = ((i & 0x7f) << 8) | w83627hf_read_value(data, W83781D_REG_BEEP_INTS1) | w83627hf_read_value(data, W83781D_REG_BEEP_INTS3) << 16; data->last_updated = jiffies; data->valid = 1; } mutex_unlock(&data->update_lock); return data;}static int __init w83627hf_device_add(unsigned short address, const struct w83627hf_sio_data *sio_data){ struct resource res = { .start = address + WINB_REGION_OFFSET, .end = address + WINB_REGION_OFFSET + WINB_REGION_SIZE - 1, .name = DRVNAME, .flags = IORESOURCE_IO, }; int err; pdev = platform_device_alloc(DRVNAME, address); if (!pdev) { err = -ENOMEM; printk(KERN_ERR DRVNAME ": Device allocation failed\n"); goto exit; } err = platform_device_add_resources(pdev, &res, 1); if (err) { printk(KERN_ERR DRVNAME ": Device resource addition failed " "(%d)\n", err); goto exit_device_put; } err = platform_device_add_data(pdev, sio_data, sizeof(struct w83627hf_sio_data)); if (err) { printk(KERN_ERR DRVNAME ": Platform data allocation failed\n"); goto exit_device_put; } err = platform_device_add(pdev); if (err) { printk(KERN_ERR DRVNAME ": Device addition failed (%d)\n", err); goto exit_device_put; } return 0;exit_device_put: platform_device_put(pdev);exit: return err;}static int __init sensors_w83627hf_init(void){ int err; unsigned short address; struct w83627hf_sio_data sio_data; if (w83627hf_find(0x2e, &address, &sio_data) && w83627hf_find(0x4e, &address, &sio_data)) return -ENODEV; err = platform_driver_register(&w83627hf_driver); if (err) goto exit; /* Sets global pdev as a side effect */ err = w83627hf_device_add(address, &sio_data); if (err) goto exit_driver; return 0;exit_driver: platform_driver_unregister(&w83627hf_driver);exit: return err;}static void __exit sensors_w83627hf_exit(void){ platform_device_unregister(pdev); platform_driver_unregister(&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 + =
减小字号Ctrl + -
显示快捷键?