w83627ehf.c
来自「linux 内核源代码」· C语言 代码 · 共 1,579 行 · 第 1/4 页
C
1,579 行
device_remove_file(dev, &sda_fan_alarm[i].dev_attr); device_remove_file(dev, &sda_fan_div[i].dev_attr); device_remove_file(dev, &sda_fan_min[i].dev_attr); } for (i = 0; i < 4; i++) { device_remove_file(dev, &sda_pwm[i].dev_attr); device_remove_file(dev, &sda_pwm_mode[i].dev_attr); device_remove_file(dev, &sda_pwm_enable[i].dev_attr); device_remove_file(dev, &sda_target_temp[i].dev_attr); device_remove_file(dev, &sda_tolerance[i].dev_attr); } for (i = 0; i < ARRAY_SIZE(sda_temp); i++) device_remove_file(dev, &sda_temp[i].dev_attr); device_remove_file(dev, &dev_attr_name); if (data->vid != 0x3f) device_remove_file(dev, &dev_attr_cpu0_vid);}/* Get the monitoring functions started */static inline void __devinit w83627ehf_init_device(struct w83627ehf_data *data){ int i; u8 tmp, diode; /* Start monitoring is needed */ tmp = w83627ehf_read_value(data, W83627EHF_REG_CONFIG); if (!(tmp & 0x01)) w83627ehf_write_value(data, W83627EHF_REG_CONFIG, tmp | 0x01); /* Enable temp2 and temp3 if needed */ for (i = 0; i < 2; i++) { tmp = w83627ehf_read_value(data, W83627EHF_REG_TEMP_CONFIG[i]); if (tmp & 0x01) w83627ehf_write_value(data, W83627EHF_REG_TEMP_CONFIG[i], tmp & 0xfe); } /* Enable VBAT monitoring if needed */ tmp = w83627ehf_read_value(data, W83627EHF_REG_VBAT); if (!(tmp & 0x01)) w83627ehf_write_value(data, W83627EHF_REG_VBAT, tmp | 0x01); /* Get thermal sensor types */ diode = w83627ehf_read_value(data, W83627EHF_REG_DIODE); for (i = 0; i < 3; i++) { if ((tmp & (0x02 << i))) data->temp_type[i] = (diode & (0x10 << i)) ? 1 : 2; else data->temp_type[i] = 4; /* thermistor */ }}static int __devinit w83627ehf_probe(struct platform_device *pdev){ struct device *dev = &pdev->dev; struct w83627ehf_sio_data *sio_data = dev->platform_data; struct w83627ehf_data *data; struct resource *res; u8 fan4pin, fan5pin, en_vrm10; int i, err = 0; res = platform_get_resource(pdev, IORESOURCE_IO, 0); if (!request_region(res->start, IOREGION_LENGTH, DRVNAME)) { err = -EBUSY; dev_err(dev, "Failed to request region 0x%lx-0x%lx\n", (unsigned long)res->start, (unsigned long)res->start + IOREGION_LENGTH - 1); goto exit; } if (!(data = kzalloc(sizeof(struct w83627ehf_data), GFP_KERNEL))) { err = -ENOMEM; goto exit_release; } data->addr = res->start; mutex_init(&data->lock); mutex_init(&data->update_lock); data->name = w83627ehf_device_names[sio_data->kind]; platform_set_drvdata(pdev, data); /* 627EHG and 627EHF have 10 voltage inputs; DHG has 9 */ data->in_num = (sio_data->kind == w83627dhg) ? 9 : 10; /* Initialize the chip */ w83627ehf_init_device(data); data->vrm = vid_which_vrm(); superio_enter(sio_data->sioreg); /* Read VID value */ superio_select(sio_data->sioreg, W83627EHF_LD_HWM); if (superio_inb(sio_data->sioreg, SIO_REG_VID_CTRL) & 0x80) { /* Set VID input sensibility if needed. In theory the BIOS should have set it, but in practice it's not always the case. We only do it for the W83627EHF/EHG because the W83627DHG is more complex in this respect. */ if (sio_data->kind == w83627ehf) { en_vrm10 = superio_inb(sio_data->sioreg, SIO_REG_EN_VRM10); if ((en_vrm10 & 0x08) && data->vrm == 90) { dev_warn(dev, "Setting VID input voltage to " "TTL\n"); superio_outb(sio_data->sioreg, SIO_REG_EN_VRM10, en_vrm10 & ~0x08); } else if (!(en_vrm10 & 0x08) && data->vrm == 100) { dev_warn(dev, "Setting VID input voltage to " "VRM10\n"); superio_outb(sio_data->sioreg, SIO_REG_EN_VRM10, en_vrm10 | 0x08); } } data->vid = superio_inb(sio_data->sioreg, SIO_REG_VID_DATA) & 0x3f; } else { dev_info(dev, "VID pins in output mode, CPU VID not " "available\n"); data->vid = 0x3f; } /* fan4 and fan5 share some pins with the GPIO and serial flash */ fan5pin = superio_inb(sio_data->sioreg, 0x24) & 0x2; fan4pin = superio_inb(sio_data->sioreg, 0x29) & 0x6; superio_exit(sio_data->sioreg); /* It looks like fan4 and fan5 pins can be alternatively used as fan on/off switches, but fan5 control is write only :/ We assume that if the serial interface is disabled, designers connected fan5 as input unless they are emitting log 1, which is not the default. */ data->has_fan = 0x07; /* fan1, fan2 and fan3 */ i = w83627ehf_read_value(data, W83627EHF_REG_FANDIV1); if ((i & (1 << 2)) && (!fan4pin)) data->has_fan |= (1 << 3); if (!(i & (1 << 1)) && (!fan5pin)) data->has_fan |= (1 << 4); /* Read fan clock dividers immediately */ w83627ehf_update_fan_div(data); /* Register sysfs hooks */ for (i = 0; i < ARRAY_SIZE(sda_sf3_arrays); i++) if ((err = device_create_file(dev, &sda_sf3_arrays[i].dev_attr))) goto exit_remove; /* if fan4 is enabled create the sf3 files for it */ if (data->has_fan & (1 << 3)) for (i = 0; i < ARRAY_SIZE(sda_sf3_arrays_fan4); i++) { if ((err = device_create_file(dev, &sda_sf3_arrays_fan4[i].dev_attr))) goto exit_remove; } for (i = 0; i < data->in_num; i++) if ((err = device_create_file(dev, &sda_in_input[i].dev_attr)) || (err = device_create_file(dev, &sda_in_alarm[i].dev_attr)) || (err = device_create_file(dev, &sda_in_min[i].dev_attr)) || (err = device_create_file(dev, &sda_in_max[i].dev_attr))) goto exit_remove; for (i = 0; i < 5; i++) { if (data->has_fan & (1 << i)) { if ((err = device_create_file(dev, &sda_fan_input[i].dev_attr)) || (err = device_create_file(dev, &sda_fan_alarm[i].dev_attr)) || (err = device_create_file(dev, &sda_fan_div[i].dev_attr)) || (err = device_create_file(dev, &sda_fan_min[i].dev_attr))) goto exit_remove; if (i < 4 && /* w83627ehf only has 4 pwm */ ((err = device_create_file(dev, &sda_pwm[i].dev_attr)) || (err = device_create_file(dev, &sda_pwm_mode[i].dev_attr)) || (err = device_create_file(dev, &sda_pwm_enable[i].dev_attr)) || (err = device_create_file(dev, &sda_target_temp[i].dev_attr)) || (err = device_create_file(dev, &sda_tolerance[i].dev_attr)))) goto exit_remove; } } for (i = 0; i < ARRAY_SIZE(sda_temp); i++) if ((err = device_create_file(dev, &sda_temp[i].dev_attr))) goto exit_remove; err = device_create_file(dev, &dev_attr_name); if (err) goto exit_remove; if (data->vid != 0x3f) { err = device_create_file(dev, &dev_attr_cpu0_vid); if (err) goto exit_remove; } data->hwmon_dev = hwmon_device_register(dev); if (IS_ERR(data->hwmon_dev)) { err = PTR_ERR(data->hwmon_dev); goto exit_remove; } return 0;exit_remove: w83627ehf_device_remove_files(dev); kfree(data); platform_set_drvdata(pdev, NULL);exit_release: release_region(res->start, IOREGION_LENGTH);exit: return err;}static int __devexit w83627ehf_remove(struct platform_device *pdev){ struct w83627ehf_data *data = platform_get_drvdata(pdev); hwmon_device_unregister(data->hwmon_dev); w83627ehf_device_remove_files(&pdev->dev); release_region(data->addr, IOREGION_LENGTH); platform_set_drvdata(pdev, NULL); kfree(data); return 0;}static struct platform_driver w83627ehf_driver = { .driver = { .owner = THIS_MODULE, .name = DRVNAME, }, .probe = w83627ehf_probe, .remove = __devexit_p(w83627ehf_remove),};/* w83627ehf_find() looks for a '627 in the Super-I/O config space */static int __init w83627ehf_find(int sioaddr, unsigned short *addr, struct w83627ehf_sio_data *sio_data){ static const char __initdata sio_name_W83627EHF[] = "W83627EHF"; static const char __initdata sio_name_W83627EHG[] = "W83627EHG"; static const char __initdata sio_name_W83627DHG[] = "W83627DHG"; u16 val; const char *sio_name; superio_enter(sioaddr); val = (superio_inb(sioaddr, SIO_REG_DEVID) << 8) | superio_inb(sioaddr, SIO_REG_DEVID + 1); switch (val & SIO_ID_MASK) { case SIO_W83627EHF_ID: sio_data->kind = w83627ehf; sio_name = sio_name_W83627EHF; break; case SIO_W83627EHG_ID: sio_data->kind = w83627ehf; sio_name = sio_name_W83627EHG; break; case SIO_W83627DHG_ID: sio_data->kind = w83627dhg; sio_name = sio_name_W83627DHG; break; default: if (val != 0xffff) pr_debug(DRVNAME ": unsupported chip ID: 0x%04x\n", val); superio_exit(sioaddr); return -ENODEV; } /* We have a known chip, find the HWM I/O address */ superio_select(sioaddr, W83627EHF_LD_HWM); val = (superio_inb(sioaddr, SIO_REG_ADDR) << 8) | superio_inb(sioaddr, SIO_REG_ADDR + 1); *addr = val & IOREGION_ALIGNMENT; if (*addr == 0) { printk(KERN_ERR DRVNAME ": Refusing to enable a Super-I/O " "device with a base I/O port 0.\n"); superio_exit(sioaddr); return -ENODEV; } /* Activate logical device if needed */ val = superio_inb(sioaddr, SIO_REG_ENABLE); if (!(val & 0x01)) { printk(KERN_WARNING DRVNAME ": Forcibly enabling Super-I/O. " "Sensor is probably unusable.\n"); superio_outb(sioaddr, SIO_REG_ENABLE, val | 0x01); } superio_exit(sioaddr); pr_info(DRVNAME ": Found %s chip at %#x\n", sio_name, *addr); sio_data->sioreg = sioaddr; return 0;}/* when Super-I/O functions move to a separate file, the Super-I/O * bus will manage the lifetime of the device and this module will only keep * track of the w83627ehf driver. But since we platform_device_alloc(), we * must keep track of the device */static struct platform_device *pdev;static int __init sensors_w83627ehf_init(void){ int err; unsigned short address; struct resource res; struct w83627ehf_sio_data sio_data; /* initialize sio_data->kind and sio_data->sioreg. * * when Super-I/O functions move to a separate file, the Super-I/O * driver will probe 0x2e and 0x4e and auto-detect the presence of a * w83627ehf hardware monitor, and call probe() */ if (w83627ehf_find(0x2e, &address, &sio_data) && w83627ehf_find(0x4e, &address, &sio_data)) return -ENODEV; err = platform_driver_register(&w83627ehf_driver); if (err) goto exit; if (!(pdev = platform_device_alloc(DRVNAME, address))) { err = -ENOMEM; printk(KERN_ERR DRVNAME ": Device allocation failed\n"); goto exit_unregister; } err = platform_device_add_data(pdev, &sio_data, sizeof(struct w83627ehf_sio_data)); if (err) { printk(KERN_ERR DRVNAME ": Platform data allocation failed\n"); goto exit_device_put; } memset(&res, 0, sizeof(res)); res.name = DRVNAME; res.start = address + IOREGION_OFFSET; res.end = address + IOREGION_OFFSET + IOREGION_LENGTH - 1; res.flags = IORESOURCE_IO; 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; } /* platform_device_add calls probe() */ 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_unregister: platform_driver_unregister(&w83627ehf_driver);exit: return err;}static void __exit sensors_w83627ehf_exit(void){ platform_device_unregister(pdev); platform_driver_unregister(&w83627ehf_driver);}MODULE_AUTHOR("Jean Delvare <khali@linux-fr.org>");MODULE_DESCRIPTION("W83627EHF driver");MODULE_LICENSE("GPL");module_init(sensors_w83627ehf_init);module_exit(sensors_w83627ehf_exit);
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?