📄 sis5595.c
字号:
} switch (nr) { case 0: reg = (reg & 0xcf) | (data->fan_div[nr] << 4); break; case 1: reg = (reg & 0x3f) | (data->fan_div[nr] << 6); break; } sis5595_write_value(client, SIS5595_REG_FANDIV, reg); data->fan_min[nr] = FAN_TO_REG(min, DIV_FROM_REG(data->fan_div[nr])); sis5595_write_value(client, SIS5595_REG_FAN_MIN(nr), data->fan_min[nr]); up(&data->update_lock); return count;}#define show_fan_offset(offset) \static ssize_t show_fan_##offset (struct device *dev, char *buf) \{ \ return show_fan(dev, buf, offset - 1); \} \static ssize_t show_fan_##offset##_min (struct device *dev, char *buf) \{ \ return show_fan_min(dev, buf, offset - 1); \} \static ssize_t show_fan_##offset##_div (struct device *dev, char *buf) \{ \ return show_fan_div(dev, buf, offset - 1); \} \static ssize_t set_fan_##offset##_min (struct device *dev, \ const char *buf, size_t count) \{ \ return set_fan_min(dev, buf, count, offset - 1); \} \static DEVICE_ATTR(fan##offset##_input, S_IRUGO, show_fan_##offset, NULL);\static DEVICE_ATTR(fan##offset##_min, S_IRUGO | S_IWUSR, \ show_fan_##offset##_min, set_fan_##offset##_min);show_fan_offset(1);show_fan_offset(2);static ssize_t set_fan_1_div(struct device *dev, const char *buf, size_t count){ return set_fan_div(dev, buf, count, 0) ;}static ssize_t set_fan_2_div(struct device *dev, const char *buf, size_t count){ return set_fan_div(dev, buf, count, 1) ;}static DEVICE_ATTR(fan1_div, S_IRUGO | S_IWUSR, show_fan_1_div, set_fan_1_div);static DEVICE_ATTR(fan2_div, S_IRUGO | S_IWUSR, show_fan_2_div, set_fan_2_div);/* Alarms */static ssize_t show_alarms(struct device *dev, char *buf){ struct sis5595_data *data = sis5595_update_device(dev); return sprintf(buf, "%d\n", data->alarms);}static DEVICE_ATTR(alarms, S_IRUGO, show_alarms, NULL); /* This is called when the module is loaded */static int sis5595_attach_adapter(struct i2c_adapter *adapter){ if (!(adapter->class & I2C_CLASS_HWMON)) return 0; return i2c_detect(adapter, &addr_data, sis5595_detect);}int sis5595_detect(struct i2c_adapter *adapter, int address, int kind){ int err = 0; int i; struct i2c_client *new_client; struct sis5595_data *data; char val; u16 a; /* Make sure we are probing the ISA bus!! */ if (!i2c_is_isa_adapter(adapter)) goto exit; if (force_addr) address = force_addr & ~(SIS5595_EXTENT - 1); /* Reserve the ISA region */ if (!request_region(address, SIS5595_EXTENT, sis5595_driver.name)) { err = -EBUSY; goto exit; } if (force_addr) { dev_warn(&adapter->dev, "forcing ISA address 0x%04X\n", address); if (PCIBIOS_SUCCESSFUL != pci_write_config_word(s_bridge, SIS5595_BASE_REG, address)) goto exit_release; if (PCIBIOS_SUCCESSFUL != pci_read_config_word(s_bridge, SIS5595_BASE_REG, &a)) goto exit_release; if ((a & ~(SIS5595_EXTENT - 1)) != address) /* doesn't work for some chips? */ goto exit_release; } if (PCIBIOS_SUCCESSFUL != pci_read_config_byte(s_bridge, SIS5595_ENABLE_REG, &val)) { goto exit_release; } if ((val & 0x80) == 0) { if (PCIBIOS_SUCCESSFUL != pci_write_config_byte(s_bridge, SIS5595_ENABLE_REG, val | 0x80)) goto exit_release; if (PCIBIOS_SUCCESSFUL != pci_read_config_byte(s_bridge, SIS5595_ENABLE_REG, &val)) goto exit_release; if ((val & 0x80) == 0) /* doesn't work for some chips! */ goto exit_release; } if (!(data = kmalloc(sizeof(struct sis5595_data), GFP_KERNEL))) { err = -ENOMEM; goto exit_release; } memset(data, 0, sizeof(struct sis5595_data)); new_client = &data->client; new_client->addr = address; init_MUTEX(&data->lock); i2c_set_clientdata(new_client, data); new_client->adapter = adapter; new_client->driver = &sis5595_driver; new_client->flags = 0; /* Check revision and pin registers to determine whether 4 or 5 voltages */ pci_read_config_byte(s_bridge, SIS5595_REVISION_REG, &(data->revision)); /* 4 voltages, 1 temp */ data->maxins = 3; if (data->revision >= REV2MIN) { pci_read_config_byte(s_bridge, SIS5595_PIN_REG, &val); if (!(val & 0x80)) /* 5 voltages, no temps */ data->maxins = 4; } /* Fill in the remaining client fields and put it into the global list */ strlcpy(new_client->name, "sis5595", I2C_NAME_SIZE); 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 exit_free; /* Initialize the SIS5595 chip */ sis5595_init_client(new_client); /* A few vars need to be filled upon startup */ for (i = 0; i < 2; i++) { data->fan_min[i] = sis5595_read_value(new_client, SIS5595_REG_FAN_MIN(i)); } /* Register sysfs hooks */ device_create_file(&new_client->dev, &dev_attr_in0_input); device_create_file(&new_client->dev, &dev_attr_in0_min); device_create_file(&new_client->dev, &dev_attr_in0_max); device_create_file(&new_client->dev, &dev_attr_in1_input); device_create_file(&new_client->dev, &dev_attr_in1_min); device_create_file(&new_client->dev, &dev_attr_in1_max); device_create_file(&new_client->dev, &dev_attr_in2_input); device_create_file(&new_client->dev, &dev_attr_in2_min); device_create_file(&new_client->dev, &dev_attr_in2_max); device_create_file(&new_client->dev, &dev_attr_in3_input); device_create_file(&new_client->dev, &dev_attr_in3_min); device_create_file(&new_client->dev, &dev_attr_in3_max); if (data->maxins == 4) { device_create_file(&new_client->dev, &dev_attr_in4_input); device_create_file(&new_client->dev, &dev_attr_in4_min); device_create_file(&new_client->dev, &dev_attr_in4_max); } device_create_file(&new_client->dev, &dev_attr_fan1_input); device_create_file(&new_client->dev, &dev_attr_fan1_min); device_create_file(&new_client->dev, &dev_attr_fan1_div); device_create_file(&new_client->dev, &dev_attr_fan2_input); device_create_file(&new_client->dev, &dev_attr_fan2_min); device_create_file(&new_client->dev, &dev_attr_fan2_div); device_create_file(&new_client->dev, &dev_attr_alarms); if (data->maxins == 3) { device_create_file(&new_client->dev, &dev_attr_temp1_input); device_create_file(&new_client->dev, &dev_attr_temp1_max); device_create_file(&new_client->dev, &dev_attr_temp1_max_hyst); } return 0; exit_free: kfree(data);exit_release: release_region(address, SIS5595_EXTENT);exit: return err;}static int sis5595_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; } if (i2c_is_isa_client(client)) release_region(client->addr, SIS5595_EXTENT); kfree(i2c_get_clientdata(client)); return 0;}/* ISA access must be locked explicitly. */static int sis5595_read_value(struct i2c_client *client, u8 reg){ int res; struct sis5595_data *data = i2c_get_clientdata(client); down(&data->lock); outb_p(reg, client->addr + SIS5595_ADDR_REG_OFFSET); res = inb_p(client->addr + SIS5595_DATA_REG_OFFSET); up(&data->lock); return res;}static int sis5595_write_value(struct i2c_client *client, u8 reg, u8 value){ struct sis5595_data *data = i2c_get_clientdata(client); down(&data->lock); outb_p(reg, client->addr + SIS5595_ADDR_REG_OFFSET); outb_p(value, client->addr + SIS5595_DATA_REG_OFFSET); up(&data->lock); return 0;}/* Called when we have found a new SIS5595. */static void sis5595_init_client(struct i2c_client *client){ u8 config = sis5595_read_value(client, SIS5595_REG_CONFIG); if (!(config & 0x01)) sis5595_write_value(client, SIS5595_REG_CONFIG, (config & 0xf7) | 0x01);}static struct sis5595_data *sis5595_update_device(struct device *dev){ struct i2c_client *client = to_i2c_client(dev); struct sis5595_data *data = i2c_get_clientdata(client); int i; down(&data->update_lock); if (time_after(jiffies, data->last_updated + HZ + HZ / 2) || !data->valid) { for (i = 0; i <= data->maxins; i++) { data->in[i] = sis5595_read_value(client, SIS5595_REG_IN(i)); data->in_min[i] = sis5595_read_value(client, SIS5595_REG_IN_MIN(i)); data->in_max[i] = sis5595_read_value(client, SIS5595_REG_IN_MAX(i)); } for (i = 0; i < 2; i++) { data->fan[i] = sis5595_read_value(client, SIS5595_REG_FAN(i)); data->fan_min[i] = sis5595_read_value(client, SIS5595_REG_FAN_MIN(i)); } if (data->maxins == 3) { data->temp = sis5595_read_value(client, SIS5595_REG_TEMP); data->temp_over = sis5595_read_value(client, SIS5595_REG_TEMP_OVER); data->temp_hyst = sis5595_read_value(client, SIS5595_REG_TEMP_HYST); } i = sis5595_read_value(client, SIS5595_REG_FANDIV); data->fan_div[0] = (i >> 4) & 0x03; data->fan_div[1] = i >> 6; data->alarms = sis5595_read_value(client, SIS5595_REG_ALARM1) | (sis5595_read_value(client, SIS5595_REG_ALARM2) << 8); data->last_updated = jiffies; data->valid = 1; } up(&data->update_lock); return data;}static struct pci_device_id sis5595_pci_ids[] = { { PCI_DEVICE(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_503) }, { 0, }};MODULE_DEVICE_TABLE(pci, sis5595_pci_ids);static int blacklist[] __devinitdata = { PCI_DEVICE_ID_SI_540, PCI_DEVICE_ID_SI_550, PCI_DEVICE_ID_SI_630, PCI_DEVICE_ID_SI_645, PCI_DEVICE_ID_SI_730, PCI_DEVICE_ID_SI_735, PCI_DEVICE_ID_SI_5511, /* 5513 chip has the 0008 device but that ID shows up in other chips so we use the 5511 ID for recognition */ PCI_DEVICE_ID_SI_5597, PCI_DEVICE_ID_SI_5598, 0 };static int __devinit sis5595_pci_probe(struct pci_dev *dev, const struct pci_device_id *id){ u16 val; int *i; int addr = 0; for (i = blacklist; *i != 0; i++) { struct pci_dev *dev; dev = pci_get_device(PCI_VENDOR_ID_SI, *i, NULL); if (dev) { dev_err(&dev->dev, "Looked for SIS5595 but found unsupported device %.4x\n", *i); pci_dev_put(dev); return -ENODEV; } } if (PCIBIOS_SUCCESSFUL != pci_read_config_word(dev, SIS5595_BASE_REG, &val)) return -ENODEV; addr = val & ~(SIS5595_EXTENT - 1); if (addr == 0 && force_addr == 0) { dev_err(&dev->dev, "Base address not set - upgrade BIOS or use force_addr=0xaddr\n"); return -ENODEV; } if (force_addr) addr = force_addr; /* so detect will get called */ if (!addr) { dev_err(&dev->dev,"No SiS 5595 sensors found.\n"); return -ENODEV; } normal_isa[0] = addr; s_bridge = pci_dev_get(dev); if (i2c_add_driver(&sis5595_driver)) { pci_dev_put(s_bridge); s_bridge = NULL; } /* Always return failure here. This is to allow other drivers to bind * to this pci device. We don't really want to have control over the * pci device, we only wanted to read as few register values from it. */ return -ENODEV;}static struct pci_driver sis5595_pci_driver = { .name = "sis5595", .id_table = sis5595_pci_ids, .probe = sis5595_pci_probe,};static int __init sm_sis5595_init(void){ return pci_register_driver(&sis5595_pci_driver);}static void __exit sm_sis5595_exit(void){ pci_unregister_driver(&sis5595_pci_driver); if (s_bridge != NULL) { i2c_del_driver(&sis5595_driver); pci_dev_put(s_bridge); s_bridge = NULL; }}MODULE_AUTHOR("Aurelien Jarno <aurelien@aurel32.net>");MODULE_DESCRIPTION("SiS 5595 Sensor device");MODULE_LICENSE("GPL");module_init(sm_sis5595_init);module_exit(sm_sis5595_exit);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -