diff options
Diffstat (limited to 'drivers/hwmon/pc87360.c')
| -rw-r--r-- | drivers/hwmon/pc87360.c | 232 | 
1 files changed, 137 insertions, 95 deletions
| diff --git a/drivers/hwmon/pc87360.c b/drivers/hwmon/pc87360.c index c8a21be09d87..cb72526c346a 100644 --- a/drivers/hwmon/pc87360.c +++ b/drivers/hwmon/pc87360.c | |||
| @@ -1,7 +1,7 @@ | |||
| 1 | /* | 1 | /* | 
| 2 | * pc87360.c - Part of lm_sensors, Linux kernel modules | 2 | * pc87360.c - Part of lm_sensors, Linux kernel modules | 
| 3 | * for hardware monitoring | 3 | * for hardware monitoring | 
| 4 | * Copyright (C) 2004 Jean Delvare <khali@linux-fr.org> | 4 | * Copyright (C) 2004, 2007 Jean Delvare <khali@linux-fr.org> | 
| 5 | * | 5 | * | 
| 6 | * Copied from smsc47m1.c: | 6 | * Copied from smsc47m1.c: | 
| 7 | * Copyright (C) 2002 Mark D. Studebaker <mdsxyz123@yahoo.com> | 7 | * Copyright (C) 2002 Mark D. Studebaker <mdsxyz123@yahoo.com> | 
| @@ -37,8 +37,7 @@ | |||
| 37 | #include <linux/init.h> | 37 | #include <linux/init.h> | 
| 38 | #include <linux/slab.h> | 38 | #include <linux/slab.h> | 
| 39 | #include <linux/jiffies.h> | 39 | #include <linux/jiffies.h> | 
| 40 | #include <linux/i2c.h> | 40 | #include <linux/platform_device.h> | 
| 41 | #include <linux/i2c-isa.h> | ||
| 42 | #include <linux/hwmon.h> | 41 | #include <linux/hwmon.h> | 
| 43 | #include <linux/hwmon-sysfs.h> | 42 | #include <linux/hwmon-sysfs.h> | 
| 44 | #include <linux/hwmon-vid.h> | 43 | #include <linux/hwmon-vid.h> | 
| @@ -47,12 +46,10 @@ | |||
| 47 | #include <asm/io.h> | 46 | #include <asm/io.h> | 
| 48 | 47 | ||
| 49 | static u8 devid; | 48 | static u8 devid; | 
| 50 | static unsigned short address; | 49 | static struct platform_device *pdev; | 
| 51 | static unsigned short extra_isa[3]; | 50 | static unsigned short extra_isa[3]; | 
| 52 | static u8 confreg[4]; | 51 | static u8 confreg[4]; | 
| 53 | 52 | ||
| 54 | enum chips { any_chip, pc87360, pc87363, pc87364, pc87365, pc87366 }; | ||
| 55 | |||
| 56 | static int init = 1; | 53 | static int init = 1; | 
| 57 | module_param(init, int, 0); | 54 | module_param(init, int, 0); | 
| 58 | MODULE_PARM_DESC(init, | 55 | MODULE_PARM_DESC(init, | 
| @@ -178,11 +175,11 @@ static inline u8 PWM_TO_REG(int val, int inv) | |||
| 178 | ((val) + 500) / 1000) | 175 | ((val) + 500) / 1000) | 
| 179 | 176 | ||
| 180 | /* | 177 | /* | 
| 181 | * Client data (each client gets its own) | 178 | * Device data | 
| 182 | */ | 179 | */ | 
| 183 | 180 | ||
| 184 | struct pc87360_data { | 181 | struct pc87360_data { | 
| 185 | struct i2c_client client; | 182 | const char *name; | 
| 186 | struct class_device *class_dev; | 183 | struct class_device *class_dev; | 
| 187 | struct mutex lock; | 184 | struct mutex lock; | 
| 188 | struct mutex update_lock; | 185 | struct mutex update_lock; | 
| @@ -222,27 +219,28 @@ struct pc87360_data { | |||
| 222 | * Functions declaration | 219 | * Functions declaration | 
| 223 | */ | 220 | */ | 
| 224 | 221 | ||
| 225 | static int pc87360_detect(struct i2c_adapter *adapter); | 222 | static int pc87360_probe(struct platform_device *pdev); | 
| 226 | static int pc87360_detach_client(struct i2c_client *client); | 223 | static int pc87360_remove(struct platform_device *pdev); | 
| 227 | 224 | ||
| 228 | static int pc87360_read_value(struct pc87360_data *data, u8 ldi, u8 bank, | 225 | static int pc87360_read_value(struct pc87360_data *data, u8 ldi, u8 bank, | 
| 229 | u8 reg); | 226 | u8 reg); | 
| 230 | static void pc87360_write_value(struct pc87360_data *data, u8 ldi, u8 bank, | 227 | static void pc87360_write_value(struct pc87360_data *data, u8 ldi, u8 bank, | 
| 231 | u8 reg, u8 value); | 228 | u8 reg, u8 value); | 
| 232 | static void pc87360_init_client(struct i2c_client *client, int use_thermistors); | 229 | static void pc87360_init_device(struct platform_device *pdev, | 
| 230 | int use_thermistors); | ||
| 233 | static struct pc87360_data *pc87360_update_device(struct device *dev); | 231 | static struct pc87360_data *pc87360_update_device(struct device *dev); | 
| 234 | 232 | ||
| 235 | /* | 233 | /* | 
| 236 | * Driver data (common to all clients) | 234 | * Driver data | 
| 237 | */ | 235 | */ | 
| 238 | 236 | ||
| 239 | static struct i2c_driver pc87360_driver = { | 237 | static struct platform_driver pc87360_driver = { | 
| 240 | .driver = { | 238 | .driver = { | 
| 241 | .owner = THIS_MODULE, | 239 | .owner = THIS_MODULE, | 
| 242 | .name = "pc87360", | 240 | .name = "pc87360", | 
| 243 | }, | 241 | }, | 
| 244 | .attach_adapter = pc87360_detect, | 242 | .probe = pc87360_probe, | 
| 245 | .detach_client = pc87360_detach_client, | 243 | .remove = __devexit_p(pc87360_remove), | 
| 246 | }; | 244 | }; | 
| 247 | 245 | ||
| 248 | /* | 246 | /* | 
| @@ -281,8 +279,7 @@ static ssize_t set_fan_min(struct device *dev, struct device_attribute *devattr, | |||
| 281 | size_t count) | 279 | size_t count) | 
| 282 | { | 280 | { | 
| 283 | struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); | 281 | struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); | 
| 284 | struct i2c_client *client = to_i2c_client(dev); | 282 | struct pc87360_data *data = dev_get_drvdata(dev); | 
| 285 | struct pc87360_data *data = i2c_get_clientdata(client); | ||
| 286 | long fan_min = simple_strtol(buf, NULL, 10); | 283 | long fan_min = simple_strtol(buf, NULL, 10); | 
| 287 | 284 | ||
| 288 | mutex_lock(&data->update_lock); | 285 | mutex_lock(&data->update_lock); | 
| @@ -347,8 +344,7 @@ static ssize_t set_pwm(struct device *dev, struct device_attribute *devattr, con | |||
| 347 | size_t count) | 344 | size_t count) | 
| 348 | { | 345 | { | 
| 349 | struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); | 346 | struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); | 
| 350 | struct i2c_client *client = to_i2c_client(dev); | 347 | struct pc87360_data *data = dev_get_drvdata(dev); | 
| 351 | struct pc87360_data *data = i2c_get_clientdata(client); | ||
| 352 | long val = simple_strtol(buf, NULL, 10); | 348 | long val = simple_strtol(buf, NULL, 10); | 
| 353 | 349 | ||
| 354 | mutex_lock(&data->update_lock); | 350 | mutex_lock(&data->update_lock); | 
| @@ -410,8 +406,7 @@ static ssize_t set_in_min(struct device *dev, struct device_attribute *devattr, | |||
| 410 | size_t count) | 406 | size_t count) | 
| 411 | { | 407 | { | 
| 412 | struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); | 408 | struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); | 
| 413 | struct i2c_client *client = to_i2c_client(dev); | 409 | struct pc87360_data *data = dev_get_drvdata(dev); | 
| 414 | struct pc87360_data *data = i2c_get_clientdata(client); | ||
| 415 | long val = simple_strtol(buf, NULL, 10); | 410 | long val = simple_strtol(buf, NULL, 10); | 
| 416 | 411 | ||
| 417 | mutex_lock(&data->update_lock); | 412 | mutex_lock(&data->update_lock); | 
| @@ -425,8 +420,7 @@ static ssize_t set_in_max(struct device *dev, struct device_attribute *devattr, | |||
| 425 | size_t count) | 420 | size_t count) | 
| 426 | { | 421 | { | 
| 427 | struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); | 422 | struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); | 
| 428 | struct i2c_client *client = to_i2c_client(dev); | 423 | struct pc87360_data *data = dev_get_drvdata(dev); | 
| 429 | struct pc87360_data *data = i2c_get_clientdata(client); | ||
| 430 | long val = simple_strtol(buf, NULL, 10); | 424 | long val = simple_strtol(buf, NULL, 10); | 
| 431 | 425 | ||
| 432 | mutex_lock(&data->update_lock); | 426 | mutex_lock(&data->update_lock); | 
| @@ -511,8 +505,7 @@ static ssize_t show_vrm(struct device *dev, struct device_attribute *attr, char | |||
| 511 | } | 505 | } | 
| 512 | static ssize_t set_vrm(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) | 506 | static ssize_t set_vrm(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) | 
| 513 | { | 507 | { | 
| 514 | struct i2c_client *client = to_i2c_client(dev); | 508 | struct pc87360_data *data = dev_get_drvdata(dev); | 
| 515 | struct pc87360_data *data = i2c_get_clientdata(client); | ||
| 516 | data->vrm = simple_strtoul(buf, NULL, 10); | 509 | data->vrm = simple_strtoul(buf, NULL, 10); | 
| 517 | return count; | 510 | return count; | 
| 518 | } | 511 | } | 
| @@ -584,8 +577,7 @@ static ssize_t set_therm_min(struct device *dev, struct device_attribute *devatt | |||
| 584 | size_t count) | 577 | size_t count) | 
| 585 | { | 578 | { | 
| 586 | struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); | 579 | struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); | 
| 587 | struct i2c_client *client = to_i2c_client(dev); | 580 | struct pc87360_data *data = dev_get_drvdata(dev); | 
| 588 | struct pc87360_data *data = i2c_get_clientdata(client); | ||
| 589 | long val = simple_strtol(buf, NULL, 10); | 581 | long val = simple_strtol(buf, NULL, 10); | 
| 590 | 582 | ||
| 591 | mutex_lock(&data->update_lock); | 583 | mutex_lock(&data->update_lock); | 
| @@ -599,8 +591,7 @@ static ssize_t set_therm_max(struct device *dev, struct device_attribute *devatt | |||
| 599 | size_t count) | 591 | size_t count) | 
| 600 | { | 592 | { | 
| 601 | struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); | 593 | struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); | 
| 602 | struct i2c_client *client = to_i2c_client(dev); | 594 | struct pc87360_data *data = dev_get_drvdata(dev); | 
| 603 | struct pc87360_data *data = i2c_get_clientdata(client); | ||
| 604 | long val = simple_strtol(buf, NULL, 10); | 595 | long val = simple_strtol(buf, NULL, 10); | 
| 605 | 596 | ||
| 606 | mutex_lock(&data->update_lock); | 597 | mutex_lock(&data->update_lock); | 
| @@ -614,8 +605,7 @@ static ssize_t set_therm_crit(struct device *dev, struct device_attribute *devat | |||
| 614 | size_t count) | 605 | size_t count) | 
| 615 | { | 606 | { | 
| 616 | struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); | 607 | struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); | 
| 617 | struct i2c_client *client = to_i2c_client(dev); | 608 | struct pc87360_data *data = dev_get_drvdata(dev); | 
| 618 | struct pc87360_data *data = i2c_get_clientdata(client); | ||
| 619 | long val = simple_strtol(buf, NULL, 10); | 609 | long val = simple_strtol(buf, NULL, 10); | 
| 620 | 610 | ||
| 621 | mutex_lock(&data->update_lock); | 611 | mutex_lock(&data->update_lock); | 
| @@ -715,8 +705,7 @@ static ssize_t set_temp_min(struct device *dev, struct device_attribute *devattr | |||
| 715 | size_t count) | 705 | size_t count) | 
| 716 | { | 706 | { | 
| 717 | struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); | 707 | struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); | 
| 718 | struct i2c_client *client = to_i2c_client(dev); | 708 | struct pc87360_data *data = dev_get_drvdata(dev); | 
| 719 | struct pc87360_data *data = i2c_get_clientdata(client); | ||
| 720 | long val = simple_strtol(buf, NULL, 10); | 709 | long val = simple_strtol(buf, NULL, 10); | 
| 721 | 710 | ||
| 722 | mutex_lock(&data->update_lock); | 711 | mutex_lock(&data->update_lock); | 
| @@ -730,8 +719,7 @@ static ssize_t set_temp_max(struct device *dev, struct device_attribute *devattr | |||
| 730 | size_t count) | 719 | size_t count) | 
| 731 | { | 720 | { | 
| 732 | struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); | 721 | struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); | 
| 733 | struct i2c_client *client = to_i2c_client(dev); | 722 | struct pc87360_data *data = dev_get_drvdata(dev); | 
| 734 | struct pc87360_data *data = i2c_get_clientdata(client); | ||
| 735 | long val = simple_strtol(buf, NULL, 10); | 723 | long val = simple_strtol(buf, NULL, 10); | 
| 736 | 724 | ||
| 737 | mutex_lock(&data->update_lock); | 725 | mutex_lock(&data->update_lock); | 
| @@ -745,8 +733,7 @@ static ssize_t set_temp_crit(struct device *dev, struct device_attribute *devatt | |||
| 745 | size_t count) | 733 | size_t count) | 
| 746 | { | 734 | { | 
| 747 | struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); | 735 | struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); | 
| 748 | struct i2c_client *client = to_i2c_client(dev); | 736 | struct pc87360_data *data = dev_get_drvdata(dev); | 
| 749 | struct pc87360_data *data = i2c_get_clientdata(client); | ||
| 750 | long val = simple_strtol(buf, NULL, 10); | 737 | long val = simple_strtol(buf, NULL, 10); | 
| 751 | 738 | ||
| 752 | mutex_lock(&data->update_lock); | 739 | mutex_lock(&data->update_lock); | 
| @@ -818,6 +805,14 @@ static const struct attribute_group pc8736x_temp_group = { | |||
| 818 | .attrs = pc8736x_temp_attr_array, | 805 | .attrs = pc8736x_temp_attr_array, | 
| 819 | }; | 806 | }; | 
| 820 | 807 | ||
| 808 | static ssize_t show_name(struct device *dev, struct device_attribute | ||
| 809 | *devattr, char *buf) | ||
| 810 | { | ||
| 811 | struct pc87360_data *data = dev_get_drvdata(dev); | ||
| 812 | return sprintf(buf, "%s\n", data->name); | ||
| 813 | } | ||
| 814 | static DEVICE_ATTR(name, S_IRUGO, show_name, NULL); | ||
| 815 | |||
| 821 | /* | 816 | /* | 
| 822 | * Device detection, registration and update | 817 | * Device detection, registration and update | 
| 823 | */ | 818 | */ | 
| @@ -912,28 +907,18 @@ static int __init pc87360_find(int sioaddr, u8 *devid, unsigned short *addresses | |||
| 912 | return 0; | 907 | return 0; | 
| 913 | } | 908 | } | 
| 914 | 909 | ||
| 915 | static int pc87360_detect(struct i2c_adapter *adapter) | 910 | static int __devinit pc87360_probe(struct platform_device *pdev) | 
| 916 | { | 911 | { | 
| 917 | int i; | 912 | int i; | 
| 918 | struct i2c_client *client; | ||
| 919 | struct pc87360_data *data; | 913 | struct pc87360_data *data; | 
| 920 | int err = 0; | 914 | int err = 0; | 
| 921 | const char *name = "pc87360"; | 915 | const char *name = "pc87360"; | 
| 922 | int use_thermistors = 0; | 916 | int use_thermistors = 0; | 
| 923 | struct device *dev; | 917 | struct device *dev = &pdev->dev; | 
| 924 | 918 | ||
| 925 | if (!(data = kzalloc(sizeof(struct pc87360_data), GFP_KERNEL))) | 919 | if (!(data = kzalloc(sizeof(struct pc87360_data), GFP_KERNEL))) | 
| 926 | return -ENOMEM; | 920 | return -ENOMEM; | 
| 927 | 921 | ||
| 928 | client = &data->client; | ||
| 929 | dev = &client->dev; | ||
| 930 | i2c_set_clientdata(client, data); | ||
| 931 | client->addr = address; | ||
| 932 | mutex_init(&data->lock); | ||
| 933 | client->adapter = adapter; | ||
| 934 | client->driver = &pc87360_driver; | ||
| 935 | client->flags = 0; | ||
| 936 | |||
| 937 | data->fannr = 2; | 922 | data->fannr = 2; | 
| 938 | data->innr = 0; | 923 | data->innr = 0; | 
| 939 | data->tempnr = 0; | 924 | data->tempnr = 0; | 
| @@ -960,15 +945,17 @@ static int pc87360_detect(struct i2c_adapter *adapter) | |||
| 960 | break; | 945 | break; | 
| 961 | } | 946 | } | 
| 962 | 947 | ||
| 963 | strlcpy(client->name, name, sizeof(client->name)); | 948 | data->name = name; | 
| 964 | data->valid = 0; | 949 | data->valid = 0; | 
| 950 | mutex_init(&data->lock); | ||
| 965 | mutex_init(&data->update_lock); | 951 | mutex_init(&data->update_lock); | 
| 952 | platform_set_drvdata(pdev, data); | ||
| 966 | 953 | ||
| 967 | for (i = 0; i < 3; i++) { | 954 | for (i = 0; i < 3; i++) { | 
| 968 | if (((data->address[i] = extra_isa[i])) | 955 | if (((data->address[i] = extra_isa[i])) | 
| 969 | && !request_region(extra_isa[i], PC87360_EXTENT, | 956 | && !request_region(extra_isa[i], PC87360_EXTENT, | 
| 970 | pc87360_driver.driver.name)) { | 957 | pc87360_driver.driver.name)) { | 
| 971 | dev_err(&client->dev, "Region 0x%x-0x%x already " | 958 | dev_err(dev, "Region 0x%x-0x%x already " | 
| 972 | "in use!\n", extra_isa[i], | 959 | "in use!\n", extra_isa[i], | 
| 973 | extra_isa[i]+PC87360_EXTENT-1); | 960 | extra_isa[i]+PC87360_EXTENT-1); | 
| 974 | for (i--; i >= 0; i--) | 961 | for (i--; i >= 0; i--) | 
| @@ -982,9 +969,6 @@ static int pc87360_detect(struct i2c_adapter *adapter) | |||
| 982 | if (data->fannr) | 969 | if (data->fannr) | 
| 983 | data->fan_conf = confreg[0] | (confreg[1] << 8); | 970 | data->fan_conf = confreg[0] | (confreg[1] << 8); | 
| 984 | 971 | ||
| 985 | if ((err = i2c_attach_client(client))) | ||
| 986 | goto ERROR2; | ||
| 987 | |||
| 988 | /* Use the correct reference voltage | 972 | /* Use the correct reference voltage | 
| 989 | Unless both the VLM and the TMS logical devices agree to | 973 | Unless both the VLM and the TMS logical devices agree to | 
| 990 | use an external Vref, the internal one is used. */ | 974 | use an external Vref, the internal one is used. */ | 
| @@ -996,7 +980,7 @@ static int pc87360_detect(struct i2c_adapter *adapter) | |||
| 996 | PC87365_REG_TEMP_CONFIG); | 980 | PC87365_REG_TEMP_CONFIG); | 
| 997 | } | 981 | } | 
| 998 | data->in_vref = (i&0x02) ? 3025 : 2966; | 982 | data->in_vref = (i&0x02) ? 3025 : 2966; | 
| 999 | dev_dbg(&client->dev, "Using %s reference voltage\n", | 983 | dev_dbg(dev, "Using %s reference voltage\n", | 
| 1000 | (i&0x02) ? "external" : "internal"); | 984 | (i&0x02) ? "external" : "internal"); | 
| 1001 | 985 | ||
| 1002 | data->vid_conf = confreg[3]; | 986 | data->vid_conf = confreg[3]; | 
| @@ -1015,18 +999,18 @@ static int pc87360_detect(struct i2c_adapter *adapter) | |||
| 1015 | if (devid == 0xe9 && data->address[1]) /* PC87366 */ | 999 | if (devid == 0xe9 && data->address[1]) /* PC87366 */ | 
| 1016 | use_thermistors = confreg[2] & 0x40; | 1000 | use_thermistors = confreg[2] & 0x40; | 
| 1017 | 1001 | ||
| 1018 | pc87360_init_client(client, use_thermistors); | 1002 | pc87360_init_device(pdev, use_thermistors); | 
| 1019 | } | 1003 | } | 
| 1020 | 1004 | ||
| 1021 | /* Register all-or-nothing sysfs groups */ | 1005 | /* Register all-or-nothing sysfs groups */ | 
| 1022 | 1006 | ||
| 1023 | if (data->innr && | 1007 | if (data->innr && | 
| 1024 | (err = sysfs_create_group(&client->dev.kobj, | 1008 | (err = sysfs_create_group(&dev->kobj, | 
| 1025 | &pc8736x_vin_group))) | 1009 | &pc8736x_vin_group))) | 
| 1026 | goto ERROR3; | 1010 | goto ERROR3; | 
| 1027 | 1011 | ||
| 1028 | if (data->innr == 14 && | 1012 | if (data->innr == 14 && | 
| 1029 | (err = sysfs_create_group(&client->dev.kobj, | 1013 | (err = sysfs_create_group(&dev->kobj, | 
| 1030 | &pc8736x_therm_group))) | 1014 | &pc8736x_therm_group))) | 
| 1031 | goto ERROR3; | 1015 | goto ERROR3; | 
| 1032 | 1016 | ||
| @@ -1067,7 +1051,10 @@ static int pc87360_detect(struct i2c_adapter *adapter) | |||
| 1067 | goto ERROR3; | 1051 | goto ERROR3; | 
| 1068 | } | 1052 | } | 
| 1069 | 1053 | ||
| 1070 | data->class_dev = hwmon_device_register(&client->dev); | 1054 | if ((err = device_create_file(dev, &dev_attr_name))) | 
| 1055 | goto ERROR3; | ||
| 1056 | |||
| 1057 | data->class_dev = hwmon_device_register(dev); | ||
| 1071 | if (IS_ERR(data->class_dev)) { | 1058 | if (IS_ERR(data->class_dev)) { | 
| 1072 | err = PTR_ERR(data->class_dev); | 1059 | err = PTR_ERR(data->class_dev); | 
| 1073 | goto ERROR3; | 1060 | goto ERROR3; | 
| @@ -1075,14 +1062,12 @@ static int pc87360_detect(struct i2c_adapter *adapter) | |||
| 1075 | return 0; | 1062 | return 0; | 
| 1076 | 1063 | ||
| 1077 | ERROR3: | 1064 | ERROR3: | 
| 1065 | device_remove_file(dev, &dev_attr_name); | ||
| 1078 | /* can still remove groups whose members were added individually */ | 1066 | /* can still remove groups whose members were added individually */ | 
| 1079 | sysfs_remove_group(&client->dev.kobj, &pc8736x_temp_group); | 1067 | sysfs_remove_group(&dev->kobj, &pc8736x_temp_group); | 
| 1080 | sysfs_remove_group(&client->dev.kobj, &pc8736x_fan_group); | 1068 | sysfs_remove_group(&dev->kobj, &pc8736x_fan_group); | 
| 1081 | sysfs_remove_group(&client->dev.kobj, &pc8736x_therm_group); | 1069 | sysfs_remove_group(&dev->kobj, &pc8736x_therm_group); | 
| 1082 | sysfs_remove_group(&client->dev.kobj, &pc8736x_vin_group); | 1070 | sysfs_remove_group(&dev->kobj, &pc8736x_vin_group); | 
| 1083 | |||
| 1084 | i2c_detach_client(client); | ||
| 1085 | ERROR2: | ||
| 1086 | for (i = 0; i < 3; i++) { | 1071 | for (i = 0; i < 3; i++) { | 
| 1087 | if (data->address[i]) { | 1072 | if (data->address[i]) { | 
| 1088 | release_region(data->address[i], PC87360_EXTENT); | 1073 | release_region(data->address[i], PC87360_EXTENT); | 
| @@ -1093,20 +1078,18 @@ ERROR1: | |||
| 1093 | return err; | 1078 | return err; | 
| 1094 | } | 1079 | } | 
| 1095 | 1080 | ||
| 1096 | static int pc87360_detach_client(struct i2c_client *client) | 1081 | static int __devexit pc87360_remove(struct platform_device *pdev) | 
| 1097 | { | 1082 | { | 
| 1098 | struct pc87360_data *data = i2c_get_clientdata(client); | 1083 | struct pc87360_data *data = platform_get_drvdata(pdev); | 
| 1099 | int i; | 1084 | int i; | 
| 1100 | 1085 | ||
| 1101 | hwmon_device_unregister(data->class_dev); | 1086 | hwmon_device_unregister(data->class_dev); | 
| 1102 | 1087 | ||
| 1103 | sysfs_remove_group(&client->dev.kobj, &pc8736x_temp_group); | 1088 | device_remove_file(&pdev->dev, &dev_attr_name); | 
| 1104 | sysfs_remove_group(&client->dev.kobj, &pc8736x_fan_group); | 1089 | sysfs_remove_group(&pdev->dev.kobj, &pc8736x_temp_group); | 
| 1105 | sysfs_remove_group(&client->dev.kobj, &pc8736x_therm_group); | 1090 | sysfs_remove_group(&pdev->dev.kobj, &pc8736x_fan_group); | 
| 1106 | sysfs_remove_group(&client->dev.kobj, &pc8736x_vin_group); | 1091 | sysfs_remove_group(&pdev->dev.kobj, &pc8736x_therm_group); | 
| 1107 | 1092 | sysfs_remove_group(&pdev->dev.kobj, &pc8736x_vin_group); | |
| 1108 | if ((i = i2c_detach_client(client))) | ||
| 1109 | return i; | ||
| 1110 | 1093 | ||
| 1111 | for (i = 0; i < 3; i++) { | 1094 | for (i = 0; i < 3; i++) { | 
| 1112 | if (data->address[i]) { | 1095 | if (data->address[i]) { | 
| @@ -1144,9 +1127,10 @@ static void pc87360_write_value(struct pc87360_data *data, u8 ldi, u8 bank, | |||
| 1144 | mutex_unlock(&(data->lock)); | 1127 | mutex_unlock(&(data->lock)); | 
| 1145 | } | 1128 | } | 
| 1146 | 1129 | ||
| 1147 | static void pc87360_init_client(struct i2c_client *client, int use_thermistors) | 1130 | static void pc87360_init_device(struct platform_device *pdev, | 
| 1131 | int use_thermistors) | ||
| 1148 | { | 1132 | { | 
| 1149 | struct pc87360_data *data = i2c_get_clientdata(client); | 1133 | struct pc87360_data *data = platform_get_drvdata(pdev); | 
| 1150 | int i, nr; | 1134 | int i, nr; | 
| 1151 | const u8 init_in[14] = { 2, 2, 2, 2, 2, 2, 2, 1, 1, 3, 1, 2, 2, 2 }; | 1135 | const u8 init_in[14] = { 2, 2, 2, 2, 2, 2, 2, 1, 1, 3, 1, 2, 2, 2 }; | 
| 1152 | const u8 init_temp[3] = { 2, 2, 1 }; | 1136 | const u8 init_temp[3] = { 2, 2, 1 }; | 
| @@ -1155,7 +1139,7 @@ static void pc87360_init_client(struct i2c_client *client, int use_thermistors) | |||
| 1155 | if (init >= 2 && data->innr) { | 1139 | if (init >= 2 && data->innr) { | 
| 1156 | reg = pc87360_read_value(data, LD_IN, NO_BANK, | 1140 | reg = pc87360_read_value(data, LD_IN, NO_BANK, | 
| 1157 | PC87365_REG_IN_CONVRATE); | 1141 | PC87365_REG_IN_CONVRATE); | 
| 1158 | dev_info(&client->dev, "VLM conversion set to " | 1142 | dev_info(&pdev->dev, "VLM conversion set to " | 
| 1159 | "1s period, 160us delay\n"); | 1143 | "1s period, 160us delay\n"); | 
| 1160 | pc87360_write_value(data, LD_IN, NO_BANK, | 1144 | pc87360_write_value(data, LD_IN, NO_BANK, | 
| 1161 | PC87365_REG_IN_CONVRATE, | 1145 | PC87365_REG_IN_CONVRATE, | 
| @@ -1169,7 +1153,7 @@ static void pc87360_init_client(struct i2c_client *client, int use_thermistors) | |||
| 1169 | reg = pc87360_read_value(data, LD_IN, i, | 1153 | reg = pc87360_read_value(data, LD_IN, i, | 
| 1170 | PC87365_REG_IN_STATUS); | 1154 | PC87365_REG_IN_STATUS); | 
| 1171 | if (!(reg & 0x01)) { | 1155 | if (!(reg & 0x01)) { | 
| 1172 | dev_dbg(&client->dev, "Forcibly " | 1156 | dev_dbg(&pdev->dev, "Forcibly " | 
| 1173 | "enabling in%d\n", i); | 1157 | "enabling in%d\n", i); | 
| 1174 | pc87360_write_value(data, LD_IN, i, | 1158 | pc87360_write_value(data, LD_IN, i, | 
| 1175 | PC87365_REG_IN_STATUS, | 1159 | PC87365_REG_IN_STATUS, | 
| @@ -1193,7 +1177,7 @@ static void pc87360_init_client(struct i2c_client *client, int use_thermistors) | |||
| 1193 | reg = pc87360_read_value(data, LD_TEMP, i, | 1177 | reg = pc87360_read_value(data, LD_TEMP, i, | 
| 1194 | PC87365_REG_TEMP_STATUS); | 1178 | PC87365_REG_TEMP_STATUS); | 
| 1195 | if (!(reg & 0x01)) { | 1179 | if (!(reg & 0x01)) { | 
| 1196 | dev_dbg(&client->dev, "Forcibly " | 1180 | dev_dbg(&pdev->dev, "Forcibly " | 
| 1197 | "enabling temp%d\n", i+1); | 1181 | "enabling temp%d\n", i+1); | 
| 1198 | pc87360_write_value(data, LD_TEMP, i, | 1182 | pc87360_write_value(data, LD_TEMP, i, | 
| 1199 | PC87365_REG_TEMP_STATUS, | 1183 | PC87365_REG_TEMP_STATUS, | 
| @@ -1210,7 +1194,7 @@ static void pc87360_init_client(struct i2c_client *client, int use_thermistors) | |||
| 1210 | reg = pc87360_read_value(data, LD_TEMP, | 1194 | reg = pc87360_read_value(data, LD_TEMP, | 
| 1211 | (i-11)/2, PC87365_REG_TEMP_STATUS); | 1195 | (i-11)/2, PC87365_REG_TEMP_STATUS); | 
| 1212 | if (reg & 0x01) { | 1196 | if (reg & 0x01) { | 
| 1213 | dev_dbg(&client->dev, "Skipping " | 1197 | dev_dbg(&pdev->dev, "Skipping " | 
| 1214 | "temp%d, pin already in use " | 1198 | "temp%d, pin already in use " | 
| 1215 | "by temp%d\n", i-7, (i-11)/2); | 1199 | "by temp%d\n", i-7, (i-11)/2); | 
| 1216 | continue; | 1200 | continue; | 
| @@ -1220,7 +1204,7 @@ static void pc87360_init_client(struct i2c_client *client, int use_thermistors) | |||
| 1220 | reg = pc87360_read_value(data, LD_IN, i, | 1204 | reg = pc87360_read_value(data, LD_IN, i, | 
| 1221 | PC87365_REG_IN_STATUS); | 1205 | PC87365_REG_IN_STATUS); | 
| 1222 | if (!(reg & 0x01)) { | 1206 | if (!(reg & 0x01)) { | 
| 1223 | dev_dbg(&client->dev, "Forcibly " | 1207 | dev_dbg(&pdev->dev, "Forcibly " | 
| 1224 | "enabling temp%d\n", i-7); | 1208 | "enabling temp%d\n", i-7); | 
| 1225 | pc87360_write_value(data, LD_IN, i, | 1209 | pc87360_write_value(data, LD_IN, i, | 
| 1226 | PC87365_REG_TEMP_STATUS, | 1210 | PC87365_REG_TEMP_STATUS, | 
| @@ -1234,7 +1218,7 @@ static void pc87360_init_client(struct i2c_client *client, int use_thermistors) | |||
| 1234 | reg = pc87360_read_value(data, LD_IN, NO_BANK, | 1218 | reg = pc87360_read_value(data, LD_IN, NO_BANK, | 
| 1235 | PC87365_REG_IN_CONFIG); | 1219 | PC87365_REG_IN_CONFIG); | 
| 1236 | if (reg & 0x01) { | 1220 | if (reg & 0x01) { | 
| 1237 | dev_dbg(&client->dev, "Forcibly " | 1221 | dev_dbg(&pdev->dev, "Forcibly " | 
| 1238 | "enabling monitoring (VLM)\n"); | 1222 | "enabling monitoring (VLM)\n"); | 
| 1239 | pc87360_write_value(data, LD_IN, NO_BANK, | 1223 | pc87360_write_value(data, LD_IN, NO_BANK, | 
| 1240 | PC87365_REG_IN_CONFIG, | 1224 | PC87365_REG_IN_CONFIG, | 
| @@ -1246,7 +1230,7 @@ static void pc87360_init_client(struct i2c_client *client, int use_thermistors) | |||
| 1246 | reg = pc87360_read_value(data, LD_TEMP, NO_BANK, | 1230 | reg = pc87360_read_value(data, LD_TEMP, NO_BANK, | 
| 1247 | PC87365_REG_TEMP_CONFIG); | 1231 | PC87365_REG_TEMP_CONFIG); | 
| 1248 | if (reg & 0x01) { | 1232 | if (reg & 0x01) { | 
| 1249 | dev_dbg(&client->dev, "Forcibly enabling " | 1233 | dev_dbg(&pdev->dev, "Forcibly enabling " | 
| 1250 | "monitoring (TMS)\n"); | 1234 | "monitoring (TMS)\n"); | 
| 1251 | pc87360_write_value(data, LD_TEMP, NO_BANK, | 1235 | pc87360_write_value(data, LD_TEMP, NO_BANK, | 
| 1252 | PC87365_REG_TEMP_CONFIG, | 1236 | PC87365_REG_TEMP_CONFIG, | 
| @@ -1268,9 +1252,9 @@ static void pc87360_init_client(struct i2c_client *client, int use_thermistors) | |||
| 1268 | } | 1252 | } | 
| 1269 | } | 1253 | } | 
| 1270 | 1254 | ||
| 1271 | static void pc87360_autodiv(struct i2c_client *client, int nr) | 1255 | static void pc87360_autodiv(struct device *dev, int nr) | 
| 1272 | { | 1256 | { | 
| 1273 | struct pc87360_data *data = i2c_get_clientdata(client); | 1257 | struct pc87360_data *data = dev_get_drvdata(dev); | 
| 1274 | u8 old_min = data->fan_min[nr]; | 1258 | u8 old_min = data->fan_min[nr]; | 
| 1275 | 1259 | ||
| 1276 | /* Increase clock divider if needed and possible */ | 1260 | /* Increase clock divider if needed and possible */ | 
| @@ -1280,7 +1264,7 @@ static void pc87360_autodiv(struct i2c_client *client, int nr) | |||
| 1280 | data->fan_status[nr] += 0x20; | 1264 | data->fan_status[nr] += 0x20; | 
| 1281 | data->fan_min[nr] >>= 1; | 1265 | data->fan_min[nr] >>= 1; | 
| 1282 | data->fan[nr] >>= 1; | 1266 | data->fan[nr] >>= 1; | 
| 1283 | dev_dbg(&client->dev, "Increasing " | 1267 | dev_dbg(dev, "Increasing " | 
| 1284 | "clock divider to %d for fan %d\n", | 1268 | "clock divider to %d for fan %d\n", | 
| 1285 | FAN_DIV_FROM_REG(data->fan_status[nr]), nr+1); | 1269 | FAN_DIV_FROM_REG(data->fan_status[nr]), nr+1); | 
| 1286 | } | 1270 | } | 
| @@ -1292,7 +1276,7 @@ static void pc87360_autodiv(struct i2c_client *client, int nr) | |||
| 1292 | data->fan_status[nr] -= 0x20; | 1276 | data->fan_status[nr] -= 0x20; | 
| 1293 | data->fan_min[nr] <<= 1; | 1277 | data->fan_min[nr] <<= 1; | 
| 1294 | data->fan[nr] <<= 1; | 1278 | data->fan[nr] <<= 1; | 
| 1295 | dev_dbg(&client->dev, "Decreasing " | 1279 | dev_dbg(dev, "Decreasing " | 
| 1296 | "clock divider to %d for fan %d\n", | 1280 | "clock divider to %d for fan %d\n", | 
| 1297 | FAN_DIV_FROM_REG(data->fan_status[nr]), | 1281 | FAN_DIV_FROM_REG(data->fan_status[nr]), | 
| 1298 | nr+1); | 1282 | nr+1); | 
| @@ -1309,14 +1293,13 @@ static void pc87360_autodiv(struct i2c_client *client, int nr) | |||
| 1309 | 1293 | ||
| 1310 | static struct pc87360_data *pc87360_update_device(struct device *dev) | 1294 | static struct pc87360_data *pc87360_update_device(struct device *dev) | 
| 1311 | { | 1295 | { | 
| 1312 | struct i2c_client *client = to_i2c_client(dev); | 1296 | struct pc87360_data *data = dev_get_drvdata(dev); | 
| 1313 | struct pc87360_data *data = i2c_get_clientdata(client); | ||
| 1314 | u8 i; | 1297 | u8 i; | 
| 1315 | 1298 | ||
| 1316 | mutex_lock(&data->update_lock); | 1299 | mutex_lock(&data->update_lock); | 
| 1317 | 1300 | ||
| 1318 | if (time_after(jiffies, data->last_updated + HZ * 2) || !data->valid) { | 1301 | if (time_after(jiffies, data->last_updated + HZ * 2) || !data->valid) { | 
| 1319 | dev_dbg(&client->dev, "Data update\n"); | 1302 | dev_dbg(dev, "Data update\n"); | 
| 1320 | 1303 | ||
| 1321 | /* Fans */ | 1304 | /* Fans */ | 
| 1322 | for (i = 0; i < data->fannr; i++) { | 1305 | for (i = 0; i < data->fannr; i++) { | 
| @@ -1330,7 +1313,7 @@ static struct pc87360_data *pc87360_update_device(struct device *dev) | |||
| 1330 | LD_FAN, NO_BANK, | 1313 | LD_FAN, NO_BANK, | 
| 1331 | PC87360_REG_FAN_MIN(i)); | 1314 | PC87360_REG_FAN_MIN(i)); | 
| 1332 | /* Change clock divider if needed */ | 1315 | /* Change clock divider if needed */ | 
| 1333 | pc87360_autodiv(client, i); | 1316 | pc87360_autodiv(dev, i); | 
| 1334 | /* Clear bits and write new divider */ | 1317 | /* Clear bits and write new divider */ | 
| 1335 | pc87360_write_value(data, LD_FAN, NO_BANK, | 1318 | pc87360_write_value(data, LD_FAN, NO_BANK, | 
| 1336 | PC87360_REG_FAN_STATUS(i), | 1319 | PC87360_REG_FAN_STATUS(i), | 
| @@ -1418,9 +1401,53 @@ static struct pc87360_data *pc87360_update_device(struct device *dev) | |||
| 1418 | return data; | 1401 | return data; | 
| 1419 | } | 1402 | } | 
| 1420 | 1403 | ||
| 1404 | static int __init pc87360_device_add(unsigned short address) | ||
| 1405 | { | ||
| 1406 | struct resource res = { | ||
| 1407 | .name = "pc87360", | ||
| 1408 | .flags = IORESOURCE_IO, | ||
| 1409 | }; | ||
| 1410 | int err, i; | ||
| 1411 | |||
| 1412 | pdev = platform_device_alloc("pc87360", address); | ||
| 1413 | if (!pdev) { | ||
| 1414 | err = -ENOMEM; | ||
| 1415 | printk(KERN_ERR "pc87360: Device allocation failed\n"); | ||
| 1416 | goto exit; | ||
| 1417 | } | ||
| 1418 | |||
| 1419 | for (i = 0; i < 3; i++) { | ||
| 1420 | if (!extra_isa[i]) | ||
| 1421 | continue; | ||
| 1422 | res.start = extra_isa[i]; | ||
| 1423 | res.end = extra_isa[i] + PC87360_EXTENT - 1; | ||
| 1424 | err = platform_device_add_resources(pdev, &res, 1); | ||
| 1425 | if (err) { | ||
| 1426 | printk(KERN_ERR "pc87360: Device resource[%d] " | ||
| 1427 | "addition failed (%d)\n", i, err); | ||
| 1428 | goto exit_device_put; | ||
| 1429 | } | ||
| 1430 | } | ||
| 1431 | |||
| 1432 | err = platform_device_add(pdev); | ||
| 1433 | if (err) { | ||
| 1434 | printk(KERN_ERR "pc87360: Device addition failed (%d)\n", | ||
| 1435 | err); | ||
| 1436 | goto exit_device_put; | ||
| 1437 | } | ||
| 1438 | |||
| 1439 | return 0; | ||
| 1440 | |||
| 1441 | exit_device_put: | ||
| 1442 | platform_device_put(pdev); | ||
| 1443 | exit: | ||
| 1444 | return err; | ||
| 1445 | } | ||
| 1446 | |||
| 1421 | static int __init pc87360_init(void) | 1447 | static int __init pc87360_init(void) | 
| 1422 | { | 1448 | { | 
| 1423 | int i; | 1449 | int err, i; | 
| 1450 | unsigned short address = 0; | ||
| 1424 | 1451 | ||
| 1425 | if (pc87360_find(0x2e, &devid, extra_isa) | 1452 | if (pc87360_find(0x2e, &devid, extra_isa) | 
| 1426 | && pc87360_find(0x4e, &devid, extra_isa)) { | 1453 | && pc87360_find(0x4e, &devid, extra_isa)) { | 
| @@ -1443,12 +1470,27 @@ static int __init pc87360_init(void) | |||
| 1443 | return -ENODEV; | 1470 | return -ENODEV; | 
| 1444 | } | 1471 | } | 
| 1445 | 1472 | ||
| 1446 | return i2c_isa_add_driver(&pc87360_driver); | 1473 | err = platform_driver_register(&pc87360_driver); | 
| 1474 | if (err) | ||
| 1475 | goto exit; | ||
| 1476 | |||
| 1477 | /* Sets global pdev as a side effect */ | ||
| 1478 | err = pc87360_device_add(address); | ||
| 1479 | if (err) | ||
| 1480 | goto exit_driver; | ||
| 1481 | |||
| 1482 | return 0; | ||
| 1483 | |||
| 1484 | exit_driver: | ||
| 1485 | platform_driver_unregister(&pc87360_driver); | ||
| 1486 | exit: | ||
| 1487 | return err; | ||
| 1447 | } | 1488 | } | 
| 1448 | 1489 | ||
| 1449 | static void __exit pc87360_exit(void) | 1490 | static void __exit pc87360_exit(void) | 
| 1450 | { | 1491 | { | 
| 1451 | i2c_isa_del_driver(&pc87360_driver); | 1492 | platform_device_unregister(pdev); | 
| 1493 | platform_driver_unregister(&pc87360_driver); | ||
| 1452 | } | 1494 | } | 
| 1453 | 1495 | ||
| 1454 | 1496 | ||
