📄 dme1737.c
字号:
}static int dme1737_create_files(struct device *dev){ struct dme1737_data *data = dev_get_drvdata(dev); int err, ix; /* Create a name attribute for ISA devices */ if (!data->client.driver && (err = sysfs_create_file(&dev->kobj, &dev_attr_name.attr))) { goto exit; } /* Create standard sysfs attributes */ if ((err = sysfs_create_group(&dev->kobj, &dme1737_group))) { goto exit_remove; } /* Create fan sysfs attributes */ for (ix = 0; ix < ARRAY_SIZE(dme1737_fan_group); ix++) { if (data->has_fan & (1 << ix)) { if ((err = sysfs_create_group(&dev->kobj, &dme1737_fan_group[ix]))) { goto exit_remove; } } } /* Create PWM sysfs attributes */ for (ix = 0; ix < ARRAY_SIZE(dme1737_pwm_group); ix++) { if (data->has_pwm & (1 << ix)) { if ((err = sysfs_create_group(&dev->kobj, &dme1737_pwm_group[ix]))) { goto exit_remove; } } } /* Inform if the device is locked. Otherwise change the permissions of * selected attributes from read-only to read-writeable. */ if (data->config & 0x02) { dev_info(dev, "Device is locked. Some attributes " "will be read-only.\n"); } else { /* Change permissions of standard attributes */ dme1737_chmod_group(dev, &dme1737_lock_group, S_IRUGO | S_IWUSR); /* Change permissions of PWM attributes */ for (ix = 0; ix < ARRAY_SIZE(dme1737_pwm_lock_group); ix++) { if (data->has_pwm & (1 << ix)) { dme1737_chmod_group(dev, &dme1737_pwm_lock_group[ix], S_IRUGO | S_IWUSR); } } /* Change permissions of pwm[1-3] if in manual mode */ for (ix = 0; ix < 3; ix++) { if ((data->has_pwm & (1 << ix)) && (PWM_EN_FROM_REG(data->pwm_config[ix]) == 1)) { dme1737_chmod_file(dev, dme1737_attr_pwm[ix], S_IRUGO | S_IWUSR); } } } return 0;exit_remove: dme1737_remove_files(dev);exit: return err;}static int dme1737_init_device(struct device *dev){ struct dme1737_data *data = dev_get_drvdata(dev); struct i2c_client *client = &data->client; int ix; u8 reg; data->config = dme1737_read(client, DME1737_REG_CONFIG); /* Inform if part is not monitoring/started */ if (!(data->config & 0x01)) { if (!force_start) { dev_err(dev, "Device is not monitoring. " "Use the force_start load parameter to " "override.\n"); return -EFAULT; } /* Force monitoring */ data->config |= 0x01; dme1737_write(client, DME1737_REG_CONFIG, data->config); } /* Inform if part is not ready */ if (!(data->config & 0x04)) { dev_err(dev, "Device is not ready.\n"); return -EFAULT; } /* Determine which optional fan and pwm features are enabled/present */ if (client->driver) { /* I2C chip */ data->config2 = dme1737_read(client, DME1737_REG_CONFIG2); /* Check if optional fan3 input is enabled */ if (data->config2 & 0x04) { data->has_fan |= (1 << 2); } /* Fan4 and pwm3 are only available if the client's I2C address * is the default 0x2e. Otherwise the I/Os associated with * these functions are used for addr enable/select. */ if (data->client.addr == 0x2e) { data->has_fan |= (1 << 3); data->has_pwm |= (1 << 2); } /* Determine which of the optional fan[5-6] and pwm[5-6] * features are enabled. For this, we need to query the runtime * registers through the Super-IO LPC interface. Try both * config ports 0x2e and 0x4e. */ if (dme1737_i2c_get_features(0x2e, data) && dme1737_i2c_get_features(0x4e, data)) { dev_warn(dev, "Failed to query Super-IO for optional " "features.\n"); } } else { /* ISA chip */ /* Fan3 and pwm3 are always available. Fan[4-5] and pwm[5-6] * don't exist in the ISA chip. */ data->has_fan |= (1 << 2); data->has_pwm |= (1 << 2); } /* Fan1, fan2, pwm1, and pwm2 are always present */ data->has_fan |= 0x03; data->has_pwm |= 0x03; dev_info(dev, "Optional features: pwm3=%s, pwm5=%s, pwm6=%s, " "fan3=%s, fan4=%s, fan5=%s, fan6=%s.\n", (data->has_pwm & (1 << 2)) ? "yes" : "no", (data->has_pwm & (1 << 4)) ? "yes" : "no", (data->has_pwm & (1 << 5)) ? "yes" : "no", (data->has_fan & (1 << 2)) ? "yes" : "no", (data->has_fan & (1 << 3)) ? "yes" : "no", (data->has_fan & (1 << 4)) ? "yes" : "no", (data->has_fan & (1 << 5)) ? "yes" : "no"); reg = dme1737_read(client, DME1737_REG_TACH_PWM); /* Inform if fan-to-pwm mapping differs from the default */ if (client->driver && reg != 0xa4) { /* I2C chip */ dev_warn(dev, "Non-standard fan to pwm mapping: " "fan1->pwm%d, fan2->pwm%d, fan3->pwm%d, " "fan4->pwm%d. Please report to the driver " "maintainer.\n", (reg & 0x03) + 1, ((reg >> 2) & 0x03) + 1, ((reg >> 4) & 0x03) + 1, ((reg >> 6) & 0x03) + 1); } else if (!client->driver && reg != 0x24) { /* ISA chip */ dev_warn(dev, "Non-standard fan to pwm mapping: " "fan1->pwm%d, fan2->pwm%d, fan3->pwm%d. " "Please report to the driver maintainer.\n", (reg & 0x03) + 1, ((reg >> 2) & 0x03) + 1, ((reg >> 4) & 0x03) + 1); } /* Switch pwm[1-3] to manual mode if they are currently disabled and * set the duty-cycles to 0% (which is identical to the PWMs being * disabled). */ if (!(data->config & 0x02)) { for (ix = 0; ix < 3; ix++) { data->pwm_config[ix] = dme1737_read(client, DME1737_REG_PWM_CONFIG(ix)); if ((data->has_pwm & (1 << ix)) && (PWM_EN_FROM_REG(data->pwm_config[ix]) == -1)) { dev_info(dev, "Switching pwm%d to " "manual mode.\n", ix + 1); data->pwm_config[ix] = PWM_EN_TO_REG(1, data->pwm_config[ix]); dme1737_write(client, DME1737_REG_PWM(ix), 0); dme1737_write(client, DME1737_REG_PWM_CONFIG(ix), data->pwm_config[ix]); } } } /* Initialize the default PWM auto channels zone (acz) assignments */ data->pwm_acz[0] = 1; /* pwm1 -> zone1 */ data->pwm_acz[1] = 2; /* pwm2 -> zone2 */ data->pwm_acz[2] = 4; /* pwm3 -> zone3 */ /* Set VRM */ data->vrm = vid_which_vrm(); return 0;}/* --------------------------------------------------------------------- * I2C device detection and registration * --------------------------------------------------------------------- */static struct i2c_driver dme1737_i2c_driver;static int dme1737_i2c_get_features(int sio_cip, struct dme1737_data *data){ int err = 0, reg; u16 addr; dme1737_sio_enter(sio_cip); /* Check device ID * The DME1737 can return either 0x78 or 0x77 as its device ID. */ reg = dme1737_sio_inb(sio_cip, 0x20); if (!(reg == 0x77 || reg == 0x78)) { err = -ENODEV; goto exit; } /* Select logical device A (runtime registers) */ dme1737_sio_outb(sio_cip, 0x07, 0x0a); /* Get the base address of the runtime registers */ if (!(addr = (dme1737_sio_inb(sio_cip, 0x60) << 8) | dme1737_sio_inb(sio_cip, 0x61))) { err = -ENODEV; goto exit; } /* Read the runtime registers to determine which optional features * are enabled and available. Bits [3:2] of registers 0x43-0x46 are set * to '10' if the respective feature is enabled. */ if ((inb(addr + 0x43) & 0x0c) == 0x08) { /* fan6 */ data->has_fan |= (1 << 5); } if ((inb(addr + 0x44) & 0x0c) == 0x08) { /* pwm6 */ data->has_pwm |= (1 << 5); } if ((inb(addr + 0x45) & 0x0c) == 0x08) { /* fan5 */ data->has_fan |= (1 << 4); } if ((inb(addr + 0x46) & 0x0c) == 0x08) { /* pwm5 */ data->has_pwm |= (1 << 4); }exit: dme1737_sio_exit(sio_cip); return err;}static int dme1737_i2c_detect(struct i2c_adapter *adapter, int address, int kind){ u8 company, verstep = 0; struct i2c_client *client; struct dme1737_data *data; struct device *dev; int err = 0; const char *name; if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) { goto exit; } if (!(data = kzalloc(sizeof(struct dme1737_data), GFP_KERNEL))) { err = -ENOMEM; goto exit; } client = &data->client; i2c_set_clientdata(client, data); client->addr = address; client->adapter = adapter; client->driver = &dme1737_i2c_driver; dev = &client->dev; /* A negative kind means that the driver was loaded with no force * parameter (default), so we must identify the chip. */ if (kind < 0) { company = dme1737_read(client, DME1737_REG_COMPANY); verstep = dme1737_read(client, DME1737_REG_VERSTEP); if (!((company == DME1737_COMPANY_SMSC) && ((verstep & DME1737_VERSTEP_MASK) == DME1737_VERSTEP))) { err = -ENODEV; goto exit_kfree; } } kind = dme1737; name = "dme1737"; /* Fill in the remaining client fields and put it into the global * list */ strlcpy(client->name, name, I2C_NAME_SIZE); mutex_init(&data->update_lock); /* Tell the I2C layer a new client has arrived */ if ((err = i2c_attach_client(client))) { goto exit_kfree; } dev_info(dev, "Found a DME1737 chip at 0x%02x (rev 0x%02x).\n", client->addr, verstep); /* Initialize the DME1737 chip */ if ((err = dme1737_init_device(dev))) { dev_err(dev, "Failed to initialize device.\n"); goto exit_detach; } /* Create sysfs files */ if ((err = dme1737_create_files(dev))) { dev_err(dev, "Failed to create sysfs files.\n"); goto exit_detach; } /* Register device */ data->hwmon_dev = hwmon_device_register(dev); if (IS_ERR(data->hwmon_dev)) { dev_err(dev, "Failed to register device.\n"); err = PTR_ERR(data->hwmon_dev); goto exit_remove; } return 0;exit_remove: dme1737_remove_files(dev);exit_detach: i2c_detach_client(client);exit_kfree: kfree(data);exit: return err;}static int dme1737_i2c_attach_adapter(struct i2c_adapter *adapter){ if (!(adapter->class & I2C_CLASS_HWMON)) { return 0; } return i2c_probe(adapter, &addr_data, dme1737_i2c_detect);}static int dme1737_i2c_detach_client(struct i2c_client *client){ struct dme1737_data *data = i2c_get_clientdata(client); int err; hwmon_device_unregister(data->hwmon_dev); dme1737_remove_files(&client->dev); if ((err = i2c_detach_client(client))) { return err; } kfree(data); return 0;}static struct i2c_driver dme1737_i2c_driver = { .driver = { .name = "dme1737", }, .attach_adapter = dme1737_i2c_attach_adapter, .detach_client = dme1737_i2c_detach_client,};/* --------------------------------------------------------------------- * ISA device detection and registration * --------------------------------------------------------------------- */static int __init dme1737_isa_detect(int sio_cip, unsigned short *addr){ int err = 0, reg; unsigned short base_addr; dme1737_sio_enter(sio_cip); /* Check device ID * We currently know about SCH3112 (0x7c), SCH3114 (0x7d), and * SCH3116 (0x7f). */ reg = dme1737_sio_inb(sio_cip, 0x20); if (!(reg == 0x7c || reg == 0x7d || reg == 0x7f)) { err = -ENODEV; goto exit; } /* Select logical device A (runtime registers) */ dme1737_sio_outb(sio_cip, 0x07, 0x0a); /* Get the base address of the runtime registers */ if (!(base_addr = (dme1737_sio_inb(sio_cip, 0x60) << 8) | dme1737_sio_inb(sio_cip, 0x61))) { printk(KERN_ERR "dme1737: Base address not set.\n"); err = -ENODEV; goto exit; } /* Access to the hwmon registers is through an index/data register * pair located at offset 0x70/0x71. */ *addr = base_addr + 0x70;exit: dme1737_sio_exit(sio_cip); return err;}static int __init dme1737_isa_device_add(unsigned short addr){ struct resource res = { .start = addr, .end = addr + DME1737_EXTENT - 1, .name = "dme1737", .flags = IORESOURCE_IO, }; int err; if (!(pdev = platform_device_alloc("dme1737", addr))) { printk(KERN_ERR "dme1737: Failed to allocate device.\n"); err = -ENOMEM; goto exit; } if ((err = platform_device_add_resources(pdev, &res, 1))) { printk(KERN_ERR "dme1737: Failed to add device resource " "(err = %d).\n", err); goto exit_device_put; } if ((err = platform_device_add(pdev))) { printk(KERN_ERR "dme1737: Failed to add device (err = %d).\n", err); goto exit_device_put; } return 0;exit_device_put: platform_device_put(pdev); pdev = NULL;exit: return err;}static int __devinit dme1737_isa_probe(struct platform_device *pdev){ u8 comp
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -