diff options
author | Jonathan Herman <hermanjl@cs.unc.edu> | 2013-01-17 16:15:55 -0500 |
---|---|---|
committer | Jonathan Herman <hermanjl@cs.unc.edu> | 2013-01-17 16:15:55 -0500 |
commit | 8dea78da5cee153b8af9c07a2745f6c55057fe12 (patch) | |
tree | a8f4d49d63b1ecc92f2fddceba0655b2472c5bd9 /drivers/hwmon/pc87427.c | |
parent | 406089d01562f1e2bf9f089fd7637009ebaad589 (diff) |
Patched in Tegra support.
Diffstat (limited to 'drivers/hwmon/pc87427.c')
-rw-r--r-- | drivers/hwmon/pc87427.c | 139 |
1 files changed, 75 insertions, 64 deletions
diff --git a/drivers/hwmon/pc87427.c b/drivers/hwmon/pc87427.c index 6086ad039d7..8da2181630b 100644 --- a/drivers/hwmon/pc87427.c +++ b/drivers/hwmon/pc87427.c | |||
@@ -46,11 +46,9 @@ static struct platform_device *pdev; | |||
46 | 46 | ||
47 | #define DRVNAME "pc87427" | 47 | #define DRVNAME "pc87427" |
48 | 48 | ||
49 | /* | 49 | /* The lock mutex protects both the I/O accesses (needed because the |
50 | * The lock mutex protects both the I/O accesses (needed because the | 50 | device is using banked registers) and the register cache (needed to keep |
51 | * device is using banked registers) and the register cache (needed to keep | 51 | the data in the registers and the cache in sync at any time). */ |
52 | * the data in the registers and the cache in sync at any time). | ||
53 | */ | ||
54 | struct pc87427_data { | 52 | struct pc87427_data { |
55 | struct device *hwmon_dev; | 53 | struct device *hwmon_dev; |
56 | struct mutex lock; | 54 | struct mutex lock; |
@@ -175,12 +173,10 @@ static inline void pc87427_write8_bank(struct pc87427_data *data, u8 ldi, | |||
175 | #define FAN_STATUS_LOSPD (1 << 1) | 173 | #define FAN_STATUS_LOSPD (1 << 1) |
176 | #define FAN_STATUS_MONEN (1 << 0) | 174 | #define FAN_STATUS_MONEN (1 << 0) |
177 | 175 | ||
178 | /* | 176 | /* Dedicated function to read all registers related to a given fan input. |
179 | * Dedicated function to read all registers related to a given fan input. | 177 | This saves us quite a few locks and bank selections. |
180 | * This saves us quite a few locks and bank selections. | 178 | Must be called with data->lock held. |
181 | * Must be called with data->lock held. | 179 | nr is from 0 to 7 */ |
182 | * nr is from 0 to 7 | ||
183 | */ | ||
184 | static void pc87427_readall_fan(struct pc87427_data *data, u8 nr) | 180 | static void pc87427_readall_fan(struct pc87427_data *data, u8 nr) |
185 | { | 181 | { |
186 | int iobase = data->address[LD_FAN]; | 182 | int iobase = data->address[LD_FAN]; |
@@ -193,10 +189,8 @@ static void pc87427_readall_fan(struct pc87427_data *data, u8 nr) | |||
193 | outb(data->fan_status[nr], iobase + PC87427_REG_FAN_STATUS); | 189 | outb(data->fan_status[nr], iobase + PC87427_REG_FAN_STATUS); |
194 | } | 190 | } |
195 | 191 | ||
196 | /* | 192 | /* The 2 LSB of fan speed registers are used for something different. |
197 | * The 2 LSB of fan speed registers are used for something different. | 193 | The actual 2 LSB of the measurements are not available. */ |
198 | * The actual 2 LSB of the measurements are not available. | ||
199 | */ | ||
200 | static inline unsigned long fan_from_reg(u16 reg) | 194 | static inline unsigned long fan_from_reg(u16 reg) |
201 | { | 195 | { |
202 | reg &= 0xfffc; | 196 | reg &= 0xfffc; |
@@ -230,12 +224,10 @@ static inline u16 fan_to_reg(unsigned long val) | |||
230 | #define PWM_MODE_OFF (2 << 4) | 224 | #define PWM_MODE_OFF (2 << 4) |
231 | #define PWM_MODE_ON (7 << 4) | 225 | #define PWM_MODE_ON (7 << 4) |
232 | 226 | ||
233 | /* | 227 | /* Dedicated function to read all registers related to a given PWM output. |
234 | * Dedicated function to read all registers related to a given PWM output. | 228 | This saves us quite a few locks and bank selections. |
235 | * This saves us quite a few locks and bank selections. | 229 | Must be called with data->lock held. |
236 | * Must be called with data->lock held. | 230 | nr is from 0 to 3 */ |
237 | * nr is from 0 to 3 | ||
238 | */ | ||
239 | static void pc87427_readall_pwm(struct pc87427_data *data, u8 nr) | 231 | static void pc87427_readall_pwm(struct pc87427_data *data, u8 nr) |
240 | { | 232 | { |
241 | int iobase = data->address[LD_FAN]; | 233 | int iobase = data->address[LD_FAN]; |
@@ -294,12 +286,10 @@ static inline u8 pwm_enable_to_reg(unsigned long val, u8 pwmval) | |||
294 | #define TEMP_TYPE_REMOTE_DIODE (2 << 5) | 286 | #define TEMP_TYPE_REMOTE_DIODE (2 << 5) |
295 | #define TEMP_TYPE_LOCAL_DIODE (3 << 5) | 287 | #define TEMP_TYPE_LOCAL_DIODE (3 << 5) |
296 | 288 | ||
297 | /* | 289 | /* Dedicated function to read all registers related to a given temperature |
298 | * Dedicated function to read all registers related to a given temperature | 290 | input. This saves us quite a few locks and bank selections. |
299 | * input. This saves us quite a few locks and bank selections. | 291 | Must be called with data->lock held. |
300 | * Must be called with data->lock held. | 292 | nr is from 0 to 5 */ |
301 | * nr is from 0 to 5 | ||
302 | */ | ||
303 | static void pc87427_readall_temp(struct pc87427_data *data, u8 nr) | 293 | static void pc87427_readall_temp(struct pc87427_data *data, u8 nr) |
304 | { | 294 | { |
305 | int iobase = data->address[LD_TEMP]; | 295 | int iobase = data->address[LD_TEMP]; |
@@ -328,10 +318,8 @@ static inline unsigned int temp_type_from_reg(u8 reg) | |||
328 | } | 318 | } |
329 | } | 319 | } |
330 | 320 | ||
331 | /* | 321 | /* We assume 8-bit thermal sensors; 9-bit thermal sensors are possible |
332 | * We assume 8-bit thermal sensors; 9-bit thermal sensors are possible | 322 | too, but I have no idea how to figure out when they are used. */ |
333 | * too, but I have no idea how to figure out when they are used. | ||
334 | */ | ||
335 | static inline long temp_from_reg(s16 reg) | 323 | static inline long temp_from_reg(s16 reg) |
336 | { | 324 | { |
337 | return reg * 1000 / 256; | 325 | return reg * 1000 / 256; |
@@ -430,16 +418,14 @@ static ssize_t set_fan_min(struct device *dev, struct device_attribute | |||
430 | unsigned long val; | 418 | unsigned long val; |
431 | int iobase = data->address[LD_FAN]; | 419 | int iobase = data->address[LD_FAN]; |
432 | 420 | ||
433 | if (kstrtoul(buf, 10, &val) < 0) | 421 | if (strict_strtoul(buf, 10, &val) < 0) |
434 | return -EINVAL; | 422 | return -EINVAL; |
435 | 423 | ||
436 | mutex_lock(&data->lock); | 424 | mutex_lock(&data->lock); |
437 | outb(BANK_FM(nr), iobase + PC87427_REG_BANK); | 425 | outb(BANK_FM(nr), iobase + PC87427_REG_BANK); |
438 | /* | 426 | /* The low speed limit registers are read-only while monitoring |
439 | * The low speed limit registers are read-only while monitoring | 427 | is enabled, so we have to disable monitoring, then change the |
440 | * is enabled, so we have to disable monitoring, then change the | 428 | limit, and finally enable monitoring again. */ |
441 | * limit, and finally enable monitoring again. | ||
442 | */ | ||
443 | outb(0, iobase + PC87427_REG_FAN_STATUS); | 429 | outb(0, iobase + PC87427_REG_FAN_STATUS); |
444 | data->fan_min[nr] = fan_to_reg(val); | 430 | data->fan_min[nr] = fan_to_reg(val); |
445 | outw(data->fan_min[nr], iobase + PC87427_REG_FAN_MIN); | 431 | outw(data->fan_min[nr], iobase + PC87427_REG_FAN_MIN); |
@@ -556,10 +542,8 @@ static const struct attribute_group pc87427_group_fan[8] = { | |||
556 | { .attrs = pc87427_attributes_fan[7] }, | 542 | { .attrs = pc87427_attributes_fan[7] }, |
557 | }; | 543 | }; |
558 | 544 | ||
559 | /* | 545 | /* Must be called with data->lock held and pc87427_readall_pwm() freshly |
560 | * Must be called with data->lock held and pc87427_readall_pwm() freshly | 546 | called */ |
561 | * called | ||
562 | */ | ||
563 | static void update_pwm_enable(struct pc87427_data *data, int nr, u8 mode) | 547 | static void update_pwm_enable(struct pc87427_data *data, int nr, u8 mode) |
564 | { | 548 | { |
565 | int iobase = data->address[LD_FAN]; | 549 | int iobase = data->address[LD_FAN]; |
@@ -588,7 +572,7 @@ static ssize_t set_pwm_enable(struct device *dev, struct device_attribute | |||
588 | int nr = to_sensor_dev_attr(devattr)->index; | 572 | int nr = to_sensor_dev_attr(devattr)->index; |
589 | unsigned long val; | 573 | unsigned long val; |
590 | 574 | ||
591 | if (kstrtoul(buf, 10, &val) < 0 || val > 2) | 575 | if (strict_strtoul(buf, 10, &val) < 0 || val > 2) |
592 | return -EINVAL; | 576 | return -EINVAL; |
593 | /* Can't go to automatic mode if it isn't configured */ | 577 | /* Can't go to automatic mode if it isn't configured */ |
594 | if (val == 2 && !(data->pwm_auto_ok & (1 << nr))) | 578 | if (val == 2 && !(data->pwm_auto_ok & (1 << nr))) |
@@ -620,7 +604,7 @@ static ssize_t set_pwm(struct device *dev, struct device_attribute | |||
620 | int iobase = data->address[LD_FAN]; | 604 | int iobase = data->address[LD_FAN]; |
621 | u8 mode; | 605 | u8 mode; |
622 | 606 | ||
623 | if (kstrtoul(buf, 10, &val) < 0 || val > 0xff) | 607 | if (strict_strtoul(buf, 10, &val) < 0 || val > 0xff) |
624 | return -EINVAL; | 608 | return -EINVAL; |
625 | 609 | ||
626 | mutex_lock(&data->lock); | 610 | mutex_lock(&data->lock); |
@@ -956,31 +940,47 @@ static DEVICE_ATTR(name, S_IRUGO, show_name, NULL); | |||
956 | * Device detection, attach and detach | 940 | * Device detection, attach and detach |
957 | */ | 941 | */ |
958 | 942 | ||
959 | static int pc87427_request_regions(struct platform_device *pdev, | 943 | static void pc87427_release_regions(struct platform_device *pdev, int count) |
960 | int count) | ||
961 | { | 944 | { |
962 | struct resource *res; | 945 | struct resource *res; |
963 | int i; | 946 | int i; |
964 | 947 | ||
965 | for (i = 0; i < count; i++) { | 948 | for (i = 0; i < count; i++) { |
966 | res = platform_get_resource(pdev, IORESOURCE_IO, i); | 949 | res = platform_get_resource(pdev, IORESOURCE_IO, i); |
950 | release_region(res->start, resource_size(res)); | ||
951 | } | ||
952 | } | ||
953 | |||
954 | static int __devinit pc87427_request_regions(struct platform_device *pdev, | ||
955 | int count) | ||
956 | { | ||
957 | struct resource *res; | ||
958 | int i, err = 0; | ||
959 | |||
960 | for (i = 0; i < count; i++) { | ||
961 | res = platform_get_resource(pdev, IORESOURCE_IO, i); | ||
967 | if (!res) { | 962 | if (!res) { |
963 | err = -ENOENT; | ||
968 | dev_err(&pdev->dev, "Missing resource #%d\n", i); | 964 | dev_err(&pdev->dev, "Missing resource #%d\n", i); |
969 | return -ENOENT; | 965 | break; |
970 | } | 966 | } |
971 | if (!devm_request_region(&pdev->dev, res->start, | 967 | if (!request_region(res->start, resource_size(res), DRVNAME)) { |
972 | resource_size(res), DRVNAME)) { | 968 | err = -EBUSY; |
973 | dev_err(&pdev->dev, | 969 | dev_err(&pdev->dev, |
974 | "Failed to request region 0x%lx-0x%lx\n", | 970 | "Failed to request region 0x%lx-0x%lx\n", |
975 | (unsigned long)res->start, | 971 | (unsigned long)res->start, |
976 | (unsigned long)res->end); | 972 | (unsigned long)res->end); |
977 | return -EBUSY; | 973 | break; |
978 | } | 974 | } |
979 | } | 975 | } |
980 | return 0; | 976 | |
977 | if (err && i) | ||
978 | pc87427_release_regions(pdev, i); | ||
979 | |||
980 | return err; | ||
981 | } | 981 | } |
982 | 982 | ||
983 | static void pc87427_init_device(struct device *dev) | 983 | static void __devinit pc87427_init_device(struct device *dev) |
984 | { | 984 | { |
985 | struct pc87427_sio_data *sio_data = dev->platform_data; | 985 | struct pc87427_sio_data *sio_data = dev->platform_data; |
986 | struct pc87427_data *data = dev_get_drvdata(dev); | 986 | struct pc87427_data *data = dev_get_drvdata(dev); |
@@ -1023,11 +1023,9 @@ static void pc87427_init_device(struct device *dev) | |||
1023 | if (reg & PWM_ENABLE_CTLEN) | 1023 | if (reg & PWM_ENABLE_CTLEN) |
1024 | data->pwm_enabled |= (1 << i); | 1024 | data->pwm_enabled |= (1 << i); |
1025 | 1025 | ||
1026 | /* | 1026 | /* We don't expose an interface to reconfigure the automatic |
1027 | * We don't expose an interface to reconfigure the automatic | 1027 | fan control mode, so only allow to return to this mode if |
1028 | * fan control mode, so only allow to return to this mode if | 1028 | it was originally set. */ |
1029 | * it was originally set. | ||
1030 | */ | ||
1031 | if ((reg & PWM_ENABLE_MODE_MASK) == PWM_MODE_AUTO) { | 1029 | if ((reg & PWM_ENABLE_MODE_MASK) == PWM_MODE_AUTO) { |
1032 | dev_dbg(dev, "PWM%d is in automatic control mode\n", | 1030 | dev_dbg(dev, "PWM%d is in automatic control mode\n", |
1033 | i + 1); | 1031 | i + 1); |
@@ -1072,17 +1070,17 @@ static void pc87427_remove_files(struct device *dev) | |||
1072 | } | 1070 | } |
1073 | } | 1071 | } |
1074 | 1072 | ||
1075 | static int pc87427_probe(struct platform_device *pdev) | 1073 | static int __devinit pc87427_probe(struct platform_device *pdev) |
1076 | { | 1074 | { |
1077 | struct pc87427_sio_data *sio_data = pdev->dev.platform_data; | 1075 | struct pc87427_sio_data *sio_data = pdev->dev.platform_data; |
1078 | struct pc87427_data *data; | 1076 | struct pc87427_data *data; |
1079 | int i, err, res_count; | 1077 | int i, err, res_count; |
1080 | 1078 | ||
1081 | data = devm_kzalloc(&pdev->dev, sizeof(struct pc87427_data), | 1079 | data = kzalloc(sizeof(struct pc87427_data), GFP_KERNEL); |
1082 | GFP_KERNEL); | ||
1083 | if (!data) { | 1080 | if (!data) { |
1081 | err = -ENOMEM; | ||
1084 | pr_err("Out of memory\n"); | 1082 | pr_err("Out of memory\n"); |
1085 | return -ENOMEM; | 1083 | goto exit; |
1086 | } | 1084 | } |
1087 | 1085 | ||
1088 | data->address[0] = sio_data->address[0]; | 1086 | data->address[0] = sio_data->address[0]; |
@@ -1091,7 +1089,7 @@ static int pc87427_probe(struct platform_device *pdev) | |||
1091 | 1089 | ||
1092 | err = pc87427_request_regions(pdev, res_count); | 1090 | err = pc87427_request_regions(pdev, res_count); |
1093 | if (err) | 1091 | if (err) |
1094 | return err; | 1092 | goto exit_kfree; |
1095 | 1093 | ||
1096 | mutex_init(&data->lock); | 1094 | mutex_init(&data->lock); |
1097 | data->name = "pc87427"; | 1095 | data->name = "pc87427"; |
@@ -1101,7 +1099,7 @@ static int pc87427_probe(struct platform_device *pdev) | |||
1101 | /* Register sysfs hooks */ | 1099 | /* Register sysfs hooks */ |
1102 | err = device_create_file(&pdev->dev, &dev_attr_name); | 1100 | err = device_create_file(&pdev->dev, &dev_attr_name); |
1103 | if (err) | 1101 | if (err) |
1104 | return err; | 1102 | goto exit_release_region; |
1105 | for (i = 0; i < 8; i++) { | 1103 | for (i = 0; i < 8; i++) { |
1106 | if (!(data->fan_enabled & (1 << i))) | 1104 | if (!(data->fan_enabled & (1 << i))) |
1107 | continue; | 1105 | continue; |
@@ -1138,15 +1136,28 @@ static int pc87427_probe(struct platform_device *pdev) | |||
1138 | 1136 | ||
1139 | exit_remove_files: | 1137 | exit_remove_files: |
1140 | pc87427_remove_files(&pdev->dev); | 1138 | pc87427_remove_files(&pdev->dev); |
1139 | exit_release_region: | ||
1140 | pc87427_release_regions(pdev, res_count); | ||
1141 | exit_kfree: | ||
1142 | platform_set_drvdata(pdev, NULL); | ||
1143 | kfree(data); | ||
1144 | exit: | ||
1141 | return err; | 1145 | return err; |
1142 | } | 1146 | } |
1143 | 1147 | ||
1144 | static int pc87427_remove(struct platform_device *pdev) | 1148 | static int __devexit pc87427_remove(struct platform_device *pdev) |
1145 | { | 1149 | { |
1146 | struct pc87427_data *data = platform_get_drvdata(pdev); | 1150 | struct pc87427_data *data = platform_get_drvdata(pdev); |
1151 | int res_count; | ||
1152 | |||
1153 | res_count = (data->address[0] != 0) + (data->address[1] != 0); | ||
1147 | 1154 | ||
1148 | hwmon_device_unregister(data->hwmon_dev); | 1155 | hwmon_device_unregister(data->hwmon_dev); |
1149 | pc87427_remove_files(&pdev->dev); | 1156 | pc87427_remove_files(&pdev->dev); |
1157 | platform_set_drvdata(pdev, NULL); | ||
1158 | kfree(data); | ||
1159 | |||
1160 | pc87427_release_regions(pdev, res_count); | ||
1150 | 1161 | ||
1151 | return 0; | 1162 | return 0; |
1152 | } | 1163 | } |
@@ -1158,7 +1169,7 @@ static struct platform_driver pc87427_driver = { | |||
1158 | .name = DRVNAME, | 1169 | .name = DRVNAME, |
1159 | }, | 1170 | }, |
1160 | .probe = pc87427_probe, | 1171 | .probe = pc87427_probe, |
1161 | .remove = pc87427_remove, | 1172 | .remove = __devexit_p(pc87427_remove), |
1162 | }; | 1173 | }; |
1163 | 1174 | ||
1164 | static int __init pc87427_device_add(const struct pc87427_sio_data *sio_data) | 1175 | static int __init pc87427_device_add(const struct pc87427_sio_data *sio_data) |