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/macintosh | |
| parent | 406089d01562f1e2bf9f089fd7637009ebaad589 (diff) | |
Patched in Tegra support.
Diffstat (limited to 'drivers/macintosh')
37 files changed, 701 insertions, 3319 deletions
diff --git a/drivers/macintosh/Kconfig b/drivers/macintosh/Kconfig index a555da64224..fa51af11c6f 100644 --- a/drivers/macintosh/Kconfig +++ b/drivers/macintosh/Kconfig | |||
| @@ -204,14 +204,11 @@ config THERM_ADT746X | |||
| 204 | better fan behaviour by default, and some manual control. | 204 | better fan behaviour by default, and some manual control. |
| 205 | 205 | ||
| 206 | config THERM_PM72 | 206 | config THERM_PM72 |
| 207 | tristate "Support for thermal management on PowerMac G5 (AGP)" | 207 | tristate "Support for thermal management on PowerMac G5" |
| 208 | depends on I2C && I2C_POWERMAC && PPC_PMAC64 | 208 | depends on I2C && I2C_POWERMAC && PPC_PMAC64 |
| 209 | default n | ||
| 210 | help | 209 | help |
| 211 | This driver provides thermostat and fan control for the desktop | 210 | This driver provides thermostat and fan control for the desktop |
| 212 | G5 machines. | 211 | G5 machines. |
| 213 | |||
| 214 | This is deprecated, use windfarm instead. | ||
| 215 | 212 | ||
| 216 | config WINDFARM | 213 | config WINDFARM |
| 217 | tristate "New PowerMac thermal control infrastructure" | 214 | tristate "New PowerMac thermal control infrastructure" |
| @@ -224,22 +221,6 @@ config WINDFARM_PM81 | |||
| 224 | help | 221 | help |
| 225 | This driver provides thermal control for the iMacG5 | 222 | This driver provides thermal control for the iMacG5 |
| 226 | 223 | ||
| 227 | config WINDFARM_PM72 | ||
| 228 | tristate "Support for thermal management on PowerMac G5 (AGP)" | ||
| 229 | depends on WINDFARM && I2C && CPU_FREQ_PMAC64 && ADB_PMU | ||
| 230 | select I2C_POWERMAC | ||
| 231 | help | ||
| 232 | This driver provides thermal control for the PowerMac G5 | ||
| 233 | "AGP" variants (PowerMac 7,2 and 7,3) | ||
| 234 | |||
| 235 | config WINDFARM_RM31 | ||
| 236 | tristate "Support for thermal management on Xserve G5" | ||
| 237 | depends on WINDFARM && I2C && CPU_FREQ_PMAC64 && ADB_PMU | ||
| 238 | select I2C_POWERMAC | ||
| 239 | help | ||
| 240 | This driver provides thermal control for the Xserve G5 | ||
| 241 | (RackMac3,1) | ||
| 242 | |||
| 243 | config WINDFARM_PM91 | 224 | config WINDFARM_PM91 |
| 244 | tristate "Support for thermal management on PowerMac9,1" | 225 | tristate "Support for thermal management on PowerMac9,1" |
| 245 | depends on WINDFARM && I2C && CPU_FREQ_PMAC64 && PMAC_SMU | 226 | depends on WINDFARM && I2C && CPU_FREQ_PMAC64 && PMAC_SMU |
diff --git a/drivers/macintosh/Makefile b/drivers/macintosh/Makefile index 6753b65f8ed..6652a6ebb6f 100644 --- a/drivers/macintosh/Makefile +++ b/drivers/macintosh/Makefile | |||
| @@ -29,20 +29,6 @@ obj-$(CONFIG_THERM_PM72) += therm_pm72.o | |||
| 29 | obj-$(CONFIG_THERM_WINDTUNNEL) += therm_windtunnel.o | 29 | obj-$(CONFIG_THERM_WINDTUNNEL) += therm_windtunnel.o |
| 30 | obj-$(CONFIG_THERM_ADT746X) += therm_adt746x.o | 30 | obj-$(CONFIG_THERM_ADT746X) += therm_adt746x.o |
| 31 | obj-$(CONFIG_WINDFARM) += windfarm_core.o | 31 | obj-$(CONFIG_WINDFARM) += windfarm_core.o |
| 32 | obj-$(CONFIG_WINDFARM_PM72) += windfarm_fcu_controls.o \ | ||
| 33 | windfarm_ad7417_sensor.o \ | ||
| 34 | windfarm_lm75_sensor.o \ | ||
| 35 | windfarm_max6690_sensor.o \ | ||
| 36 | windfarm_pid.o \ | ||
| 37 | windfarm_cpufreq_clamp.o \ | ||
| 38 | windfarm_pm72.o | ||
| 39 | obj-$(CONFIG_WINDFARM_RM31) += windfarm_fcu_controls.o \ | ||
| 40 | windfarm_ad7417_sensor.o \ | ||
| 41 | windfarm_lm75_sensor.o \ | ||
| 42 | windfarm_lm87_sensor.o \ | ||
| 43 | windfarm_pid.o \ | ||
| 44 | windfarm_cpufreq_clamp.o \ | ||
| 45 | windfarm_rm31.o | ||
| 46 | obj-$(CONFIG_WINDFARM_PM81) += windfarm_smu_controls.o \ | 32 | obj-$(CONFIG_WINDFARM_PM81) += windfarm_smu_controls.o \ |
| 47 | windfarm_smu_sensors.o \ | 33 | windfarm_smu_sensors.o \ |
| 48 | windfarm_lm75_sensor.o windfarm_pid.o \ | 34 | windfarm_lm75_sensor.o windfarm_pid.o \ |
diff --git a/drivers/macintosh/adb.c b/drivers/macintosh/adb.c index b026896206c..75049e76519 100644 --- a/drivers/macintosh/adb.c +++ b/drivers/macintosh/adb.c | |||
| @@ -710,7 +710,7 @@ static ssize_t adb_read(struct file *file, char __user *buf, | |||
| 710 | req = NULL; | 710 | req = NULL; |
| 711 | spin_lock_irqsave(&state->lock, flags); | 711 | spin_lock_irqsave(&state->lock, flags); |
| 712 | add_wait_queue(&state->wait_queue, &wait); | 712 | add_wait_queue(&state->wait_queue, &wait); |
| 713 | set_current_state(TASK_INTERRUPTIBLE); | 713 | current->state = TASK_INTERRUPTIBLE; |
| 714 | 714 | ||
| 715 | for (;;) { | 715 | for (;;) { |
| 716 | req = state->completed; | 716 | req = state->completed; |
| @@ -734,7 +734,7 @@ static ssize_t adb_read(struct file *file, char __user *buf, | |||
| 734 | spin_lock_irqsave(&state->lock, flags); | 734 | spin_lock_irqsave(&state->lock, flags); |
| 735 | } | 735 | } |
| 736 | 736 | ||
| 737 | set_current_state(TASK_RUNNING); | 737 | current->state = TASK_RUNNING; |
| 738 | remove_wait_queue(&state->wait_queue, &wait); | 738 | remove_wait_queue(&state->wait_queue, &wait); |
| 739 | spin_unlock_irqrestore(&state->lock, flags); | 739 | spin_unlock_irqrestore(&state->lock, flags); |
| 740 | 740 | ||
diff --git a/drivers/macintosh/ams/ams-core.c b/drivers/macintosh/ams/ams-core.c index 36a4fdddd64..399beb1638d 100644 --- a/drivers/macintosh/ams/ams-core.c +++ b/drivers/macintosh/ams/ams-core.c | |||
| @@ -31,7 +31,7 @@ | |||
| 31 | /* There is only one motion sensor per machine */ | 31 | /* There is only one motion sensor per machine */ |
| 32 | struct ams ams_info; | 32 | struct ams ams_info; |
| 33 | 33 | ||
| 34 | static bool verbose; | 34 | static unsigned int verbose; |
| 35 | module_param(verbose, bool, 0644); | 35 | module_param(verbose, bool, 0644); |
| 36 | MODULE_PARM_DESC(verbose, "Show free falls and shocks in kernel output"); | 36 | MODULE_PARM_DESC(verbose, "Show free falls and shocks in kernel output"); |
| 37 | 37 | ||
| @@ -226,7 +226,7 @@ void ams_sensor_detach(void) | |||
| 226 | * We do this after ams_info.exit(), because an interrupt might | 226 | * We do this after ams_info.exit(), because an interrupt might |
| 227 | * have arrived before disabling them. | 227 | * have arrived before disabling them. |
| 228 | */ | 228 | */ |
| 229 | flush_work(&ams_info.worker); | 229 | flush_work_sync(&ams_info.worker); |
| 230 | 230 | ||
| 231 | /* Remove device */ | 231 | /* Remove device */ |
| 232 | of_device_unregister(ams_info.of_dev); | 232 | of_device_unregister(ams_info.of_dev); |
diff --git a/drivers/macintosh/ams/ams-i2c.c b/drivers/macintosh/ams/ams-i2c.c index 978eda8d667..abeecd27b48 100644 --- a/drivers/macintosh/ams/ams-i2c.c +++ b/drivers/macintosh/ams/ams-i2c.c | |||
| @@ -65,7 +65,7 @@ static int ams_i2c_probe(struct i2c_client *client, | |||
| 65 | static int ams_i2c_remove(struct i2c_client *client); | 65 | static int ams_i2c_remove(struct i2c_client *client); |
| 66 | 66 | ||
| 67 | static const struct i2c_device_id ams_id[] = { | 67 | static const struct i2c_device_id ams_id[] = { |
| 68 | { "MAC,accelerometer_1", 0 }, | 68 | { "ams", 0 }, |
| 69 | { } | 69 | { } |
| 70 | }; | 70 | }; |
| 71 | MODULE_DEVICE_TABLE(i2c, ams_id); | 71 | MODULE_DEVICE_TABLE(i2c, ams_id); |
diff --git a/drivers/macintosh/ams/ams-input.c b/drivers/macintosh/ams/ams-input.c index b27e530a87a..8a712392cd3 100644 --- a/drivers/macintosh/ams/ams-input.c +++ b/drivers/macintosh/ams/ams-input.c | |||
| @@ -19,11 +19,11 @@ | |||
| 19 | 19 | ||
| 20 | #include "ams.h" | 20 | #include "ams.h" |
| 21 | 21 | ||
| 22 | static bool joystick; | 22 | static unsigned int joystick; |
| 23 | module_param(joystick, bool, S_IRUGO); | 23 | module_param(joystick, bool, S_IRUGO); |
| 24 | MODULE_PARM_DESC(joystick, "Enable the input class device on module load"); | 24 | MODULE_PARM_DESC(joystick, "Enable the input class device on module load"); |
| 25 | 25 | ||
| 26 | static bool invert; | 26 | static unsigned int invert; |
| 27 | module_param(invert, bool, S_IWUSR | S_IRUGO); | 27 | module_param(invert, bool, S_IWUSR | S_IRUGO); |
| 28 | MODULE_PARM_DESC(invert, "Invert input data on X and Y axis"); | 28 | MODULE_PARM_DESC(invert, "Invert input data on X and Y axis"); |
| 29 | 29 | ||
diff --git a/drivers/macintosh/macio-adb.c b/drivers/macintosh/macio-adb.c index 87de8d9bcfa..b6ef8f59076 100644 --- a/drivers/macintosh/macio-adb.c +++ b/drivers/macintosh/macio-adb.c | |||
| @@ -14,6 +14,7 @@ | |||
| 14 | #include <asm/pgtable.h> | 14 | #include <asm/pgtable.h> |
| 15 | #include <asm/hydra.h> | 15 | #include <asm/hydra.h> |
| 16 | #include <asm/irq.h> | 16 | #include <asm/irq.h> |
| 17 | #include <asm/system.h> | ||
| 17 | #include <linux/init.h> | 18 | #include <linux/init.h> |
| 18 | #include <linux/ioport.h> | 19 | #include <linux/ioport.h> |
| 19 | 20 | ||
diff --git a/drivers/macintosh/macio_asic.c b/drivers/macintosh/macio_asic.c index ac5c8793986..4daf9e5a773 100644 --- a/drivers/macintosh/macio_asic.c +++ b/drivers/macintosh/macio_asic.c | |||
| @@ -137,7 +137,7 @@ extern struct device_attribute macio_dev_attrs[]; | |||
| 137 | struct bus_type macio_bus_type = { | 137 | struct bus_type macio_bus_type = { |
| 138 | .name = "macio", | 138 | .name = "macio", |
| 139 | .match = macio_bus_match, | 139 | .match = macio_bus_match, |
| 140 | .uevent = of_device_uevent_modalias, | 140 | .uevent = of_device_uevent, |
| 141 | .probe = macio_device_probe, | 141 | .probe = macio_device_probe, |
| 142 | .remove = macio_device_remove, | 142 | .remove = macio_device_remove, |
| 143 | .shutdown = macio_device_shutdown, | 143 | .shutdown = macio_device_shutdown, |
| @@ -679,7 +679,7 @@ void macio_release_resources(struct macio_dev *dev) | |||
| 679 | 679 | ||
| 680 | #ifdef CONFIG_PCI | 680 | #ifdef CONFIG_PCI |
| 681 | 681 | ||
| 682 | static int macio_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) | 682 | static int __devinit macio_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) |
| 683 | { | 683 | { |
| 684 | struct device_node* np; | 684 | struct device_node* np; |
| 685 | struct macio_chip* chip; | 685 | struct macio_chip* chip; |
| @@ -739,7 +739,7 @@ static int macio_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent | |||
| 739 | return 0; | 739 | return 0; |
| 740 | } | 740 | } |
| 741 | 741 | ||
| 742 | static void macio_pci_remove(struct pci_dev* pdev) | 742 | static void __devexit macio_pci_remove(struct pci_dev* pdev) |
| 743 | { | 743 | { |
| 744 | panic("removing of macio-asic not supported !\n"); | 744 | panic("removing of macio-asic not supported !\n"); |
| 745 | } | 745 | } |
| @@ -748,7 +748,7 @@ static void macio_pci_remove(struct pci_dev* pdev) | |||
| 748 | * MacIO is matched against any Apple ID, it's probe() function | 748 | * MacIO is matched against any Apple ID, it's probe() function |
| 749 | * will then decide wether it applies or not | 749 | * will then decide wether it applies or not |
| 750 | */ | 750 | */ |
| 751 | static const struct pci_device_id pci_ids[] = { { | 751 | static const struct pci_device_id __devinitdata pci_ids [] = { { |
| 752 | .vendor = PCI_VENDOR_ID_APPLE, | 752 | .vendor = PCI_VENDOR_ID_APPLE, |
| 753 | .device = PCI_ANY_ID, | 753 | .device = PCI_ANY_ID, |
| 754 | .subvendor = PCI_ANY_ID, | 754 | .subvendor = PCI_ANY_ID, |
diff --git a/drivers/macintosh/mediabay.c b/drivers/macintosh/mediabay.c index d98e566a8f5..2fd435bc542 100644 --- a/drivers/macintosh/mediabay.c +++ b/drivers/macintosh/mediabay.c | |||
| @@ -63,7 +63,7 @@ struct media_bay_info { | |||
| 63 | int value_count; | 63 | int value_count; |
| 64 | int timer; | 64 | int timer; |
| 65 | struct macio_dev *mdev; | 65 | struct macio_dev *mdev; |
| 66 | const struct mb_ops* ops; | 66 | struct mb_ops* ops; |
| 67 | int index; | 67 | int index; |
| 68 | int cached_gpio; | 68 | int cached_gpio; |
| 69 | int sleeping; | 69 | int sleeping; |
| @@ -356,7 +356,7 @@ static void poll_media_bay(struct media_bay_info* bay) | |||
| 356 | static char *mb_content_types[] = { | 356 | static char *mb_content_types[] = { |
| 357 | "a floppy drive", | 357 | "a floppy drive", |
| 358 | "a floppy drive", | 358 | "a floppy drive", |
| 359 | "an unsupported audio device", | 359 | "an unsuported audio device", |
| 360 | "an ATA device", | 360 | "an ATA device", |
| 361 | "an unsupported PCI device", | 361 | "an unsupported PCI device", |
| 362 | "an unknown device", | 362 | "an unknown device", |
| @@ -556,8 +556,7 @@ static int media_bay_task(void *x) | |||
| 556 | return 0; | 556 | return 0; |
| 557 | } | 557 | } |
| 558 | 558 | ||
| 559 | static int media_bay_attach(struct macio_dev *mdev, | 559 | static int __devinit media_bay_attach(struct macio_dev *mdev, const struct of_device_id *match) |
| 560 | const struct of_device_id *match) | ||
| 561 | { | 560 | { |
| 562 | struct media_bay_info* bay; | 561 | struct media_bay_info* bay; |
| 563 | u32 __iomem *regbase; | 562 | u32 __iomem *regbase; |
| @@ -670,7 +669,7 @@ static int media_bay_resume(struct macio_dev *mdev) | |||
| 670 | 669 | ||
| 671 | /* Definitions of "ops" structures. | 670 | /* Definitions of "ops" structures. |
| 672 | */ | 671 | */ |
| 673 | static const struct mb_ops ohare_mb_ops = { | 672 | static struct mb_ops ohare_mb_ops = { |
| 674 | .name = "Ohare", | 673 | .name = "Ohare", |
| 675 | .content = ohare_mb_content, | 674 | .content = ohare_mb_content, |
| 676 | .power = ohare_mb_power, | 675 | .power = ohare_mb_power, |
| @@ -679,7 +678,7 @@ static const struct mb_ops ohare_mb_ops = { | |||
| 679 | .un_reset_ide = ohare_mb_un_reset_ide, | 678 | .un_reset_ide = ohare_mb_un_reset_ide, |
| 680 | }; | 679 | }; |
| 681 | 680 | ||
| 682 | static const struct mb_ops heathrow_mb_ops = { | 681 | static struct mb_ops heathrow_mb_ops = { |
| 683 | .name = "Heathrow", | 682 | .name = "Heathrow", |
| 684 | .content = heathrow_mb_content, | 683 | .content = heathrow_mb_content, |
| 685 | .power = heathrow_mb_power, | 684 | .power = heathrow_mb_power, |
| @@ -688,7 +687,7 @@ static const struct mb_ops heathrow_mb_ops = { | |||
| 688 | .un_reset_ide = heathrow_mb_un_reset_ide, | 687 | .un_reset_ide = heathrow_mb_un_reset_ide, |
| 689 | }; | 688 | }; |
| 690 | 689 | ||
| 691 | static const struct mb_ops keylargo_mb_ops = { | 690 | static struct mb_ops keylargo_mb_ops = { |
| 692 | .name = "KeyLargo", | 691 | .name = "KeyLargo", |
| 693 | .init = keylargo_mb_init, | 692 | .init = keylargo_mb_init, |
| 694 | .content = keylargo_mb_content, | 693 | .content = keylargo_mb_content, |
diff --git a/drivers/macintosh/rack-meter.c b/drivers/macintosh/rack-meter.c index cad0e19b47a..2637c139777 100644 --- a/drivers/macintosh/rack-meter.c +++ b/drivers/macintosh/rack-meter.c | |||
| @@ -81,13 +81,13 @@ static int rackmeter_ignore_nice; | |||
| 81 | */ | 81 | */ |
| 82 | static inline cputime64_t get_cpu_idle_time(unsigned int cpu) | 82 | static inline cputime64_t get_cpu_idle_time(unsigned int cpu) |
| 83 | { | 83 | { |
| 84 | u64 retval; | 84 | cputime64_t retval; |
| 85 | 85 | ||
| 86 | retval = kcpustat_cpu(cpu).cpustat[CPUTIME_IDLE] + | 86 | retval = cputime64_add(kstat_cpu(cpu).cpustat.idle, |
| 87 | kcpustat_cpu(cpu).cpustat[CPUTIME_IOWAIT]; | 87 | kstat_cpu(cpu).cpustat.iowait); |
| 88 | 88 | ||
| 89 | if (rackmeter_ignore_nice) | 89 | if (rackmeter_ignore_nice) |
| 90 | retval += kcpustat_cpu(cpu).cpustat[CPUTIME_NICE]; | 90 | retval = cputime64_add(retval, kstat_cpu(cpu).cpustat.nice); |
| 91 | 91 | ||
| 92 | return retval; | 92 | return retval; |
| 93 | } | 93 | } |
| @@ -220,11 +220,13 @@ static void rackmeter_do_timer(struct work_struct *work) | |||
| 220 | int i, offset, load, cumm, pause; | 220 | int i, offset, load, cumm, pause; |
| 221 | 221 | ||
| 222 | cur_jiffies = jiffies64_to_cputime64(get_jiffies_64()); | 222 | cur_jiffies = jiffies64_to_cputime64(get_jiffies_64()); |
| 223 | total_ticks = (unsigned int) (cur_jiffies - rcpu->prev_wall); | 223 | total_ticks = (unsigned int)cputime64_sub(cur_jiffies, |
| 224 | rcpu->prev_wall); | ||
| 224 | rcpu->prev_wall = cur_jiffies; | 225 | rcpu->prev_wall = cur_jiffies; |
| 225 | 226 | ||
| 226 | total_idle_ticks = get_cpu_idle_time(cpu); | 227 | total_idle_ticks = get_cpu_idle_time(cpu); |
| 227 | idle_ticks = (unsigned int) (total_idle_ticks - rcpu->prev_idle); | 228 | idle_ticks = (unsigned int) cputime64_sub(total_idle_ticks, |
| 229 | rcpu->prev_idle); | ||
| 228 | rcpu->prev_idle = total_idle_ticks; | 230 | rcpu->prev_idle = total_idle_ticks; |
| 229 | 231 | ||
| 230 | /* We do a very dumb calculation to update the LEDs for now, | 232 | /* We do a very dumb calculation to update the LEDs for now, |
| @@ -253,7 +255,7 @@ static void rackmeter_do_timer(struct work_struct *work) | |||
| 253 | msecs_to_jiffies(CPU_SAMPLING_RATE)); | 255 | msecs_to_jiffies(CPU_SAMPLING_RATE)); |
| 254 | } | 256 | } |
| 255 | 257 | ||
| 256 | static void rackmeter_init_cpu_sniffer(struct rackmeter *rm) | 258 | static void __devinit rackmeter_init_cpu_sniffer(struct rackmeter *rm) |
| 257 | { | 259 | { |
| 258 | unsigned int cpu; | 260 | unsigned int cpu; |
| 259 | 261 | ||
| @@ -287,7 +289,7 @@ static void rackmeter_stop_cpu_sniffer(struct rackmeter *rm) | |||
| 287 | cancel_delayed_work_sync(&rm->cpu[1].sniffer); | 289 | cancel_delayed_work_sync(&rm->cpu[1].sniffer); |
| 288 | } | 290 | } |
| 289 | 291 | ||
| 290 | static int rackmeter_setup(struct rackmeter *rm) | 292 | static int __devinit rackmeter_setup(struct rackmeter *rm) |
| 291 | { | 293 | { |
| 292 | pr_debug("rackmeter: setting up i2s..\n"); | 294 | pr_debug("rackmeter: setting up i2s..\n"); |
| 293 | rackmeter_setup_i2s(rm); | 295 | rackmeter_setup_i2s(rm); |
| @@ -362,8 +364,8 @@ static irqreturn_t rackmeter_irq(int irq, void *arg) | |||
| 362 | return IRQ_HANDLED; | 364 | return IRQ_HANDLED; |
| 363 | } | 365 | } |
| 364 | 366 | ||
| 365 | static int rackmeter_probe(struct macio_dev* mdev, | 367 | static int __devinit rackmeter_probe(struct macio_dev* mdev, |
| 366 | const struct of_device_id *match) | 368 | const struct of_device_id *match) |
| 367 | { | 369 | { |
| 368 | struct device_node *i2s = NULL, *np = NULL; | 370 | struct device_node *i2s = NULL, *np = NULL; |
| 369 | struct rackmeter *rm = NULL; | 371 | struct rackmeter *rm = NULL; |
| @@ -521,7 +523,7 @@ static int rackmeter_probe(struct macio_dev* mdev, | |||
| 521 | return rc; | 523 | return rc; |
| 522 | } | 524 | } |
| 523 | 525 | ||
| 524 | static int rackmeter_remove(struct macio_dev* mdev) | 526 | static int __devexit rackmeter_remove(struct macio_dev* mdev) |
| 525 | { | 527 | { |
| 526 | struct rackmeter *rm = dev_get_drvdata(&mdev->ofdev.dev); | 528 | struct rackmeter *rm = dev_get_drvdata(&mdev->ofdev.dev); |
| 527 | 529 | ||
| @@ -588,7 +590,7 @@ static struct macio_driver rackmeter_driver = { | |||
| 588 | .of_match_table = rackmeter_match, | 590 | .of_match_table = rackmeter_match, |
| 589 | }, | 591 | }, |
| 590 | .probe = rackmeter_probe, | 592 | .probe = rackmeter_probe, |
| 591 | .remove = rackmeter_remove, | 593 | .remove = __devexit_p(rackmeter_remove), |
| 592 | .shutdown = rackmeter_shutdown, | 594 | .shutdown = rackmeter_shutdown, |
| 593 | }; | 595 | }; |
| 594 | 596 | ||
diff --git a/drivers/macintosh/smu.c b/drivers/macintosh/smu.c index 9c6b9641486..116a49ce74b 100644 --- a/drivers/macintosh/smu.c +++ b/drivers/macintosh/smu.c | |||
| @@ -32,6 +32,7 @@ | |||
| 32 | #include <linux/completion.h> | 32 | #include <linux/completion.h> |
| 33 | #include <linux/miscdevice.h> | 33 | #include <linux/miscdevice.h> |
| 34 | #include <linux/delay.h> | 34 | #include <linux/delay.h> |
| 35 | #include <linux/sysdev.h> | ||
| 35 | #include <linux/poll.h> | 36 | #include <linux/poll.h> |
| 36 | #include <linux/mutex.h> | 37 | #include <linux/mutex.h> |
| 37 | #include <linux/of_device.h> | 38 | #include <linux/of_device.h> |
| @@ -45,6 +46,7 @@ | |||
| 45 | #include <asm/pmac_feature.h> | 46 | #include <asm/pmac_feature.h> |
| 46 | #include <asm/smu.h> | 47 | #include <asm/smu.h> |
| 47 | #include <asm/sections.h> | 48 | #include <asm/sections.h> |
| 49 | #include <asm/abs_addr.h> | ||
| 48 | #include <asm/uaccess.h> | 50 | #include <asm/uaccess.h> |
| 49 | 51 | ||
| 50 | #define VERSION "0.7" | 52 | #define VERSION "0.7" |
| @@ -501,7 +503,7 @@ int __init smu_init (void) | |||
| 501 | * 32 bits value safely | 503 | * 32 bits value safely |
| 502 | */ | 504 | */ |
| 503 | smu->cmd_buf_abs = (u32)smu_cmdbuf_abs; | 505 | smu->cmd_buf_abs = (u32)smu_cmdbuf_abs; |
| 504 | smu->cmd_buf = __va(smu_cmdbuf_abs); | 506 | smu->cmd_buf = (struct smu_cmd_buf *)abs_to_virt(smu_cmdbuf_abs); |
| 505 | 507 | ||
| 506 | smu->db_node = of_find_node_by_name(NULL, "smu-doorbell"); | 508 | smu->db_node = of_find_node_by_name(NULL, "smu-doorbell"); |
| 507 | if (smu->db_node == NULL) { | 509 | if (smu->db_node == NULL) { |
| @@ -565,7 +567,7 @@ fail_msg_node: | |||
| 565 | fail_db_node: | 567 | fail_db_node: |
| 566 | of_node_put(smu->db_node); | 568 | of_node_put(smu->db_node); |
| 567 | fail_bootmem: | 569 | fail_bootmem: |
| 568 | free_bootmem(__pa(smu), sizeof(struct smu_device)); | 570 | free_bootmem((unsigned long)smu, sizeof(struct smu_device)); |
| 569 | smu = NULL; | 571 | smu = NULL; |
| 570 | fail_np: | 572 | fail_np: |
| 571 | of_node_put(np); | 573 | of_node_put(np); |
| @@ -679,6 +681,9 @@ static struct platform_driver smu_of_platform_driver = | |||
| 679 | static int __init smu_init_sysfs(void) | 681 | static int __init smu_init_sysfs(void) |
| 680 | { | 682 | { |
| 681 | /* | 683 | /* |
| 684 | * Due to sysfs bogosity, a sysdev is not a real device, so | ||
| 685 | * we should in fact create both if we want sysdev semantics | ||
| 686 | * for power management. | ||
| 682 | * For now, we don't power manage machines with an SMU chip, | 687 | * For now, we don't power manage machines with an SMU chip, |
| 683 | * I'm a bit too far from figuring out how that works with those | 688 | * I'm a bit too far from figuring out how that works with those |
| 684 | * new chipsets, but that will come back and bite us | 689 | * new chipsets, but that will come back and bite us |
| @@ -997,7 +1002,7 @@ static struct smu_sdbp_header *smu_create_sdb_partition(int id) | |||
| 997 | "%02x !\n", id, hdr->id); | 1002 | "%02x !\n", id, hdr->id); |
| 998 | goto failure; | 1003 | goto failure; |
| 999 | } | 1004 | } |
| 1000 | if (of_add_property(smu->of_node, prop)) { | 1005 | if (prom_add_property(smu->of_node, prop)) { |
| 1001 | printk(KERN_DEBUG "SMU: Failed creating sdb-partition-%02x " | 1006 | printk(KERN_DEBUG "SMU: Failed creating sdb-partition-%02x " |
| 1002 | "property !\n", id); | 1007 | "property !\n", id); |
| 1003 | goto failure; | 1008 | goto failure; |
diff --git a/drivers/macintosh/therm_adt746x.c b/drivers/macintosh/therm_adt746x.c index f433521a6f9..02367308ff2 100644 --- a/drivers/macintosh/therm_adt746x.c +++ b/drivers/macintosh/therm_adt746x.c | |||
| @@ -29,6 +29,7 @@ | |||
| 29 | #include <asm/prom.h> | 29 | #include <asm/prom.h> |
| 30 | #include <asm/machdep.h> | 30 | #include <asm/machdep.h> |
| 31 | #include <asm/io.h> | 31 | #include <asm/io.h> |
| 32 | #include <asm/system.h> | ||
| 32 | #include <asm/sections.h> | 33 | #include <asm/sections.h> |
| 33 | 34 | ||
| 34 | #undef DEBUG | 35 | #undef DEBUG |
| @@ -47,11 +48,11 @@ static u8 FAN_SPD_SET[2] = {0x30, 0x31}; | |||
| 47 | 48 | ||
| 48 | static u8 default_limits_local[3] = {70, 50, 70}; /* local, sensor1, sensor2 */ | 49 | static u8 default_limits_local[3] = {70, 50, 70}; /* local, sensor1, sensor2 */ |
| 49 | static u8 default_limits_chip[3] = {80, 65, 80}; /* local, sensor1, sensor2 */ | 50 | static u8 default_limits_chip[3] = {80, 65, 80}; /* local, sensor1, sensor2 */ |
| 50 | static const char *sensor_location[3] = { "?", "?", "?" }; | 51 | static const char *sensor_location[3]; |
| 51 | 52 | ||
| 52 | static int limit_adjust; | 53 | static int limit_adjust; |
| 53 | static int fan_speed = -1; | 54 | static int fan_speed = -1; |
| 54 | static bool verbose; | 55 | static int verbose; |
| 55 | 56 | ||
| 56 | MODULE_AUTHOR("Colin Leroy <colin@colino.net>"); | 57 | MODULE_AUTHOR("Colin Leroy <colin@colino.net>"); |
| 57 | MODULE_DESCRIPTION("Driver for ADT746x thermostat in iBook G4 and " | 58 | MODULE_DESCRIPTION("Driver for ADT746x thermostat in iBook G4 and " |
| @@ -79,16 +80,18 @@ struct thermostat { | |||
| 79 | int last_speed[2]; | 80 | int last_speed[2]; |
| 80 | int last_var[2]; | 81 | int last_var[2]; |
| 81 | int pwm_inv[2]; | 82 | int pwm_inv[2]; |
| 82 | struct task_struct *thread; | ||
| 83 | struct platform_device *pdev; | ||
| 84 | enum { | ||
| 85 | ADT7460, | ||
| 86 | ADT7467 | ||
| 87 | } type; | ||
| 88 | }; | 83 | }; |
| 89 | 84 | ||
| 85 | static enum {ADT7460, ADT7467} therm_type; | ||
| 86 | static int therm_bus, therm_address; | ||
| 87 | static struct platform_device * of_dev; | ||
| 88 | static struct thermostat* thermostat; | ||
| 89 | static struct task_struct *thread_therm = NULL; | ||
| 90 | |||
| 90 | static void write_both_fan_speed(struct thermostat *th, int speed); | 91 | static void write_both_fan_speed(struct thermostat *th, int speed); |
| 91 | static void write_fan_speed(struct thermostat *th, int speed, int fan); | 92 | static void write_fan_speed(struct thermostat *th, int speed, int fan); |
| 93 | static void thermostat_create_files(void); | ||
| 94 | static void thermostat_remove_files(void); | ||
| 92 | 95 | ||
| 93 | static int | 96 | static int |
| 94 | write_reg(struct thermostat* th, int reg, u8 data) | 97 | write_reg(struct thermostat* th, int reg, u8 data) |
| @@ -124,6 +127,66 @@ read_reg(struct thermostat* th, int reg) | |||
| 124 | return data; | 127 | return data; |
| 125 | } | 128 | } |
| 126 | 129 | ||
| 130 | static struct i2c_driver thermostat_driver; | ||
| 131 | |||
| 132 | static int | ||
| 133 | attach_thermostat(struct i2c_adapter *adapter) | ||
| 134 | { | ||
| 135 | unsigned long bus_no; | ||
| 136 | struct i2c_board_info info; | ||
| 137 | struct i2c_client *client; | ||
| 138 | |||
| 139 | if (strncmp(adapter->name, "uni-n", 5)) | ||
| 140 | return -ENODEV; | ||
| 141 | bus_no = simple_strtoul(adapter->name + 6, NULL, 10); | ||
| 142 | if (bus_no != therm_bus) | ||
| 143 | return -ENODEV; | ||
| 144 | |||
| 145 | memset(&info, 0, sizeof(struct i2c_board_info)); | ||
| 146 | strlcpy(info.type, "therm_adt746x", I2C_NAME_SIZE); | ||
| 147 | info.addr = therm_address; | ||
| 148 | client = i2c_new_device(adapter, &info); | ||
| 149 | if (!client) | ||
| 150 | return -ENODEV; | ||
| 151 | |||
| 152 | /* | ||
| 153 | * Let i2c-core delete that device on driver removal. | ||
| 154 | * This is safe because i2c-core holds the core_lock mutex for us. | ||
| 155 | */ | ||
| 156 | list_add_tail(&client->detected, &thermostat_driver.clients); | ||
| 157 | return 0; | ||
| 158 | } | ||
| 159 | |||
| 160 | static int | ||
| 161 | remove_thermostat(struct i2c_client *client) | ||
| 162 | { | ||
| 163 | struct thermostat *th = i2c_get_clientdata(client); | ||
| 164 | int i; | ||
| 165 | |||
| 166 | thermostat_remove_files(); | ||
| 167 | |||
| 168 | if (thread_therm != NULL) { | ||
| 169 | kthread_stop(thread_therm); | ||
| 170 | } | ||
| 171 | |||
| 172 | printk(KERN_INFO "adt746x: Putting max temperatures back from " | ||
| 173 | "%d, %d, %d to %d, %d, %d\n", | ||
| 174 | th->limits[0], th->limits[1], th->limits[2], | ||
| 175 | th->initial_limits[0], th->initial_limits[1], | ||
| 176 | th->initial_limits[2]); | ||
| 177 | |||
| 178 | for (i = 0; i < 3; i++) | ||
| 179 | write_reg(th, LIMIT_REG[i], th->initial_limits[i]); | ||
| 180 | |||
| 181 | write_both_fan_speed(th, -1); | ||
| 182 | |||
| 183 | thermostat = NULL; | ||
| 184 | |||
| 185 | kfree(th); | ||
| 186 | |||
| 187 | return 0; | ||
| 188 | } | ||
| 189 | |||
| 127 | static int read_fan_speed(struct thermostat *th, u8 addr) | 190 | static int read_fan_speed(struct thermostat *th, u8 addr) |
| 128 | { | 191 | { |
| 129 | u8 tmp[2]; | 192 | u8 tmp[2]; |
| @@ -141,7 +204,7 @@ static int read_fan_speed(struct thermostat *th, u8 addr) | |||
| 141 | static void write_both_fan_speed(struct thermostat *th, int speed) | 204 | static void write_both_fan_speed(struct thermostat *th, int speed) |
| 142 | { | 205 | { |
| 143 | write_fan_speed(th, speed, 0); | 206 | write_fan_speed(th, speed, 0); |
| 144 | if (th->type == ADT7460) | 207 | if (therm_type == ADT7460) |
| 145 | write_fan_speed(th, speed, 1); | 208 | write_fan_speed(th, speed, 1); |
| 146 | } | 209 | } |
| 147 | 210 | ||
| @@ -154,7 +217,7 @@ static void write_fan_speed(struct thermostat *th, int speed, int fan) | |||
| 154 | else if (speed < -1) | 217 | else if (speed < -1) |
| 155 | speed = 0; | 218 | speed = 0; |
| 156 | 219 | ||
| 157 | if (th->type == ADT7467 && fan == 1) | 220 | if (therm_type == ADT7467 && fan == 1) |
| 158 | return; | 221 | return; |
| 159 | 222 | ||
| 160 | if (th->last_speed[fan] != speed) { | 223 | if (th->last_speed[fan] != speed) { |
| @@ -177,7 +240,7 @@ static void write_fan_speed(struct thermostat *th, int speed, int fan) | |||
| 177 | write_reg(th, FAN_SPD_SET[fan], speed); | 240 | write_reg(th, FAN_SPD_SET[fan], speed); |
| 178 | } else { | 241 | } else { |
| 179 | /* back to automatic */ | 242 | /* back to automatic */ |
| 180 | if(th->type == ADT7460) { | 243 | if(therm_type == ADT7460) { |
| 181 | manual = read_reg(th, | 244 | manual = read_reg(th, |
| 182 | MANUAL_MODE[fan]) & (~MANUAL_MASK); | 245 | MANUAL_MODE[fan]) & (~MANUAL_MASK); |
| 183 | manual &= ~INVERT_MASK; | 246 | manual &= ~INVERT_MASK; |
| @@ -231,7 +294,7 @@ static void update_fans_speed (struct thermostat *th) | |||
| 231 | /* we don't care about local sensor, so we start at sensor 1 */ | 294 | /* we don't care about local sensor, so we start at sensor 1 */ |
| 232 | for (i = 1; i < 3; i++) { | 295 | for (i = 1; i < 3; i++) { |
| 233 | int started = 0; | 296 | int started = 0; |
| 234 | int fan_number = (th->type == ADT7460 && i == 2); | 297 | int fan_number = (therm_type == ADT7460 && i == 2); |
| 235 | int var = th->temps[i] - th->limits[i]; | 298 | int var = th->temps[i] - th->limits[i]; |
| 236 | 299 | ||
| 237 | if (var > -1) { | 300 | if (var > -1) { |
| @@ -308,22 +371,116 @@ static int monitor_task(void *arg) | |||
| 308 | 371 | ||
| 309 | static void set_limit(struct thermostat *th, int i) | 372 | static void set_limit(struct thermostat *th, int i) |
| 310 | { | 373 | { |
| 311 | /* Set sensor1 limit higher to avoid powerdowns */ | 374 | /* Set sensor1 limit higher to avoid powerdowns */ |
| 312 | th->limits[i] = default_limits_chip[i] + limit_adjust; | 375 | th->limits[i] = default_limits_chip[i] + limit_adjust; |
| 313 | write_reg(th, LIMIT_REG[i], th->limits[i]); | 376 | write_reg(th, LIMIT_REG[i], th->limits[i]); |
| 314 | 377 | ||
| 315 | /* set our limits to normal */ | 378 | /* set our limits to normal */ |
| 316 | th->limits[i] = default_limits_local[i] + limit_adjust; | 379 | th->limits[i] = default_limits_local[i] + limit_adjust; |
| 317 | } | 380 | } |
| 318 | 381 | ||
| 319 | #define BUILD_SHOW_FUNC_INT(name, data) \ | 382 | static int probe_thermostat(struct i2c_client *client, |
| 320 | static ssize_t show_##name(struct device *dev, struct device_attribute *attr, char *buf) \ | 383 | const struct i2c_device_id *id) |
| 321 | { \ | 384 | { |
| 322 | struct thermostat *th = dev_get_drvdata(dev); \ | 385 | struct thermostat* th; |
| 323 | return sprintf(buf, "%d\n", data); \ | 386 | int rc; |
| 387 | int i; | ||
| 388 | |||
| 389 | if (thermostat) | ||
| 390 | return 0; | ||
| 391 | |||
| 392 | th = kzalloc(sizeof(struct thermostat), GFP_KERNEL); | ||
| 393 | if (!th) | ||
| 394 | return -ENOMEM; | ||
| 395 | |||
| 396 | i2c_set_clientdata(client, th); | ||
| 397 | th->clt = client; | ||
| 398 | |||
| 399 | rc = read_reg(th, CONFIG_REG); | ||
| 400 | if (rc < 0) { | ||
| 401 | dev_err(&client->dev, "Thermostat failed to read config!\n"); | ||
| 402 | kfree(th); | ||
| 403 | return -ENODEV; | ||
| 404 | } | ||
| 405 | |||
| 406 | /* force manual control to start the fan quieter */ | ||
| 407 | if (fan_speed == -1) | ||
| 408 | fan_speed = 64; | ||
| 409 | |||
| 410 | if(therm_type == ADT7460) { | ||
| 411 | printk(KERN_INFO "adt746x: ADT7460 initializing\n"); | ||
| 412 | /* The 7460 needs to be started explicitly */ | ||
| 413 | write_reg(th, CONFIG_REG, 1); | ||
| 414 | } else | ||
| 415 | printk(KERN_INFO "adt746x: ADT7467 initializing\n"); | ||
| 416 | |||
| 417 | for (i = 0; i < 3; i++) { | ||
| 418 | th->initial_limits[i] = read_reg(th, LIMIT_REG[i]); | ||
| 419 | set_limit(th, i); | ||
| 420 | } | ||
| 421 | |||
| 422 | printk(KERN_INFO "adt746x: Lowering max temperatures from %d, %d, %d" | ||
| 423 | " to %d, %d, %d\n", | ||
| 424 | th->initial_limits[0], th->initial_limits[1], | ||
| 425 | th->initial_limits[2], th->limits[0], th->limits[1], | ||
| 426 | th->limits[2]); | ||
| 427 | |||
| 428 | thermostat = th; | ||
| 429 | |||
| 430 | /* record invert bit status because fw can corrupt it after suspend */ | ||
| 431 | th->pwm_inv[0] = read_reg(th, MANUAL_MODE[0]) & INVERT_MASK; | ||
| 432 | th->pwm_inv[1] = read_reg(th, MANUAL_MODE[1]) & INVERT_MASK; | ||
| 433 | |||
| 434 | /* be sure to really write fan speed the first time */ | ||
| 435 | th->last_speed[0] = -2; | ||
| 436 | th->last_speed[1] = -2; | ||
| 437 | th->last_var[0] = -80; | ||
| 438 | th->last_var[1] = -80; | ||
| 439 | |||
| 440 | if (fan_speed != -1) { | ||
| 441 | /* manual mode, stop fans */ | ||
| 442 | write_both_fan_speed(th, 0); | ||
| 443 | } else { | ||
| 444 | /* automatic mode */ | ||
| 445 | write_both_fan_speed(th, -1); | ||
| 446 | } | ||
| 447 | |||
| 448 | thread_therm = kthread_run(monitor_task, th, "kfand"); | ||
| 449 | |||
| 450 | if (thread_therm == ERR_PTR(-ENOMEM)) { | ||
| 451 | printk(KERN_INFO "adt746x: Kthread creation failed\n"); | ||
| 452 | thread_therm = NULL; | ||
| 453 | return -ENOMEM; | ||
| 454 | } | ||
| 455 | |||
| 456 | thermostat_create_files(); | ||
| 457 | |||
| 458 | return 0; | ||
| 324 | } | 459 | } |
| 325 | 460 | ||
| 326 | #define BUILD_SHOW_FUNC_INT_LITE(name, data) \ | 461 | static const struct i2c_device_id therm_adt746x_id[] = { |
| 462 | { "therm_adt746x", 0 }, | ||
| 463 | { } | ||
| 464 | }; | ||
| 465 | |||
| 466 | static struct i2c_driver thermostat_driver = { | ||
| 467 | .driver = { | ||
| 468 | .name = "therm_adt746x", | ||
| 469 | }, | ||
| 470 | .attach_adapter = attach_thermostat, | ||
| 471 | .probe = probe_thermostat, | ||
| 472 | .remove = remove_thermostat, | ||
| 473 | .id_table = therm_adt746x_id, | ||
| 474 | }; | ||
| 475 | |||
| 476 | /* | ||
| 477 | * Now, unfortunately, sysfs doesn't give us a nice void * we could | ||
| 478 | * pass around to the attribute functions, so we don't really have | ||
| 479 | * choice but implement a bunch of them... | ||
| 480 | * | ||
| 481 | * FIXME, it does now... | ||
| 482 | */ | ||
| 483 | #define BUILD_SHOW_FUNC_INT(name, data) \ | ||
| 327 | static ssize_t show_##name(struct device *dev, struct device_attribute *attr, char *buf) \ | 484 | static ssize_t show_##name(struct device *dev, struct device_attribute *attr, char *buf) \ |
| 328 | { \ | 485 | { \ |
| 329 | return sprintf(buf, "%d\n", data); \ | 486 | return sprintf(buf, "%d\n", data); \ |
| @@ -338,24 +495,22 @@ static ssize_t show_##name(struct device *dev, struct device_attribute *attr, ch | |||
| 338 | #define BUILD_SHOW_FUNC_FAN(name, data) \ | 495 | #define BUILD_SHOW_FUNC_FAN(name, data) \ |
| 339 | static ssize_t show_##name(struct device *dev, struct device_attribute *attr, char *buf) \ | 496 | static ssize_t show_##name(struct device *dev, struct device_attribute *attr, char *buf) \ |
| 340 | { \ | 497 | { \ |
| 341 | struct thermostat *th = dev_get_drvdata(dev); \ | ||
| 342 | return sprintf(buf, "%d (%d rpm)\n", \ | 498 | return sprintf(buf, "%d (%d rpm)\n", \ |
| 343 | th->last_speed[data], \ | 499 | thermostat->last_speed[data], \ |
| 344 | read_fan_speed(th, FAN_SPEED[data]) \ | 500 | read_fan_speed(thermostat, FAN_SPEED[data]) \ |
| 345 | ); \ | 501 | ); \ |
| 346 | } | 502 | } |
| 347 | 503 | ||
| 348 | #define BUILD_STORE_FUNC_DEG(name, data) \ | 504 | #define BUILD_STORE_FUNC_DEG(name, data) \ |
| 349 | static ssize_t store_##name(struct device *dev, struct device_attribute *attr, const char *buf, size_t n) \ | 505 | static ssize_t store_##name(struct device *dev, struct device_attribute *attr, const char *buf, size_t n) \ |
| 350 | { \ | 506 | { \ |
| 351 | struct thermostat *th = dev_get_drvdata(dev); \ | ||
| 352 | int val; \ | 507 | int val; \ |
| 353 | int i; \ | 508 | int i; \ |
| 354 | val = simple_strtol(buf, NULL, 10); \ | 509 | val = simple_strtol(buf, NULL, 10); \ |
| 355 | printk(KERN_INFO "Adjusting limits by %d degrees\n", val); \ | 510 | printk(KERN_INFO "Adjusting limits by %d degrees\n", val); \ |
| 356 | limit_adjust = val; \ | 511 | limit_adjust = val; \ |
| 357 | for (i=0; i < 3; i++) \ | 512 | for (i=0; i < 3; i++) \ |
| 358 | set_limit(th, i); \ | 513 | set_limit(thermostat, i); \ |
| 359 | return n; \ | 514 | return n; \ |
| 360 | } | 515 | } |
| 361 | 516 | ||
| @@ -371,21 +526,20 @@ static ssize_t store_##name(struct device *dev, struct device_attribute *attr, c | |||
| 371 | return n; \ | 526 | return n; \ |
| 372 | } | 527 | } |
| 373 | 528 | ||
| 374 | BUILD_SHOW_FUNC_INT(sensor1_temperature, (read_reg(th, TEMP_REG[1]))) | 529 | BUILD_SHOW_FUNC_INT(sensor1_temperature, (read_reg(thermostat, TEMP_REG[1]))) |
| 375 | BUILD_SHOW_FUNC_INT(sensor2_temperature, (read_reg(th, TEMP_REG[2]))) | 530 | BUILD_SHOW_FUNC_INT(sensor2_temperature, (read_reg(thermostat, TEMP_REG[2]))) |
| 376 | BUILD_SHOW_FUNC_INT(sensor1_limit, th->limits[1]) | 531 | BUILD_SHOW_FUNC_INT(sensor1_limit, thermostat->limits[1]) |
| 377 | BUILD_SHOW_FUNC_INT(sensor2_limit, th->limits[2]) | 532 | BUILD_SHOW_FUNC_INT(sensor2_limit, thermostat->limits[2]) |
| 378 | BUILD_SHOW_FUNC_STR(sensor1_location, sensor_location[1]) | 533 | BUILD_SHOW_FUNC_STR(sensor1_location, sensor_location[1]) |
| 379 | BUILD_SHOW_FUNC_STR(sensor2_location, sensor_location[2]) | 534 | BUILD_SHOW_FUNC_STR(sensor2_location, sensor_location[2]) |
| 380 | 535 | ||
| 381 | BUILD_SHOW_FUNC_INT_LITE(specified_fan_speed, fan_speed) | 536 | BUILD_SHOW_FUNC_INT(specified_fan_speed, fan_speed) |
| 382 | BUILD_STORE_FUNC_INT(specified_fan_speed,fan_speed) | ||
| 383 | |||
| 384 | BUILD_SHOW_FUNC_FAN(sensor1_fan_speed, 0) | 537 | BUILD_SHOW_FUNC_FAN(sensor1_fan_speed, 0) |
| 385 | BUILD_SHOW_FUNC_FAN(sensor2_fan_speed, 1) | 538 | BUILD_SHOW_FUNC_FAN(sensor2_fan_speed, 1) |
| 386 | 539 | ||
| 387 | BUILD_SHOW_FUNC_INT_LITE(limit_adjust, limit_adjust) | 540 | BUILD_STORE_FUNC_INT(specified_fan_speed,fan_speed) |
| 388 | BUILD_STORE_FUNC_DEG(limit_adjust, th) | 541 | BUILD_SHOW_FUNC_INT(limit_adjust, limit_adjust) |
| 542 | BUILD_STORE_FUNC_DEG(limit_adjust, thermostat) | ||
| 389 | 543 | ||
| 390 | static DEVICE_ATTR(sensor1_temperature, S_IRUGO, | 544 | static DEVICE_ATTR(sensor1_temperature, S_IRUGO, |
| 391 | show_sensor1_temperature,NULL); | 545 | show_sensor1_temperature,NULL); |
| @@ -411,77 +565,53 @@ static DEVICE_ATTR(sensor2_fan_speed, S_IRUGO, | |||
| 411 | static DEVICE_ATTR(limit_adjust, S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH, | 565 | static DEVICE_ATTR(limit_adjust, S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH, |
| 412 | show_limit_adjust, store_limit_adjust); | 566 | show_limit_adjust, store_limit_adjust); |
| 413 | 567 | ||
| 414 | static void thermostat_create_files(struct thermostat *th) | 568 | |
| 569 | static int __init | ||
| 570 | thermostat_init(void) | ||
| 415 | { | 571 | { |
| 416 | struct device_node *np = th->clt->dev.of_node; | 572 | struct device_node* np; |
| 417 | struct device *dev; | 573 | const u32 *prop; |
| 418 | int err; | 574 | int i = 0, offset = 0; |
| 419 | 575 | ||
| 420 | /* To maintain ABI compatibility with userspace, create | 576 | np = of_find_node_by_name(NULL, "fan"); |
| 421 | * the old style platform driver and attach the attributes | 577 | if (!np) |
| 422 | * to it here | 578 | return -ENODEV; |
| 423 | */ | 579 | if (of_device_is_compatible(np, "adt7460")) |
| 424 | th->pdev = of_platform_device_create(np, "temperatures", NULL); | 580 | therm_type = ADT7460; |
| 425 | if (!th->pdev) | 581 | else if (of_device_is_compatible(np, "adt7467")) |
| 426 | return; | 582 | therm_type = ADT7467; |
| 427 | dev = &th->pdev->dev; | 583 | else { |
| 428 | dev_set_drvdata(dev, th); | 584 | of_node_put(np); |
| 429 | err = device_create_file(dev, &dev_attr_sensor1_temperature); | 585 | return -ENODEV; |
| 430 | err |= device_create_file(dev, &dev_attr_sensor2_temperature); | 586 | } |
| 431 | err |= device_create_file(dev, &dev_attr_sensor1_limit); | ||
| 432 | err |= device_create_file(dev, &dev_attr_sensor2_limit); | ||
| 433 | err |= device_create_file(dev, &dev_attr_sensor1_location); | ||
| 434 | err |= device_create_file(dev, &dev_attr_sensor2_location); | ||
| 435 | err |= device_create_file(dev, &dev_attr_limit_adjust); | ||
| 436 | err |= device_create_file(dev, &dev_attr_specified_fan_speed); | ||
| 437 | err |= device_create_file(dev, &dev_attr_sensor1_fan_speed); | ||
| 438 | if(th->type == ADT7460) | ||
| 439 | err |= device_create_file(dev, &dev_attr_sensor2_fan_speed); | ||
| 440 | if (err) | ||
| 441 | printk(KERN_WARNING | ||
| 442 | "Failed to create temperature attribute file(s).\n"); | ||
| 443 | } | ||
| 444 | 587 | ||
| 445 | static void thermostat_remove_files(struct thermostat *th) | 588 | prop = of_get_property(np, "hwsensor-params-version", NULL); |
| 446 | { | 589 | printk(KERN_INFO "adt746x: version %d (%ssupported)\n", *prop, |
| 447 | struct device *dev; | 590 | (*prop == 1)?"":"un"); |
| 591 | if (*prop != 1) { | ||
| 592 | of_node_put(np); | ||
| 593 | return -ENODEV; | ||
| 594 | } | ||
| 448 | 595 | ||
| 449 | if (!th->pdev) | 596 | prop = of_get_property(np, "reg", NULL); |
| 450 | return; | 597 | if (!prop) { |
| 451 | dev = &th->pdev->dev; | 598 | of_node_put(np); |
| 452 | device_remove_file(dev, &dev_attr_sensor1_temperature); | 599 | return -ENODEV; |
| 453 | device_remove_file(dev, &dev_attr_sensor2_temperature); | 600 | } |
| 454 | device_remove_file(dev, &dev_attr_sensor1_limit); | ||
| 455 | device_remove_file(dev, &dev_attr_sensor2_limit); | ||
| 456 | device_remove_file(dev, &dev_attr_sensor1_location); | ||
| 457 | device_remove_file(dev, &dev_attr_sensor2_location); | ||
| 458 | device_remove_file(dev, &dev_attr_limit_adjust); | ||
| 459 | device_remove_file(dev, &dev_attr_specified_fan_speed); | ||
| 460 | device_remove_file(dev, &dev_attr_sensor1_fan_speed); | ||
| 461 | if (th->type == ADT7460) | ||
| 462 | device_remove_file(dev, &dev_attr_sensor2_fan_speed); | ||
| 463 | of_device_unregister(th->pdev); | ||
| 464 | 601 | ||
| 465 | } | 602 | /* look for bus either by path or using "reg" */ |
| 603 | if (strstr(np->full_name, "/i2c-bus@") != NULL) { | ||
| 604 | const char *tmp_bus = (strstr(np->full_name, "/i2c-bus@") + 9); | ||
| 605 | therm_bus = tmp_bus[0]-'0'; | ||
| 606 | } else { | ||
| 607 | therm_bus = ((*prop) >> 8) & 0x0f; | ||
| 608 | } | ||
| 466 | 609 | ||
| 467 | static int probe_thermostat(struct i2c_client *client, | 610 | therm_address = ((*prop) & 0xff) >> 1; |
| 468 | const struct i2c_device_id *id) | ||
| 469 | { | ||
| 470 | struct device_node *np = client->dev.of_node; | ||
| 471 | struct thermostat* th; | ||
| 472 | const __be32 *prop; | ||
| 473 | int i, rc, vers, offset = 0; | ||
| 474 | 611 | ||
| 475 | if (!np) | 612 | printk(KERN_INFO "adt746x: Thermostat bus: %d, address: 0x%02x, " |
| 476 | return -ENXIO; | 613 | "limit_adjust: %d, fan_speed: %d\n", |
| 477 | prop = of_get_property(np, "hwsensor-params-version", NULL); | 614 | therm_bus, therm_address, limit_adjust, fan_speed); |
| 478 | if (!prop) | ||
| 479 | return -ENXIO; | ||
| 480 | vers = be32_to_cpup(prop); | ||
| 481 | printk(KERN_INFO "adt746x: version %d (%ssupported)\n", | ||
| 482 | vers, vers == 1 ? "" : "un"); | ||
| 483 | if (vers != 1) | ||
| 484 | return -ENXIO; | ||
| 485 | 615 | ||
| 486 | if (of_get_property(np, "hwsensor-location", NULL)) { | 616 | if (of_get_property(np, "hwsensor-location", NULL)) { |
| 487 | for (i = 0; i < 3; i++) { | 617 | for (i = 0; i < 3; i++) { |
| @@ -494,129 +624,72 @@ static int probe_thermostat(struct i2c_client *client, | |||
| 494 | printk(KERN_INFO "sensor %d: %s\n", i, sensor_location[i]); | 624 | printk(KERN_INFO "sensor %d: %s\n", i, sensor_location[i]); |
| 495 | offset += strlen(sensor_location[i]) + 1; | 625 | offset += strlen(sensor_location[i]) + 1; |
| 496 | } | 626 | } |
| 627 | } else { | ||
| 628 | sensor_location[0] = "?"; | ||
| 629 | sensor_location[1] = "?"; | ||
| 630 | sensor_location[2] = "?"; | ||
| 497 | } | 631 | } |
| 498 | 632 | ||
| 499 | th = kzalloc(sizeof(struct thermostat), GFP_KERNEL); | 633 | of_dev = of_platform_device_create(np, "temperatures", NULL); |
| 500 | if (!th) | 634 | of_node_put(np); |
| 501 | return -ENOMEM; | ||
| 502 | |||
| 503 | i2c_set_clientdata(client, th); | ||
| 504 | th->clt = client; | ||
| 505 | th->type = id->driver_data; | ||
| 506 | 635 | ||
| 507 | rc = read_reg(th, CONFIG_REG); | 636 | if (of_dev == NULL) { |
| 508 | if (rc < 0) { | 637 | printk(KERN_ERR "Can't register temperatures device !\n"); |
| 509 | dev_err(&client->dev, "Thermostat failed to read config!\n"); | ||
| 510 | kfree(th); | ||
| 511 | return -ENODEV; | 638 | return -ENODEV; |
| 512 | } | 639 | } |
| 513 | 640 | ||
| 514 | /* force manual control to start the fan quieter */ | 641 | #ifndef CONFIG_I2C_POWERMAC |
| 515 | if (fan_speed == -1) | 642 | request_module("i2c-powermac"); |
| 516 | fan_speed = 64; | 643 | #endif |
| 517 | |||
| 518 | if (th->type == ADT7460) { | ||
| 519 | printk(KERN_INFO "adt746x: ADT7460 initializing\n"); | ||
| 520 | /* The 7460 needs to be started explicitly */ | ||
| 521 | write_reg(th, CONFIG_REG, 1); | ||
| 522 | } else | ||
| 523 | printk(KERN_INFO "adt746x: ADT7467 initializing\n"); | ||
| 524 | |||
| 525 | for (i = 0; i < 3; i++) { | ||
| 526 | th->initial_limits[i] = read_reg(th, LIMIT_REG[i]); | ||
| 527 | set_limit(th, i); | ||
| 528 | } | ||
| 529 | |||
| 530 | printk(KERN_INFO "adt746x: Lowering max temperatures from %d, %d, %d" | ||
| 531 | " to %d, %d, %d\n", | ||
| 532 | th->initial_limits[0], th->initial_limits[1], | ||
| 533 | th->initial_limits[2], th->limits[0], th->limits[1], | ||
| 534 | th->limits[2]); | ||
| 535 | |||
| 536 | /* record invert bit status because fw can corrupt it after suspend */ | ||
| 537 | th->pwm_inv[0] = read_reg(th, MANUAL_MODE[0]) & INVERT_MASK; | ||
| 538 | th->pwm_inv[1] = read_reg(th, MANUAL_MODE[1]) & INVERT_MASK; | ||
| 539 | |||
| 540 | /* be sure to really write fan speed the first time */ | ||
| 541 | th->last_speed[0] = -2; | ||
| 542 | th->last_speed[1] = -2; | ||
| 543 | th->last_var[0] = -80; | ||
| 544 | th->last_var[1] = -80; | ||
| 545 | |||
| 546 | if (fan_speed != -1) { | ||
| 547 | /* manual mode, stop fans */ | ||
| 548 | write_both_fan_speed(th, 0); | ||
| 549 | } else { | ||
| 550 | /* automatic mode */ | ||
| 551 | write_both_fan_speed(th, -1); | ||
| 552 | } | ||
| 553 | |||
| 554 | th->thread = kthread_run(monitor_task, th, "kfand"); | ||
| 555 | if (th->thread == ERR_PTR(-ENOMEM)) { | ||
| 556 | printk(KERN_INFO "adt746x: Kthread creation failed\n"); | ||
| 557 | th->thread = NULL; | ||
| 558 | return -ENOMEM; | ||
| 559 | } | ||
| 560 | |||
| 561 | thermostat_create_files(th); | ||
| 562 | 644 | ||
| 563 | return 0; | 645 | return i2c_add_driver(&thermostat_driver); |
| 564 | } | 646 | } |
| 565 | 647 | ||
| 566 | static int remove_thermostat(struct i2c_client *client) | 648 | static void thermostat_create_files(void) |
| 567 | { | 649 | { |
| 568 | struct thermostat *th = i2c_get_clientdata(client); | 650 | int err; |
| 569 | int i; | ||
| 570 | |||
| 571 | thermostat_remove_files(th); | ||
| 572 | |||
| 573 | if (th->thread != NULL) | ||
| 574 | kthread_stop(th->thread); | ||
| 575 | |||
| 576 | printk(KERN_INFO "adt746x: Putting max temperatures back from " | ||
| 577 | "%d, %d, %d to %d, %d, %d\n", | ||
| 578 | th->limits[0], th->limits[1], th->limits[2], | ||
| 579 | th->initial_limits[0], th->initial_limits[1], | ||
| 580 | th->initial_limits[2]); | ||
| 581 | |||
| 582 | for (i = 0; i < 3; i++) | ||
| 583 | write_reg(th, LIMIT_REG[i], th->initial_limits[i]); | ||
| 584 | |||
| 585 | write_both_fan_speed(th, -1); | ||
| 586 | |||
| 587 | kfree(th); | ||
| 588 | 651 | ||
| 589 | return 0; | 652 | err = device_create_file(&of_dev->dev, &dev_attr_sensor1_temperature); |
| 653 | err |= device_create_file(&of_dev->dev, &dev_attr_sensor2_temperature); | ||
| 654 | err |= device_create_file(&of_dev->dev, &dev_attr_sensor1_limit); | ||
| 655 | err |= device_create_file(&of_dev->dev, &dev_attr_sensor2_limit); | ||
| 656 | err |= device_create_file(&of_dev->dev, &dev_attr_sensor1_location); | ||
| 657 | err |= device_create_file(&of_dev->dev, &dev_attr_sensor2_location); | ||
| 658 | err |= device_create_file(&of_dev->dev, &dev_attr_limit_adjust); | ||
| 659 | err |= device_create_file(&of_dev->dev, &dev_attr_specified_fan_speed); | ||
| 660 | err |= device_create_file(&of_dev->dev, &dev_attr_sensor1_fan_speed); | ||
| 661 | if(therm_type == ADT7460) | ||
| 662 | err |= device_create_file(&of_dev->dev, &dev_attr_sensor2_fan_speed); | ||
| 663 | if (err) | ||
| 664 | printk(KERN_WARNING | ||
| 665 | "Failed to create temperature attribute file(s).\n"); | ||
| 590 | } | 666 | } |
| 591 | 667 | ||
| 592 | static const struct i2c_device_id therm_adt746x_id[] = { | 668 | static void thermostat_remove_files(void) |
| 593 | { "MAC,adt7460", ADT7460 }, | ||
| 594 | { "MAC,adt7467", ADT7467 }, | ||
| 595 | { } | ||
| 596 | }; | ||
| 597 | MODULE_DEVICE_TABLE(i2c, therm_adt746x_id); | ||
| 598 | |||
| 599 | static struct i2c_driver thermostat_driver = { | ||
| 600 | .driver = { | ||
| 601 | .name = "therm_adt746x", | ||
| 602 | }, | ||
| 603 | .probe = probe_thermostat, | ||
| 604 | .remove = remove_thermostat, | ||
| 605 | .id_table = therm_adt746x_id, | ||
| 606 | }; | ||
| 607 | |||
| 608 | static int __init thermostat_init(void) | ||
| 609 | { | 669 | { |
| 610 | #ifndef CONFIG_I2C_POWERMAC | 670 | if (of_dev) { |
| 611 | request_module("i2c-powermac"); | 671 | device_remove_file(&of_dev->dev, &dev_attr_sensor1_temperature); |
| 612 | #endif | 672 | device_remove_file(&of_dev->dev, &dev_attr_sensor2_temperature); |
| 673 | device_remove_file(&of_dev->dev, &dev_attr_sensor1_limit); | ||
| 674 | device_remove_file(&of_dev->dev, &dev_attr_sensor2_limit); | ||
| 675 | device_remove_file(&of_dev->dev, &dev_attr_sensor1_location); | ||
| 676 | device_remove_file(&of_dev->dev, &dev_attr_sensor2_location); | ||
| 677 | device_remove_file(&of_dev->dev, &dev_attr_limit_adjust); | ||
| 678 | device_remove_file(&of_dev->dev, &dev_attr_specified_fan_speed); | ||
| 679 | device_remove_file(&of_dev->dev, &dev_attr_sensor1_fan_speed); | ||
| 680 | |||
| 681 | if(therm_type == ADT7460) | ||
| 682 | device_remove_file(&of_dev->dev, | ||
| 683 | &dev_attr_sensor2_fan_speed); | ||
| 613 | 684 | ||
| 614 | return i2c_add_driver(&thermostat_driver); | 685 | } |
| 615 | } | 686 | } |
| 616 | 687 | ||
| 617 | static void __exit thermostat_exit(void) | 688 | static void __exit |
| 689 | thermostat_exit(void) | ||
| 618 | { | 690 | { |
| 619 | i2c_del_driver(&thermostat_driver); | 691 | i2c_del_driver(&thermostat_driver); |
| 692 | of_device_unregister(of_dev); | ||
| 620 | } | 693 | } |
| 621 | 694 | ||
| 622 | module_init(thermostat_init); | 695 | module_init(thermostat_init); |
diff --git a/drivers/macintosh/therm_pm72.c b/drivers/macintosh/therm_pm72.c index 97cfc5ac9fd..0ff92c20800 100644 --- a/drivers/macintosh/therm_pm72.c +++ b/drivers/macintosh/therm_pm72.c | |||
| @@ -127,6 +127,7 @@ | |||
| 127 | #include <asm/prom.h> | 127 | #include <asm/prom.h> |
| 128 | #include <asm/machdep.h> | 128 | #include <asm/machdep.h> |
| 129 | #include <asm/io.h> | 129 | #include <asm/io.h> |
| 130 | #include <asm/system.h> | ||
| 130 | #include <asm/sections.h> | 131 | #include <asm/sections.h> |
| 131 | #include <asm/macio.h> | 132 | #include <asm/macio.h> |
| 132 | 133 | ||
diff --git a/drivers/macintosh/therm_windtunnel.c b/drivers/macintosh/therm_windtunnel.c index 3b4a157714b..46c4e95f10d 100644 --- a/drivers/macintosh/therm_windtunnel.c +++ b/drivers/macintosh/therm_windtunnel.c | |||
| @@ -41,6 +41,7 @@ | |||
| 41 | #include <asm/prom.h> | 41 | #include <asm/prom.h> |
| 42 | #include <asm/machdep.h> | 42 | #include <asm/machdep.h> |
| 43 | #include <asm/io.h> | 43 | #include <asm/io.h> |
| 44 | #include <asm/system.h> | ||
| 44 | #include <asm/sections.h> | 45 | #include <asm/sections.h> |
| 45 | #include <asm/macio.h> | 46 | #include <asm/macio.h> |
| 46 | 47 | ||
diff --git a/drivers/macintosh/via-cuda.c b/drivers/macintosh/via-cuda.c index 86511c570dd..971bc9582a5 100644 --- a/drivers/macintosh/via-cuda.c +++ b/drivers/macintosh/via-cuda.c | |||
| @@ -26,6 +26,7 @@ | |||
| 26 | #include <asm/mac_via.h> | 26 | #include <asm/mac_via.h> |
| 27 | #endif | 27 | #endif |
| 28 | #include <asm/io.h> | 28 | #include <asm/io.h> |
| 29 | #include <asm/system.h> | ||
| 29 | #include <linux/init.h> | 30 | #include <linux/init.h> |
| 30 | 31 | ||
| 31 | static volatile unsigned char __iomem *via; | 32 | static volatile unsigned char __iomem *via; |
diff --git a/drivers/macintosh/via-macii.c b/drivers/macintosh/via-macii.c index 3725f088f17..817f37a875c 100644 --- a/drivers/macintosh/via-macii.c +++ b/drivers/macintosh/via-macii.c | |||
| @@ -34,6 +34,7 @@ | |||
| 34 | #include <asm/macintosh.h> | 34 | #include <asm/macintosh.h> |
| 35 | #include <asm/macints.h> | 35 | #include <asm/macints.h> |
| 36 | #include <asm/mac_via.h> | 36 | #include <asm/mac_via.h> |
| 37 | #include <asm/system.h> | ||
| 37 | 38 | ||
| 38 | static volatile unsigned char *via; | 39 | static volatile unsigned char *via; |
| 39 | 40 | ||
| @@ -158,7 +159,7 @@ int macii_init(void) | |||
| 158 | err = macii_init_via(); | 159 | err = macii_init_via(); |
| 159 | if (err) goto out; | 160 | if (err) goto out; |
| 160 | 161 | ||
| 161 | err = request_irq(IRQ_MAC_ADB, macii_interrupt, 0, "ADB", | 162 | err = request_irq(IRQ_MAC_ADB, macii_interrupt, IRQ_FLG_LOCK, "ADB", |
| 162 | macii_interrupt); | 163 | macii_interrupt); |
| 163 | if (err) goto out; | 164 | if (err) goto out; |
| 164 | 165 | ||
diff --git a/drivers/macintosh/via-maciisi.c b/drivers/macintosh/via-maciisi.c index 34d02a91b29..9ab5b0c34f0 100644 --- a/drivers/macintosh/via-maciisi.c +++ b/drivers/macintosh/via-maciisi.c | |||
| @@ -122,8 +122,8 @@ maciisi_init(void) | |||
| 122 | return err; | 122 | return err; |
| 123 | } | 123 | } |
| 124 | 124 | ||
| 125 | if (request_irq(IRQ_MAC_ADB, maciisi_interrupt, 0, "ADB", | 125 | if (request_irq(IRQ_MAC_ADB, maciisi_interrupt, IRQ_FLG_LOCK | IRQ_FLG_FAST, |
| 126 | maciisi_interrupt)) { | 126 | "ADB", maciisi_interrupt)) { |
| 127 | printk(KERN_ERR "maciisi_init: can't get irq %d\n", IRQ_MAC_ADB); | 127 | printk(KERN_ERR "maciisi_init: can't get irq %d\n", IRQ_MAC_ADB); |
| 128 | return -EAGAIN; | 128 | return -EAGAIN; |
| 129 | } | 129 | } |
diff --git a/drivers/macintosh/via-pmu.c b/drivers/macintosh/via-pmu.c index 22b8ce4191c..6cccd60c594 100644 --- a/drivers/macintosh/via-pmu.c +++ b/drivers/macintosh/via-pmu.c | |||
| @@ -50,6 +50,7 @@ | |||
| 50 | #include <asm/machdep.h> | 50 | #include <asm/machdep.h> |
| 51 | #include <asm/io.h> | 51 | #include <asm/io.h> |
| 52 | #include <asm/pgtable.h> | 52 | #include <asm/pgtable.h> |
| 53 | #include <asm/system.h> | ||
| 53 | #include <asm/sections.h> | 54 | #include <asm/sections.h> |
| 54 | #include <asm/irq.h> | 55 | #include <asm/irq.h> |
| 55 | #include <asm/pmac_feature.h> | 56 | #include <asm/pmac_feature.h> |
diff --git a/drivers/macintosh/via-pmu68k.c b/drivers/macintosh/via-pmu68k.c index a00ee41f057..aeb30d07d5a 100644 --- a/drivers/macintosh/via-pmu68k.c +++ b/drivers/macintosh/via-pmu68k.c | |||
| @@ -37,6 +37,7 @@ | |||
| 37 | #include <asm/mac_via.h> | 37 | #include <asm/mac_via.h> |
| 38 | 38 | ||
| 39 | #include <asm/pgtable.h> | 39 | #include <asm/pgtable.h> |
| 40 | #include <asm/system.h> | ||
| 40 | #include <asm/irq.h> | 41 | #include <asm/irq.h> |
| 41 | #include <asm/uaccess.h> | 42 | #include <asm/uaccess.h> |
| 42 | 43 | ||
diff --git a/drivers/macintosh/windfarm.h b/drivers/macintosh/windfarm.h index 028cdac2d33..7a2482cc26a 100644 --- a/drivers/macintosh/windfarm.h +++ b/drivers/macintosh/windfarm.h | |||
| @@ -17,7 +17,7 @@ | |||
| 17 | #include <linux/device.h> | 17 | #include <linux/device.h> |
| 18 | 18 | ||
| 19 | /* Display a 16.16 fixed point value */ | 19 | /* Display a 16.16 fixed point value */ |
| 20 | #define FIX32TOPRINT(f) (((s32)(f)) >> 16),(((((s32)(f)) & 0xffff) * 1000) >> 16) | 20 | #define FIX32TOPRINT(f) ((f) >> 16),((((f) & 0xffff) * 1000) >> 16) |
| 21 | 21 | ||
| 22 | /* | 22 | /* |
| 23 | * Control objects | 23 | * Control objects |
| @@ -35,13 +35,12 @@ struct wf_control_ops { | |||
| 35 | }; | 35 | }; |
| 36 | 36 | ||
| 37 | struct wf_control { | 37 | struct wf_control { |
| 38 | struct list_head link; | 38 | struct list_head link; |
| 39 | const struct wf_control_ops *ops; | 39 | struct wf_control_ops *ops; |
| 40 | const char *name; | 40 | char *name; |
| 41 | int type; | 41 | int type; |
| 42 | struct kref ref; | 42 | struct kref ref; |
| 43 | struct device_attribute attr; | 43 | struct device_attribute attr; |
| 44 | void *priv; | ||
| 45 | }; | 44 | }; |
| 46 | 45 | ||
| 47 | #define WF_CONTROL_TYPE_GENERIC 0 | 46 | #define WF_CONTROL_TYPE_GENERIC 0 |
| @@ -73,26 +72,6 @@ static inline int wf_control_set_min(struct wf_control *ct) | |||
| 73 | return ct->ops->set_value(ct, vmin); | 72 | return ct->ops->set_value(ct, vmin); |
| 74 | } | 73 | } |
| 75 | 74 | ||
| 76 | static inline int wf_control_set(struct wf_control *ct, s32 val) | ||
| 77 | { | ||
| 78 | return ct->ops->set_value(ct, val); | ||
| 79 | } | ||
| 80 | |||
| 81 | static inline int wf_control_get(struct wf_control *ct, s32 *val) | ||
| 82 | { | ||
| 83 | return ct->ops->get_value(ct, val); | ||
| 84 | } | ||
| 85 | |||
| 86 | static inline s32 wf_control_get_min(struct wf_control *ct) | ||
| 87 | { | ||
| 88 | return ct->ops->get_min(ct); | ||
| 89 | } | ||
| 90 | |||
| 91 | static inline s32 wf_control_get_max(struct wf_control *ct) | ||
| 92 | { | ||
| 93 | return ct->ops->get_max(ct); | ||
| 94 | } | ||
| 95 | |||
| 96 | /* | 75 | /* |
| 97 | * Sensor objects | 76 | * Sensor objects |
| 98 | */ | 77 | */ |
| @@ -106,12 +85,11 @@ struct wf_sensor_ops { | |||
| 106 | }; | 85 | }; |
| 107 | 86 | ||
| 108 | struct wf_sensor { | 87 | struct wf_sensor { |
| 109 | struct list_head link; | 88 | struct list_head link; |
| 110 | const struct wf_sensor_ops *ops; | 89 | struct wf_sensor_ops *ops; |
| 111 | const char *name; | 90 | char *name; |
| 112 | struct kref ref; | 91 | struct kref ref; |
| 113 | struct device_attribute attr; | 92 | struct device_attribute attr; |
| 114 | void *priv; | ||
| 115 | }; | 93 | }; |
| 116 | 94 | ||
| 117 | /* Same lifetime rules as controls */ | 95 | /* Same lifetime rules as controls */ |
| @@ -121,11 +99,6 @@ extern struct wf_sensor * wf_find_sensor(const char *name); | |||
| 121 | extern int wf_get_sensor(struct wf_sensor *sr); | 99 | extern int wf_get_sensor(struct wf_sensor *sr); |
| 122 | extern void wf_put_sensor(struct wf_sensor *sr); | 100 | extern void wf_put_sensor(struct wf_sensor *sr); |
| 123 | 101 | ||
| 124 | static inline int wf_sensor_get(struct wf_sensor *sr, s32 *val) | ||
| 125 | { | ||
| 126 | return sr->ops->get_value(sr, val); | ||
| 127 | } | ||
| 128 | |||
| 129 | /* For use by clients. Note that we are a bit racy here since | 102 | /* For use by clients. Note that we are a bit racy here since |
| 130 | * notifier_block doesn't have a module owner field. I may fix | 103 | * notifier_block doesn't have a module owner field. I may fix |
| 131 | * it one day ... | 104 | * it one day ... |
diff --git a/drivers/macintosh/windfarm_ad7417_sensor.c b/drivers/macintosh/windfarm_ad7417_sensor.c deleted file mode 100644 index 7c28b71246c..00000000000 --- a/drivers/macintosh/windfarm_ad7417_sensor.c +++ /dev/null | |||
| @@ -1,347 +0,0 @@ | |||
| 1 | /* | ||
| 2 | * Windfarm PowerMac thermal control. AD7417 sensors | ||
| 3 | * | ||
| 4 | * Copyright 2012 Benjamin Herrenschmidt, IBM Corp. | ||
| 5 | * | ||
| 6 | * Released under the term of the GNU GPL v2. | ||
| 7 | */ | ||
| 8 | |||
| 9 | #include <linux/types.h> | ||
| 10 | #include <linux/errno.h> | ||
| 11 | #include <linux/kernel.h> | ||
| 12 | #include <linux/delay.h> | ||
| 13 | #include <linux/slab.h> | ||
| 14 | #include <linux/init.h> | ||
| 15 | #include <linux/wait.h> | ||
| 16 | #include <linux/i2c.h> | ||
| 17 | #include <asm/prom.h> | ||
| 18 | #include <asm/machdep.h> | ||
| 19 | #include <asm/io.h> | ||
| 20 | #include <asm/sections.h> | ||
| 21 | |||
| 22 | #include "windfarm.h" | ||
| 23 | #include "windfarm_mpu.h" | ||
| 24 | |||
| 25 | #define VERSION "1.0" | ||
| 26 | |||
| 27 | struct wf_ad7417_priv { | ||
| 28 | struct kref ref; | ||
| 29 | struct i2c_client *i2c; | ||
| 30 | u8 config; | ||
| 31 | u8 cpu; | ||
| 32 | const struct mpu_data *mpu; | ||
| 33 | struct wf_sensor sensors[5]; | ||
| 34 | struct mutex lock; | ||
| 35 | }; | ||
| 36 | |||
| 37 | static int wf_ad7417_temp_get(struct wf_sensor *sr, s32 *value) | ||
| 38 | { | ||
| 39 | struct wf_ad7417_priv *pv = sr->priv; | ||
| 40 | u8 buf[2]; | ||
| 41 | s16 raw; | ||
| 42 | int rc; | ||
| 43 | |||
| 44 | *value = 0; | ||
| 45 | mutex_lock(&pv->lock); | ||
| 46 | |||
| 47 | /* Read temp register */ | ||
| 48 | buf[0] = 0; | ||
| 49 | rc = i2c_master_send(pv->i2c, buf, 1); | ||
| 50 | if (rc < 0) | ||
| 51 | goto error; | ||
| 52 | rc = i2c_master_recv(pv->i2c, buf, 2); | ||
| 53 | if (rc < 0) | ||
| 54 | goto error; | ||
| 55 | |||
| 56 | /* Read a a 16-bit signed value */ | ||
| 57 | raw = be16_to_cpup((__le16 *)buf); | ||
| 58 | |||
| 59 | /* Convert 8.8-bit to 16.16 fixed point */ | ||
| 60 | *value = ((s32)raw) << 8; | ||
| 61 | |||
| 62 | mutex_unlock(&pv->lock); | ||
| 63 | return 0; | ||
| 64 | |||
| 65 | error: | ||
| 66 | mutex_unlock(&pv->lock); | ||
| 67 | return -1; | ||
| 68 | } | ||
| 69 | |||
| 70 | /* | ||
| 71 | * Scaling factors for the AD7417 ADC converters (except | ||
| 72 | * for the CPU diode which is obtained from the EEPROM). | ||
| 73 | * Those values are obtained from the property list of | ||
| 74 | * the darwin driver | ||
| 75 | */ | ||
| 76 | #define ADC_12V_CURRENT_SCALE 0x0320 /* _AD2 */ | ||
| 77 | #define ADC_CPU_VOLTAGE_SCALE 0x00a0 /* _AD3 */ | ||
| 78 | #define ADC_CPU_CURRENT_SCALE 0x1f40 /* _AD4 */ | ||
| 79 | |||
| 80 | static void wf_ad7417_adc_convert(struct wf_ad7417_priv *pv, | ||
| 81 | int chan, s32 raw, s32 *value) | ||
| 82 | { | ||
| 83 | switch(chan) { | ||
| 84 | case 1: /* Diode */ | ||
| 85 | *value = (raw * (s32)pv->mpu->mdiode + | ||
| 86 | ((s32)pv->mpu->bdiode << 12)) >> 2; | ||
| 87 | break; | ||
| 88 | case 2: /* 12v current */ | ||
| 89 | *value = raw * ADC_12V_CURRENT_SCALE; | ||
| 90 | break; | ||
| 91 | case 3: /* core voltage */ | ||
| 92 | *value = raw * ADC_CPU_VOLTAGE_SCALE; | ||
| 93 | break; | ||
| 94 | case 4: /* core current */ | ||
| 95 | *value = raw * ADC_CPU_CURRENT_SCALE; | ||
| 96 | break; | ||
| 97 | } | ||
| 98 | } | ||
| 99 | |||
| 100 | static int wf_ad7417_adc_get(struct wf_sensor *sr, s32 *value) | ||
| 101 | { | ||
| 102 | struct wf_ad7417_priv *pv = sr->priv; | ||
| 103 | int chan = sr - pv->sensors; | ||
| 104 | int i, rc; | ||
| 105 | u8 buf[2]; | ||
| 106 | u16 raw; | ||
| 107 | |||
| 108 | *value = 0; | ||
| 109 | mutex_lock(&pv->lock); | ||
| 110 | for (i = 0; i < 10; i++) { | ||
| 111 | /* Set channel */ | ||
| 112 | buf[0] = 1; | ||
| 113 | buf[1] = (pv->config & 0x1f) | (chan << 5); | ||
| 114 | rc = i2c_master_send(pv->i2c, buf, 2); | ||
| 115 | if (rc < 0) | ||
| 116 | goto error; | ||
| 117 | |||
| 118 | /* Wait for conversion */ | ||
| 119 | msleep(1); | ||
| 120 | |||
| 121 | /* Switch to data register */ | ||
| 122 | buf[0] = 4; | ||
| 123 | rc = i2c_master_send(pv->i2c, buf, 1); | ||
| 124 | if (rc < 0) | ||
| 125 | goto error; | ||
| 126 | |||
| 127 | /* Read result */ | ||
| 128 | rc = i2c_master_recv(pv->i2c, buf, 2); | ||
| 129 | if (rc < 0) | ||
| 130 | goto error; | ||
| 131 | |||
| 132 | /* Read a a 16-bit signed value */ | ||
| 133 | raw = be16_to_cpup((__le16 *)buf) >> 6; | ||
| 134 | wf_ad7417_adc_convert(pv, chan, raw, value); | ||
| 135 | |||
| 136 | dev_vdbg(&pv->i2c->dev, "ADC chan %d [%s]" | ||
| 137 | " raw value: 0x%x, conv to: 0x%08x\n", | ||
| 138 | chan, sr->name, raw, *value); | ||
| 139 | |||
| 140 | mutex_unlock(&pv->lock); | ||
| 141 | return 0; | ||
| 142 | |||
| 143 | error: | ||
| 144 | dev_dbg(&pv->i2c->dev, | ||
| 145 | "Error reading ADC, try %d...\n", i); | ||
| 146 | if (i < 9) | ||
| 147 | msleep(10); | ||
| 148 | } | ||
| 149 | mutex_unlock(&pv->lock); | ||
| 150 | return -1; | ||
| 151 | } | ||
| 152 | |||
| 153 | static void wf_ad7417_release(struct kref *ref) | ||
| 154 | { | ||
| 155 | struct wf_ad7417_priv *pv = container_of(ref, | ||
| 156 | struct wf_ad7417_priv, ref); | ||
| 157 | kfree(pv); | ||
| 158 | } | ||
| 159 | |||
| 160 | static void wf_ad7417_sensor_release(struct wf_sensor *sr) | ||
| 161 | { | ||
| 162 | struct wf_ad7417_priv *pv = sr->priv; | ||
| 163 | |||
| 164 | kfree(sr->name); | ||
| 165 | kref_put(&pv->ref, wf_ad7417_release); | ||
| 166 | } | ||
| 167 | |||
| 168 | static const struct wf_sensor_ops wf_ad7417_temp_ops = { | ||
| 169 | .get_value = wf_ad7417_temp_get, | ||
| 170 | .release = wf_ad7417_sensor_release, | ||
| 171 | .owner = THIS_MODULE, | ||
| 172 | }; | ||
| 173 | |||
| 174 | static const struct wf_sensor_ops wf_ad7417_adc_ops = { | ||
| 175 | .get_value = wf_ad7417_adc_get, | ||
| 176 | .release = wf_ad7417_sensor_release, | ||
| 177 | .owner = THIS_MODULE, | ||
| 178 | }; | ||
| 179 | |||
| 180 | static void wf_ad7417_add_sensor(struct wf_ad7417_priv *pv, | ||
| 181 | int index, const char *name, | ||
| 182 | const struct wf_sensor_ops *ops) | ||
| 183 | { | ||
| 184 | pv->sensors[index].name = kasprintf(GFP_KERNEL, "%s-%d", name, pv->cpu); | ||
| 185 | pv->sensors[index].priv = pv; | ||
| 186 | pv->sensors[index].ops = ops; | ||
| 187 | if (!wf_register_sensor(&pv->sensors[index])) | ||
| 188 | kref_get(&pv->ref); | ||
| 189 | } | ||
| 190 | |||
| 191 | static void wf_ad7417_init_chip(struct wf_ad7417_priv *pv) | ||
| 192 | { | ||
| 193 | int rc; | ||
| 194 | u8 buf[2]; | ||
| 195 | u8 config = 0; | ||
| 196 | |||
| 197 | /* | ||
| 198 | * Read ADC the configuration register and cache it. We | ||
| 199 | * also make sure Config2 contains proper values, I've seen | ||
| 200 | * cases where we got stale grabage in there, thus preventing | ||
| 201 | * proper reading of conv. values | ||
| 202 | */ | ||
| 203 | |||
| 204 | /* Clear Config2 */ | ||
| 205 | buf[0] = 5; | ||
| 206 | buf[1] = 0; | ||
| 207 | i2c_master_send(pv->i2c, buf, 2); | ||
| 208 | |||
| 209 | /* Read & cache Config1 */ | ||
| 210 | buf[0] = 1; | ||
| 211 | rc = i2c_master_send(pv->i2c, buf, 1); | ||
| 212 | if (rc > 0) { | ||
| 213 | rc = i2c_master_recv(pv->i2c, buf, 1); | ||
| 214 | if (rc > 0) { | ||
| 215 | config = buf[0]; | ||
| 216 | |||
| 217 | dev_dbg(&pv->i2c->dev, "ADC config reg: %02x\n", | ||
| 218 | config); | ||
| 219 | |||
| 220 | /* Disable shutdown mode */ | ||
| 221 | config &= 0xfe; | ||
| 222 | buf[0] = 1; | ||
| 223 | buf[1] = config; | ||
| 224 | rc = i2c_master_send(pv->i2c, buf, 2); | ||
| 225 | } | ||
| 226 | } | ||
| 227 | if (rc <= 0) | ||
| 228 | dev_err(&pv->i2c->dev, "Error reading ADC config\n"); | ||
| 229 | |||
| 230 | pv->config = config; | ||
| 231 | } | ||
| 232 | |||
| 233 | static int wf_ad7417_probe(struct i2c_client *client, | ||
| 234 | const struct i2c_device_id *id) | ||
| 235 | { | ||
| 236 | struct wf_ad7417_priv *pv; | ||
| 237 | const struct mpu_data *mpu; | ||
| 238 | const char *loc; | ||
| 239 | int cpu_nr; | ||
| 240 | |||
| 241 | loc = of_get_property(client->dev.of_node, "hwsensor-location", NULL); | ||
| 242 | if (!loc) { | ||
| 243 | dev_warn(&client->dev, "Missing hwsensor-location property!\n"); | ||
| 244 | return -ENXIO; | ||
| 245 | } | ||
| 246 | |||
| 247 | /* | ||
| 248 | * Identify which CPU we belong to by looking at the first entry | ||
| 249 | * in the hwsensor-location list | ||
| 250 | */ | ||
| 251 | if (!strncmp(loc, "CPU A", 5)) | ||
| 252 | cpu_nr = 0; | ||
| 253 | else if (!strncmp(loc, "CPU B", 5)) | ||
| 254 | cpu_nr = 1; | ||
| 255 | else { | ||
| 256 | pr_err("wf_ad7417: Can't identify location %s\n", loc); | ||
| 257 | return -ENXIO; | ||
| 258 | } | ||
| 259 | mpu = wf_get_mpu(cpu_nr); | ||
| 260 | if (!mpu) { | ||
| 261 | dev_err(&client->dev, "Failed to retrieve MPU data\n"); | ||
| 262 | return -ENXIO; | ||
| 263 | } | ||
| 264 | |||
| 265 | pv = kzalloc(sizeof(struct wf_ad7417_priv), GFP_KERNEL); | ||
| 266 | if (pv == NULL) | ||
| 267 | return -ENODEV; | ||
| 268 | |||
| 269 | kref_init(&pv->ref); | ||
| 270 | mutex_init(&pv->lock); | ||
| 271 | pv->i2c = client; | ||
| 272 | pv->cpu = cpu_nr; | ||
| 273 | pv->mpu = mpu; | ||
| 274 | dev_set_drvdata(&client->dev, pv); | ||
| 275 | |||
| 276 | /* Initialize the chip */ | ||
| 277 | wf_ad7417_init_chip(pv); | ||
| 278 | |||
| 279 | /* | ||
| 280 | * We cannot rely on Apple device-tree giving us child | ||
| 281 | * node with the names of the individual sensors so we | ||
| 282 | * just hard code what we know about them | ||
| 283 | */ | ||
| 284 | wf_ad7417_add_sensor(pv, 0, "cpu-amb-temp", &wf_ad7417_temp_ops); | ||
| 285 | wf_ad7417_add_sensor(pv, 1, "cpu-diode-temp", &wf_ad7417_adc_ops); | ||
| 286 | wf_ad7417_add_sensor(pv, 2, "cpu-12v-current", &wf_ad7417_adc_ops); | ||
| 287 | wf_ad7417_add_sensor(pv, 3, "cpu-voltage", &wf_ad7417_adc_ops); | ||
| 288 | wf_ad7417_add_sensor(pv, 4, "cpu-current", &wf_ad7417_adc_ops); | ||
| 289 | |||
| 290 | return 0; | ||
| 291 | } | ||
| 292 | |||
| 293 | static int wf_ad7417_remove(struct i2c_client *client) | ||
| 294 | { | ||
| 295 | struct wf_ad7417_priv *pv = dev_get_drvdata(&client->dev); | ||
| 296 | int i; | ||
| 297 | |||
| 298 | /* Mark client detached */ | ||
| 299 | pv->i2c = NULL; | ||
| 300 | |||
| 301 | /* Release sensor */ | ||
| 302 | for (i = 0; i < 5; i++) | ||
| 303 | wf_unregister_sensor(&pv->sensors[i]); | ||
| 304 | |||
| 305 | kref_put(&pv->ref, wf_ad7417_release); | ||
| 306 | |||
| 307 | return 0; | ||
| 308 | } | ||
| 309 | |||
| 310 | static const struct i2c_device_id wf_ad7417_id[] = { | ||
| 311 | { "MAC,ad7417", 0 }, | ||
| 312 | { } | ||
| 313 | }; | ||
| 314 | MODULE_DEVICE_TABLE(i2c, wf_ad7417_id); | ||
| 315 | |||
| 316 | static struct i2c_driver wf_ad7417_driver = { | ||
| 317 | .driver = { | ||
| 318 | .name = "wf_ad7417", | ||
| 319 | }, | ||
| 320 | .probe = wf_ad7417_probe, | ||
| 321 | .remove = wf_ad7417_remove, | ||
| 322 | .id_table = wf_ad7417_id, | ||
| 323 | }; | ||
| 324 | |||
| 325 | static int wf_ad7417_init(void) | ||
| 326 | { | ||
| 327 | /* This is only supported on these machines */ | ||
| 328 | if (!of_machine_is_compatible("PowerMac7,2") && | ||
| 329 | !of_machine_is_compatible("PowerMac7,3") && | ||
| 330 | !of_machine_is_compatible("RackMac3,1")) | ||
| 331 | return -ENODEV; | ||
| 332 | |||
| 333 | return i2c_add_driver(&wf_ad7417_driver); | ||
| 334 | } | ||
| 335 | |||
| 336 | static void wf_ad7417_exit(void) | ||
| 337 | { | ||
| 338 | i2c_del_driver(&wf_ad7417_driver); | ||
| 339 | } | ||
| 340 | |||
| 341 | module_init(wf_ad7417_init); | ||
| 342 | module_exit(wf_ad7417_exit); | ||
| 343 | |||
| 344 | MODULE_AUTHOR("Benjamin Herrenschmidt <benh@kernel.crashing.org>"); | ||
| 345 | MODULE_DESCRIPTION("ad7417 sensor driver for PowerMacs"); | ||
| 346 | MODULE_LICENSE("GPL"); | ||
| 347 | |||
diff --git a/drivers/macintosh/windfarm_core.c b/drivers/macintosh/windfarm_core.c index 3ee198b6584..ce8897933a8 100644 --- a/drivers/macintosh/windfarm_core.c +++ b/drivers/macintosh/windfarm_core.c | |||
| @@ -164,27 +164,13 @@ static ssize_t wf_show_control(struct device *dev, | |||
| 164 | struct device_attribute *attr, char *buf) | 164 | struct device_attribute *attr, char *buf) |
| 165 | { | 165 | { |
| 166 | struct wf_control *ctrl = container_of(attr, struct wf_control, attr); | 166 | struct wf_control *ctrl = container_of(attr, struct wf_control, attr); |
| 167 | const char *typestr; | ||
| 168 | s32 val = 0; | 167 | s32 val = 0; |
| 169 | int err; | 168 | int err; |
| 170 | 169 | ||
| 171 | err = ctrl->ops->get_value(ctrl, &val); | 170 | err = ctrl->ops->get_value(ctrl, &val); |
| 172 | if (err < 0) { | 171 | if (err < 0) |
| 173 | if (err == -EFAULT) | ||
| 174 | return sprintf(buf, "<HW FAULT>\n"); | ||
| 175 | return err; | 172 | return err; |
| 176 | } | 173 | return sprintf(buf, "%d\n", val); |
| 177 | switch(ctrl->type) { | ||
| 178 | case WF_CONTROL_RPM_FAN: | ||
| 179 | typestr = " RPM"; | ||
| 180 | break; | ||
| 181 | case WF_CONTROL_PWM_FAN: | ||
| 182 | typestr = " %"; | ||
| 183 | break; | ||
| 184 | default: | ||
| 185 | typestr = ""; | ||
| 186 | } | ||
| 187 | return sprintf(buf, "%d%s\n", val, typestr); | ||
| 188 | } | 174 | } |
| 189 | 175 | ||
| 190 | /* This is really only for debugging... */ | 176 | /* This is really only for debugging... */ |
| @@ -484,6 +470,11 @@ static int __init windfarm_core_init(void) | |||
| 484 | { | 470 | { |
| 485 | DBG("wf: core loaded\n"); | 471 | DBG("wf: core loaded\n"); |
| 486 | 472 | ||
| 473 | /* Don't register on old machines that use therm_pm72 for now */ | ||
| 474 | if (of_machine_is_compatible("PowerMac7,2") || | ||
| 475 | of_machine_is_compatible("PowerMac7,3") || | ||
| 476 | of_machine_is_compatible("RackMac3,1")) | ||
| 477 | return -ENODEV; | ||
| 487 | platform_device_register(&wf_platform_device); | 478 | platform_device_register(&wf_platform_device); |
| 488 | return 0; | 479 | return 0; |
| 489 | } | 480 | } |
diff --git a/drivers/macintosh/windfarm_cpufreq_clamp.c b/drivers/macintosh/windfarm_cpufreq_clamp.c index 72d1fdfe02a..1a77a7c97d0 100644 --- a/drivers/macintosh/windfarm_cpufreq_clamp.c +++ b/drivers/macintosh/windfarm_cpufreq_clamp.c | |||
| @@ -75,6 +75,12 @@ static int __init wf_cpufreq_clamp_init(void) | |||
| 75 | { | 75 | { |
| 76 | struct wf_control *clamp; | 76 | struct wf_control *clamp; |
| 77 | 77 | ||
| 78 | /* Don't register on old machines that use therm_pm72 for now */ | ||
| 79 | if (of_machine_is_compatible("PowerMac7,2") || | ||
| 80 | of_machine_is_compatible("PowerMac7,3") || | ||
| 81 | of_machine_is_compatible("RackMac3,1")) | ||
| 82 | return -ENODEV; | ||
| 83 | |||
| 78 | clamp = kmalloc(sizeof(struct wf_control), GFP_KERNEL); | 84 | clamp = kmalloc(sizeof(struct wf_control), GFP_KERNEL); |
| 79 | if (clamp == NULL) | 85 | if (clamp == NULL) |
| 80 | return -ENOMEM; | 86 | return -ENOMEM; |
diff --git a/drivers/macintosh/windfarm_fcu_controls.c b/drivers/macintosh/windfarm_fcu_controls.c deleted file mode 100644 index 0226b796a21..00000000000 --- a/drivers/macintosh/windfarm_fcu_controls.c +++ /dev/null | |||
| @@ -1,600 +0,0 @@ | |||
| 1 | /* | ||
| 2 | * Windfarm PowerMac thermal control. FCU fan control | ||
| 3 | * | ||
| 4 | * Copyright 2012 Benjamin Herrenschmidt, IBM Corp. | ||
| 5 | * | ||
| 6 | * Released under the term of the GNU GPL v2. | ||
| 7 | */ | ||
| 8 | #undef DEBUG | ||
| 9 | |||
| 10 | #include <linux/types.h> | ||
| 11 | #include <linux/errno.h> | ||
| 12 | #include <linux/kernel.h> | ||
| 13 | #include <linux/delay.h> | ||
| 14 | #include <linux/slab.h> | ||
| 15 | #include <linux/init.h> | ||
| 16 | #include <linux/wait.h> | ||
| 17 | #include <linux/i2c.h> | ||
| 18 | #include <asm/prom.h> | ||
| 19 | #include <asm/machdep.h> | ||
| 20 | #include <asm/io.h> | ||
| 21 | #include <asm/sections.h> | ||
| 22 | |||
| 23 | #include "windfarm.h" | ||
| 24 | #include "windfarm_mpu.h" | ||
| 25 | |||
| 26 | #define VERSION "1.0" | ||
| 27 | |||
| 28 | #ifdef DEBUG | ||
| 29 | #define DBG(args...) printk(args) | ||
| 30 | #else | ||
| 31 | #define DBG(args...) do { } while(0) | ||
| 32 | #endif | ||
| 33 | |||
| 34 | /* | ||
| 35 | * This option is "weird" :) Basically, if you define this to 1 | ||
| 36 | * the control loop for the RPMs fans (not PWMs) will apply the | ||
| 37 | * correction factor obtained from the PID to the actual RPM | ||
| 38 | * speed read from the FCU. | ||
| 39 | * | ||
| 40 | * If you define the below constant to 0, then it will be | ||
| 41 | * applied to the setpoint RPM speed, that is basically the | ||
| 42 | * speed we proviously "asked" for. | ||
| 43 | * | ||
| 44 | * I'm using 0 for now which is what therm_pm72 used to do and | ||
| 45 | * what Darwin -apparently- does based on observed behaviour. | ||
| 46 | */ | ||
| 47 | #define RPM_PID_USE_ACTUAL_SPEED 0 | ||
| 48 | |||
| 49 | /* Default min/max for pumps */ | ||
| 50 | #define CPU_PUMP_OUTPUT_MAX 3200 | ||
| 51 | #define CPU_PUMP_OUTPUT_MIN 1250 | ||
| 52 | |||
| 53 | #define FCU_FAN_RPM 0 | ||
| 54 | #define FCU_FAN_PWM 1 | ||
| 55 | |||
| 56 | struct wf_fcu_priv { | ||
| 57 | struct kref ref; | ||
| 58 | struct i2c_client *i2c; | ||
| 59 | struct mutex lock; | ||
| 60 | struct list_head fan_list; | ||
| 61 | int rpm_shift; | ||
| 62 | }; | ||
| 63 | |||
| 64 | struct wf_fcu_fan { | ||
| 65 | struct list_head link; | ||
| 66 | int id; | ||
| 67 | s32 min, max, target; | ||
| 68 | struct wf_fcu_priv *fcu_priv; | ||
| 69 | struct wf_control ctrl; | ||
| 70 | }; | ||
| 71 | |||
| 72 | static void wf_fcu_release(struct kref *ref) | ||
| 73 | { | ||
| 74 | struct wf_fcu_priv *pv = container_of(ref, struct wf_fcu_priv, ref); | ||
| 75 | |||
| 76 | kfree(pv); | ||
| 77 | } | ||
| 78 | |||
| 79 | static void wf_fcu_fan_release(struct wf_control *ct) | ||
| 80 | { | ||
| 81 | struct wf_fcu_fan *fan = ct->priv; | ||
| 82 | |||
| 83 | kref_put(&fan->fcu_priv->ref, wf_fcu_release); | ||
| 84 | kfree(fan); | ||
| 85 | } | ||
| 86 | |||
| 87 | static int wf_fcu_read_reg(struct wf_fcu_priv *pv, int reg, | ||
| 88 | unsigned char *buf, int nb) | ||
| 89 | { | ||
| 90 | int tries, nr, nw; | ||
| 91 | |||
| 92 | mutex_lock(&pv->lock); | ||
| 93 | |||
| 94 | buf[0] = reg; | ||
| 95 | tries = 0; | ||
| 96 | for (;;) { | ||
| 97 | nw = i2c_master_send(pv->i2c, buf, 1); | ||
| 98 | if (nw > 0 || (nw < 0 && nw != -EIO) || tries >= 100) | ||
| 99 | break; | ||
| 100 | msleep(10); | ||
| 101 | ++tries; | ||
| 102 | } | ||
| 103 | if (nw <= 0) { | ||
| 104 | pr_err("Failure writing address to FCU: %d", nw); | ||
| 105 | nr = nw; | ||
| 106 | goto bail; | ||
| 107 | } | ||
| 108 | tries = 0; | ||
| 109 | for (;;) { | ||
| 110 | nr = i2c_master_recv(pv->i2c, buf, nb); | ||
| 111 | if (nr > 0 || (nr < 0 && nr != -ENODEV) || tries >= 100) | ||
| 112 | break; | ||
| 113 | msleep(10); | ||
| 114 | ++tries; | ||
| 115 | } | ||
| 116 | if (nr <= 0) | ||
| 117 | pr_err("wf_fcu: Failure reading data from FCU: %d", nw); | ||
| 118 | bail: | ||
| 119 | mutex_unlock(&pv->lock); | ||
| 120 | return nr; | ||
| 121 | } | ||
| 122 | |||
| 123 | static int wf_fcu_write_reg(struct wf_fcu_priv *pv, int reg, | ||
| 124 | const unsigned char *ptr, int nb) | ||
| 125 | { | ||
| 126 | int tries, nw; | ||
| 127 | unsigned char buf[16]; | ||
| 128 | |||
| 129 | buf[0] = reg; | ||
| 130 | memcpy(buf+1, ptr, nb); | ||
| 131 | ++nb; | ||
| 132 | tries = 0; | ||
| 133 | for (;;) { | ||
| 134 | nw = i2c_master_send(pv->i2c, buf, nb); | ||
| 135 | if (nw > 0 || (nw < 0 && nw != -EIO) || tries >= 100) | ||
| 136 | break; | ||
| 137 | msleep(10); | ||
| 138 | ++tries; | ||
| 139 | } | ||
| 140 | if (nw < 0) | ||
| 141 | pr_err("wf_fcu: Failure writing to FCU: %d", nw); | ||
| 142 | return nw; | ||
| 143 | } | ||
| 144 | |||
| 145 | static int wf_fcu_fan_set_rpm(struct wf_control *ct, s32 value) | ||
| 146 | { | ||
| 147 | struct wf_fcu_fan *fan = ct->priv; | ||
| 148 | struct wf_fcu_priv *pv = fan->fcu_priv; | ||
| 149 | int rc, shift = pv->rpm_shift; | ||
| 150 | unsigned char buf[2]; | ||
| 151 | |||
| 152 | if (value < fan->min) | ||
| 153 | value = fan->min; | ||
| 154 | if (value > fan->max) | ||
| 155 | value = fan->max; | ||
| 156 | |||
| 157 | fan->target = value; | ||
| 158 | |||
| 159 | buf[0] = value >> (8 - shift); | ||
| 160 | buf[1] = value << shift; | ||
| 161 | rc = wf_fcu_write_reg(pv, 0x10 + (fan->id * 2), buf, 2); | ||
| 162 | if (rc < 0) | ||
| 163 | return -EIO; | ||
| 164 | return 0; | ||
| 165 | } | ||
| 166 | |||
| 167 | static int wf_fcu_fan_get_rpm(struct wf_control *ct, s32 *value) | ||
| 168 | { | ||
| 169 | struct wf_fcu_fan *fan = ct->priv; | ||
| 170 | struct wf_fcu_priv *pv = fan->fcu_priv; | ||
| 171 | int rc, reg_base, shift = pv->rpm_shift; | ||
| 172 | unsigned char failure; | ||
| 173 | unsigned char active; | ||
| 174 | unsigned char buf[2]; | ||
| 175 | |||
| 176 | rc = wf_fcu_read_reg(pv, 0xb, &failure, 1); | ||
| 177 | if (rc != 1) | ||
| 178 | return -EIO; | ||
| 179 | if ((failure & (1 << fan->id)) != 0) | ||
| 180 | return -EFAULT; | ||
| 181 | rc = wf_fcu_read_reg(pv, 0xd, &active, 1); | ||
| 182 | if (rc != 1) | ||
| 183 | return -EIO; | ||
| 184 | if ((active & (1 << fan->id)) == 0) | ||
| 185 | return -ENXIO; | ||
| 186 | |||
| 187 | /* Programmed value or real current speed */ | ||
| 188 | #if RPM_PID_USE_ACTUAL_SPEED | ||
| 189 | reg_base = 0x11; | ||
| 190 | #else | ||
| 191 | reg_base = 0x10; | ||
| 192 | #endif | ||
| 193 | rc = wf_fcu_read_reg(pv, reg_base + (fan->id * 2), buf, 2); | ||
| 194 | if (rc != 2) | ||
| 195 | return -EIO; | ||
| 196 | |||
| 197 | *value = (buf[0] << (8 - shift)) | buf[1] >> shift; | ||
| 198 | |||
| 199 | return 0; | ||
| 200 | } | ||
| 201 | |||
| 202 | static int wf_fcu_fan_set_pwm(struct wf_control *ct, s32 value) | ||
| 203 | { | ||
| 204 | struct wf_fcu_fan *fan = ct->priv; | ||
| 205 | struct wf_fcu_priv *pv = fan->fcu_priv; | ||
| 206 | unsigned char buf[2]; | ||
| 207 | int rc; | ||
| 208 | |||
| 209 | if (value < fan->min) | ||
| 210 | value = fan->min; | ||
| 211 | if (value > fan->max) | ||
| 212 | value = fan->max; | ||
| 213 | |||
| 214 | fan->target = value; | ||
| 215 | |||
| 216 | value = (value * 2559) / 1000; | ||
| 217 | buf[0] = value; | ||
| 218 | rc = wf_fcu_write_reg(pv, 0x30 + (fan->id * 2), buf, 1); | ||
| 219 | if (rc < 0) | ||
| 220 | return -EIO; | ||
| 221 | return 0; | ||
| 222 | } | ||
| 223 | |||
| 224 | static int wf_fcu_fan_get_pwm(struct wf_control *ct, s32 *value) | ||
| 225 | { | ||
| 226 | struct wf_fcu_fan *fan = ct->priv; | ||
| 227 | struct wf_fcu_priv *pv = fan->fcu_priv; | ||
| 228 | unsigned char failure; | ||
| 229 | unsigned char active; | ||
| 230 | unsigned char buf[2]; | ||
| 231 | int rc; | ||
| 232 | |||
| 233 | rc = wf_fcu_read_reg(pv, 0x2b, &failure, 1); | ||
| 234 | if (rc != 1) | ||
| 235 | return -EIO; | ||
| 236 | if ((failure & (1 << fan->id)) != 0) | ||
| 237 | return -EFAULT; | ||
| 238 | rc = wf_fcu_read_reg(pv, 0x2d, &active, 1); | ||
| 239 | if (rc != 1) | ||
| 240 | return -EIO; | ||
| 241 | if ((active & (1 << fan->id)) == 0) | ||
| 242 | return -ENXIO; | ||
| 243 | |||
| 244 | rc = wf_fcu_read_reg(pv, 0x30 + (fan->id * 2), buf, 1); | ||
| 245 | if (rc != 1) | ||
| 246 | return -EIO; | ||
| 247 | |||
| 248 | *value = (((s32)buf[0]) * 1000) / 2559; | ||
| 249 | |||
| 250 | return 0; | ||
| 251 | } | ||
| 252 | |||
| 253 | static s32 wf_fcu_fan_min(struct wf_control *ct) | ||
| 254 | { | ||
| 255 | struct wf_fcu_fan *fan = ct->priv; | ||
| 256 | |||
| 257 | return fan->min; | ||
| 258 | } | ||
| 259 | |||
| 260 | static s32 wf_fcu_fan_max(struct wf_control *ct) | ||
| 261 | { | ||
| 262 | struct wf_fcu_fan *fan = ct->priv; | ||
| 263 | |||
| 264 | return fan->max; | ||
| 265 | } | ||
| 266 | |||
| 267 | static const struct wf_control_ops wf_fcu_fan_rpm_ops = { | ||
| 268 | .set_value = wf_fcu_fan_set_rpm, | ||
| 269 | .get_value = wf_fcu_fan_get_rpm, | ||
| 270 | .get_min = wf_fcu_fan_min, | ||
| 271 | .get_max = wf_fcu_fan_max, | ||
| 272 | .release = wf_fcu_fan_release, | ||
| 273 | .owner = THIS_MODULE, | ||
| 274 | }; | ||
| 275 | |||
| 276 | static const struct wf_control_ops wf_fcu_fan_pwm_ops = { | ||
| 277 | .set_value = wf_fcu_fan_set_pwm, | ||
| 278 | .get_value = wf_fcu_fan_get_pwm, | ||
| 279 | .get_min = wf_fcu_fan_min, | ||
| 280 | .get_max = wf_fcu_fan_max, | ||
| 281 | .release = wf_fcu_fan_release, | ||
| 282 | .owner = THIS_MODULE, | ||
| 283 | }; | ||
| 284 | |||
| 285 | static void wf_fcu_get_pump_minmax(struct wf_fcu_fan *fan) | ||
| 286 | { | ||
| 287 | const struct mpu_data *mpu = wf_get_mpu(0); | ||
| 288 | u16 pump_min = 0, pump_max = 0xffff; | ||
| 289 | u16 tmp[4]; | ||
| 290 | |||
| 291 | /* Try to fetch pumps min/max infos from eeprom */ | ||
| 292 | if (mpu) { | ||
| 293 | memcpy(&tmp, mpu->processor_part_num, 8); | ||
| 294 | if (tmp[0] != 0xffff && tmp[1] != 0xffff) { | ||
| 295 | pump_min = max(pump_min, tmp[0]); | ||
| 296 | pump_max = min(pump_max, tmp[1]); | ||
| 297 | } | ||
| 298 | if (tmp[2] != 0xffff && tmp[3] != 0xffff) { | ||
| 299 | pump_min = max(pump_min, tmp[2]); | ||
| 300 | pump_max = min(pump_max, tmp[3]); | ||
| 301 | } | ||
| 302 | } | ||
| 303 | |||
| 304 | /* Double check the values, this _IS_ needed as the EEPROM on | ||
| 305 | * some dual 2.5Ghz G5s seem, at least, to have both min & max | ||
| 306 | * same to the same value ... (grrrr) | ||
| 307 | */ | ||
| 308 | if (pump_min == pump_max || pump_min == 0 || pump_max == 0xffff) { | ||
| 309 | pump_min = CPU_PUMP_OUTPUT_MIN; | ||
| 310 | pump_max = CPU_PUMP_OUTPUT_MAX; | ||
| 311 | } | ||
| 312 | |||
| 313 | fan->min = pump_min; | ||
| 314 | fan->max = pump_max; | ||
| 315 | |||
| 316 | DBG("wf_fcu: pump min/max for %s set to: [%d..%d] RPM\n", | ||
| 317 | fan->ctrl.name, pump_min, pump_max); | ||
| 318 | } | ||
| 319 | |||
| 320 | static void wf_fcu_get_rpmfan_minmax(struct wf_fcu_fan *fan) | ||
| 321 | { | ||
| 322 | struct wf_fcu_priv *pv = fan->fcu_priv; | ||
| 323 | const struct mpu_data *mpu0 = wf_get_mpu(0); | ||
| 324 | const struct mpu_data *mpu1 = wf_get_mpu(1); | ||
| 325 | |||
| 326 | /* Default */ | ||
| 327 | fan->min = 2400 >> pv->rpm_shift; | ||
| 328 | fan->max = 56000 >> pv->rpm_shift; | ||
| 329 | |||
| 330 | /* CPU fans have min/max in MPU */ | ||
| 331 | if (mpu0 && !strcmp(fan->ctrl.name, "cpu-front-fan-0")) { | ||
| 332 | fan->min = max(fan->min, (s32)mpu0->rminn_intake_fan); | ||
| 333 | fan->max = min(fan->max, (s32)mpu0->rmaxn_intake_fan); | ||
| 334 | goto bail; | ||
| 335 | } | ||
| 336 | if (mpu1 && !strcmp(fan->ctrl.name, "cpu-front-fan-1")) { | ||
| 337 | fan->min = max(fan->min, (s32)mpu1->rminn_intake_fan); | ||
| 338 | fan->max = min(fan->max, (s32)mpu1->rmaxn_intake_fan); | ||
| 339 | goto bail; | ||
| 340 | } | ||
| 341 | if (mpu0 && !strcmp(fan->ctrl.name, "cpu-rear-fan-0")) { | ||
| 342 | fan->min = max(fan->min, (s32)mpu0->rminn_exhaust_fan); | ||
| 343 | fan->max = min(fan->max, (s32)mpu0->rmaxn_exhaust_fan); | ||
| 344 | goto bail; | ||
| 345 | } | ||
| 346 | if (mpu1 && !strcmp(fan->ctrl.name, "cpu-rear-fan-1")) { | ||
| 347 | fan->min = max(fan->min, (s32)mpu1->rminn_exhaust_fan); | ||
| 348 | fan->max = min(fan->max, (s32)mpu1->rmaxn_exhaust_fan); | ||
| 349 | goto bail; | ||
| 350 | } | ||
| 351 | /* Rackmac variants, we just use mpu0 intake */ | ||
| 352 | if (!strncmp(fan->ctrl.name, "cpu-fan", 7)) { | ||
| 353 | fan->min = max(fan->min, (s32)mpu0->rminn_intake_fan); | ||
| 354 | fan->max = min(fan->max, (s32)mpu0->rmaxn_intake_fan); | ||
| 355 | goto bail; | ||
| 356 | } | ||
| 357 | bail: | ||
| 358 | DBG("wf_fcu: fan min/max for %s set to: [%d..%d] RPM\n", | ||
| 359 | fan->ctrl.name, fan->min, fan->max); | ||
| 360 | } | ||
| 361 | |||
| 362 | static void wf_fcu_add_fan(struct wf_fcu_priv *pv, const char *name, | ||
| 363 | int type, int id) | ||
| 364 | { | ||
| 365 | struct wf_fcu_fan *fan; | ||
| 366 | |||
| 367 | fan = kzalloc(sizeof(*fan), GFP_KERNEL); | ||
| 368 | if (!fan) | ||
| 369 | return; | ||
| 370 | fan->fcu_priv = pv; | ||
| 371 | fan->id = id; | ||
| 372 | fan->ctrl.name = name; | ||
| 373 | fan->ctrl.priv = fan; | ||
| 374 | |||
| 375 | /* min/max is oddball but the code comes from | ||
| 376 | * therm_pm72 which seems to work so ... | ||
| 377 | */ | ||
| 378 | if (type == FCU_FAN_RPM) { | ||
| 379 | if (!strncmp(name, "cpu-pump", strlen("cpu-pump"))) | ||
| 380 | wf_fcu_get_pump_minmax(fan); | ||
| 381 | else | ||
| 382 | wf_fcu_get_rpmfan_minmax(fan); | ||
| 383 | fan->ctrl.type = WF_CONTROL_RPM_FAN; | ||
| 384 | fan->ctrl.ops = &wf_fcu_fan_rpm_ops; | ||
| 385 | } else { | ||
| 386 | fan->min = 10; | ||
| 387 | fan->max = 100; | ||
| 388 | fan->ctrl.type = WF_CONTROL_PWM_FAN; | ||
| 389 | fan->ctrl.ops = &wf_fcu_fan_pwm_ops; | ||
| 390 | } | ||
| 391 | |||
| 392 | if (wf_register_control(&fan->ctrl)) { | ||
| 393 | pr_err("wf_fcu: Failed to register fan %s\n", name); | ||
| 394 | kfree(fan); | ||
| 395 | return; | ||
| 396 | } | ||
| 397 | list_add(&fan->link, &pv->fan_list); | ||
| 398 | kref_get(&pv->ref); | ||
| 399 | } | ||
| 400 | |||
| 401 | static void wf_fcu_lookup_fans(struct wf_fcu_priv *pv) | ||
| 402 | { | ||
| 403 | /* Translation of device-tree location properties to | ||
| 404 | * windfarm fan names | ||
| 405 | */ | ||
| 406 | static const struct { | ||
| 407 | const char *dt_name; /* Device-tree name */ | ||
| 408 | const char *ct_name; /* Control name */ | ||
| 409 | } loc_trans[] = { | ||
| 410 | { "BACKSIDE", "backside-fan", }, | ||
| 411 | { "SYS CTRLR FAN", "backside-fan", }, | ||
| 412 | { "DRIVE BAY", "drive-bay-fan", }, | ||
| 413 | { "SLOT", "slots-fan", }, | ||
| 414 | { "PCI FAN", "slots-fan", }, | ||
| 415 | { "CPU A INTAKE", "cpu-front-fan-0", }, | ||
| 416 | { "CPU A EXHAUST", "cpu-rear-fan-0", }, | ||
| 417 | { "CPU B INTAKE", "cpu-front-fan-1", }, | ||
| 418 | { "CPU B EXHAUST", "cpu-rear-fan-1", }, | ||
| 419 | { "CPU A PUMP", "cpu-pump-0", }, | ||
| 420 | { "CPU B PUMP", "cpu-pump-1", }, | ||
| 421 | { "CPU A 1", "cpu-fan-a-0", }, | ||
| 422 | { "CPU A 2", "cpu-fan-b-0", }, | ||
| 423 | { "CPU A 3", "cpu-fan-c-0", }, | ||
| 424 | { "CPU B 1", "cpu-fan-a-1", }, | ||
| 425 | { "CPU B 2", "cpu-fan-b-1", }, | ||
| 426 | { "CPU B 3", "cpu-fan-c-1", }, | ||
| 427 | }; | ||
| 428 | struct device_node *np = NULL, *fcu = pv->i2c->dev.of_node; | ||
| 429 | int i; | ||
| 430 | |||
| 431 | DBG("Looking up FCU controls in device-tree...\n"); | ||
| 432 | |||
| 433 | while ((np = of_get_next_child(fcu, np)) != NULL) { | ||
| 434 | int id, type = -1; | ||
| 435 | const char *loc; | ||
| 436 | const char *name; | ||
| 437 | const u32 *reg; | ||
| 438 | |||
| 439 | DBG(" control: %s, type: %s\n", np->name, np->type); | ||
| 440 | |||
| 441 | /* Detect control type */ | ||
| 442 | if (!strcmp(np->type, "fan-rpm-control") || | ||
| 443 | !strcmp(np->type, "fan-rpm")) | ||
| 444 | type = FCU_FAN_RPM; | ||
| 445 | if (!strcmp(np->type, "fan-pwm-control") || | ||
| 446 | !strcmp(np->type, "fan-pwm")) | ||
| 447 | type = FCU_FAN_PWM; | ||
| 448 | /* Only care about fans for now */ | ||
| 449 | if (type == -1) | ||
| 450 | continue; | ||
| 451 | |||
| 452 | /* Lookup for a matching location */ | ||
| 453 | loc = of_get_property(np, "location", NULL); | ||
| 454 | reg = of_get_property(np, "reg", NULL); | ||
| 455 | if (loc == NULL || reg == NULL) | ||
| 456 | continue; | ||
| 457 | DBG(" matching location: %s, reg: 0x%08x\n", loc, *reg); | ||
| 458 | |||
| 459 | for (i = 0; i < ARRAY_SIZE(loc_trans); i++) { | ||
| 460 | if (strncmp(loc, loc_trans[i].dt_name, | ||
| 461 | strlen(loc_trans[i].dt_name))) | ||
| 462 | continue; | ||
| 463 | name = loc_trans[i].ct_name; | ||
| 464 | |||
| 465 | DBG(" location match, name: %s\n", name); | ||
| 466 | |||
| 467 | if (type == FCU_FAN_RPM) | ||
| 468 | id = ((*reg) - 0x10) / 2; | ||
| 469 | else | ||
| 470 | id = ((*reg) - 0x30) / 2; | ||
| 471 | if (id > 7) { | ||
| 472 | pr_warning("wf_fcu: Can't parse " | ||
| 473 | "fan ID in device-tree for %s\n", | ||
| 474 | np->full_name); | ||
| 475 | break; | ||
| 476 | } | ||
| 477 | wf_fcu_add_fan(pv, name, type, id); | ||
| 478 | break; | ||
| 479 | } | ||
| 480 | } | ||
| 481 | } | ||
| 482 | |||
| 483 | static void wf_fcu_default_fans(struct wf_fcu_priv *pv) | ||
| 484 | { | ||
| 485 | /* We only support the default fans for PowerMac7,2 */ | ||
| 486 | if (!of_machine_is_compatible("PowerMac7,2")) | ||
| 487 | return; | ||
| 488 | |||
| 489 | wf_fcu_add_fan(pv, "backside-fan", FCU_FAN_PWM, 1); | ||
| 490 | wf_fcu_add_fan(pv, "drive-bay-fan", FCU_FAN_RPM, 2); | ||
| 491 | wf_fcu_add_fan(pv, "slots-fan", FCU_FAN_PWM, 2); | ||
| 492 | wf_fcu_add_fan(pv, "cpu-front-fan-0", FCU_FAN_RPM, 3); | ||
| 493 | wf_fcu_add_fan(pv, "cpu-rear-fan-0", FCU_FAN_RPM, 4); | ||
| 494 | wf_fcu_add_fan(pv, "cpu-front-fan-1", FCU_FAN_RPM, 5); | ||
| 495 | wf_fcu_add_fan(pv, "cpu-rear-fan-1", FCU_FAN_RPM, 6); | ||
| 496 | } | ||
| 497 | |||
| 498 | static int wf_fcu_init_chip(struct wf_fcu_priv *pv) | ||
| 499 | { | ||
| 500 | unsigned char buf = 0xff; | ||
| 501 | int rc; | ||
| 502 | |||
| 503 | rc = wf_fcu_write_reg(pv, 0xe, &buf, 1); | ||
| 504 | if (rc < 0) | ||
| 505 | return -EIO; | ||
| 506 | rc = wf_fcu_write_reg(pv, 0x2e, &buf, 1); | ||
| 507 | if (rc < 0) | ||
| 508 | return -EIO; | ||
| 509 | rc = wf_fcu_read_reg(pv, 0, &buf, 1); | ||
| 510 | if (rc < 0) | ||
| 511 | return -EIO; | ||
| 512 | pv->rpm_shift = (buf == 1) ? 2 : 3; | ||
| 513 | |||
| 514 | pr_debug("wf_fcu: FCU Initialized, RPM fan shift is %d\n", | ||
| 515 | pv->rpm_shift); | ||
| 516 | |||
| 517 | return 0; | ||
| 518 | } | ||
| 519 | |||
| 520 | static int wf_fcu_probe(struct i2c_client *client, | ||
| 521 | const struct i2c_device_id *id) | ||
| 522 | { | ||
| 523 | struct wf_fcu_priv *pv; | ||
| 524 | |||
| 525 | pv = kzalloc(sizeof(*pv), GFP_KERNEL); | ||
| 526 | if (!pv) | ||
| 527 | return -ENOMEM; | ||
| 528 | |||
| 529 | kref_init(&pv->ref); | ||
| 530 | mutex_init(&pv->lock); | ||
| 531 | INIT_LIST_HEAD(&pv->fan_list); | ||
| 532 | pv->i2c = client; | ||
| 533 | |||
| 534 | /* | ||
| 535 | * First we must start the FCU which will query the | ||
| 536 | * shift value to apply to RPMs | ||
| 537 | */ | ||
| 538 | if (wf_fcu_init_chip(pv)) { | ||
| 539 | pr_err("wf_fcu: Initialization failed !\n"); | ||
| 540 | kfree(pv); | ||
| 541 | return -ENXIO; | ||
| 542 | } | ||
| 543 | |||
| 544 | /* First lookup fans in the device-tree */ | ||
| 545 | wf_fcu_lookup_fans(pv); | ||
| 546 | |||
| 547 | /* | ||
| 548 | * Older machines don't have the device-tree entries | ||
| 549 | * we are looking for, just hard code the list | ||
| 550 | */ | ||
| 551 | if (list_empty(&pv->fan_list)) | ||
| 552 | wf_fcu_default_fans(pv); | ||
| 553 | |||
| 554 | /* Still no fans ? FAIL */ | ||
| 555 | if (list_empty(&pv->fan_list)) { | ||
| 556 | pr_err("wf_fcu: Failed to find fans for your machine\n"); | ||
| 557 | kfree(pv); | ||
| 558 | return -ENODEV; | ||
| 559 | } | ||
| 560 | |||
| 561 | dev_set_drvdata(&client->dev, pv); | ||
| 562 | |||
| 563 | return 0; | ||
| 564 | } | ||
| 565 | |||
| 566 | static int wf_fcu_remove(struct i2c_client *client) | ||
| 567 | { | ||
| 568 | struct wf_fcu_priv *pv = dev_get_drvdata(&client->dev); | ||
| 569 | struct wf_fcu_fan *fan; | ||
| 570 | |||
| 571 | while (!list_empty(&pv->fan_list)) { | ||
| 572 | fan = list_first_entry(&pv->fan_list, struct wf_fcu_fan, link); | ||
| 573 | list_del(&fan->link); | ||
| 574 | wf_unregister_control(&fan->ctrl); | ||
| 575 | } | ||
| 576 | kref_put(&pv->ref, wf_fcu_release); | ||
| 577 | return 0; | ||
| 578 | } | ||
| 579 | |||
| 580 | static const struct i2c_device_id wf_fcu_id[] = { | ||
| 581 | { "MAC,fcu", 0 }, | ||
| 582 | { } | ||
| 583 | }; | ||
| 584 | MODULE_DEVICE_TABLE(i2c, wf_fcu_id); | ||
| 585 | |||
| 586 | static struct i2c_driver wf_fcu_driver = { | ||
| 587 | .driver = { | ||
| 588 | .name = "wf_fcu", | ||
| 589 | }, | ||
| 590 | .probe = wf_fcu_probe, | ||
| 591 | .remove = wf_fcu_remove, | ||
| 592 | .id_table = wf_fcu_id, | ||
| 593 | }; | ||
| 594 | |||
| 595 | module_i2c_driver(wf_fcu_driver); | ||
| 596 | |||
| 597 | MODULE_AUTHOR("Benjamin Herrenschmidt <benh@kernel.crashing.org>"); | ||
| 598 | MODULE_DESCRIPTION("FCU control objects for PowerMacs thermal control"); | ||
| 599 | MODULE_LICENSE("GPL"); | ||
| 600 | |||
diff --git a/drivers/macintosh/windfarm_lm75_sensor.c b/drivers/macintosh/windfarm_lm75_sensor.c index 9ef32b3df91..647c6add219 100644 --- a/drivers/macintosh/windfarm_lm75_sensor.c +++ b/drivers/macintosh/windfarm_lm75_sensor.c | |||
| @@ -18,12 +18,13 @@ | |||
| 18 | #include <asm/prom.h> | 18 | #include <asm/prom.h> |
| 19 | #include <asm/machdep.h> | 19 | #include <asm/machdep.h> |
| 20 | #include <asm/io.h> | 20 | #include <asm/io.h> |
| 21 | #include <asm/system.h> | ||
| 21 | #include <asm/sections.h> | 22 | #include <asm/sections.h> |
| 22 | #include <asm/pmac_low_i2c.h> | 23 | #include <asm/pmac_low_i2c.h> |
| 23 | 24 | ||
| 24 | #include "windfarm.h" | 25 | #include "windfarm.h" |
| 25 | 26 | ||
| 26 | #define VERSION "1.0" | 27 | #define VERSION "0.2" |
| 27 | 28 | ||
| 28 | #undef DEBUG | 29 | #undef DEBUG |
| 29 | 30 | ||
| @@ -36,8 +37,8 @@ | |||
| 36 | struct wf_lm75_sensor { | 37 | struct wf_lm75_sensor { |
| 37 | int ds1775 : 1; | 38 | int ds1775 : 1; |
| 38 | int inited : 1; | 39 | int inited : 1; |
| 39 | struct i2c_client *i2c; | 40 | struct i2c_client *i2c; |
| 40 | struct wf_sensor sens; | 41 | struct wf_sensor sens; |
| 41 | }; | 42 | }; |
| 42 | #define wf_to_lm75(c) container_of(c, struct wf_lm75_sensor, sens) | 43 | #define wf_to_lm75(c) container_of(c, struct wf_lm75_sensor, sens) |
| 43 | 44 | ||
| @@ -90,19 +91,40 @@ static struct wf_sensor_ops wf_lm75_ops = { | |||
| 90 | 91 | ||
| 91 | static int wf_lm75_probe(struct i2c_client *client, | 92 | static int wf_lm75_probe(struct i2c_client *client, |
| 92 | const struct i2c_device_id *id) | 93 | const struct i2c_device_id *id) |
| 93 | { | 94 | { |
| 94 | struct wf_lm75_sensor *lm; | 95 | struct wf_lm75_sensor *lm; |
| 95 | int rc, ds1775 = id->driver_data; | 96 | int rc; |
| 96 | const char *name, *loc; | ||
| 97 | 97 | ||
| 98 | DBG("wf_lm75: creating %s device at address 0x%02x\n", | 98 | lm = kzalloc(sizeof(struct wf_lm75_sensor), GFP_KERNEL); |
| 99 | ds1775 ? "ds1775" : "lm75", client->addr); | 99 | if (lm == NULL) |
| 100 | return -ENODEV; | ||
| 100 | 101 | ||
| 101 | loc = of_get_property(client->dev.of_node, "hwsensor-location", NULL); | 102 | lm->inited = 0; |
| 102 | if (!loc) { | 103 | lm->ds1775 = id->driver_data; |
| 103 | dev_warn(&client->dev, "Missing hwsensor-location property!\n"); | 104 | lm->i2c = client; |
| 104 | return -ENXIO; | 105 | lm->sens.name = client->dev.platform_data; |
| 105 | } | 106 | lm->sens.ops = &wf_lm75_ops; |
| 107 | i2c_set_clientdata(client, lm); | ||
| 108 | |||
| 109 | rc = wf_register_sensor(&lm->sens); | ||
| 110 | if (rc) | ||
| 111 | kfree(lm); | ||
| 112 | |||
| 113 | return rc; | ||
| 114 | } | ||
| 115 | |||
| 116 | static struct i2c_driver wf_lm75_driver; | ||
| 117 | |||
| 118 | static struct i2c_client *wf_lm75_create(struct i2c_adapter *adapter, | ||
| 119 | u8 addr, int ds1775, | ||
| 120 | const char *loc) | ||
| 121 | { | ||
| 122 | struct i2c_board_info info; | ||
| 123 | struct i2c_client *client; | ||
| 124 | char *name; | ||
| 125 | |||
| 126 | DBG("wf_lm75: creating %s device at address 0x%02x\n", | ||
| 127 | ds1775 ? "ds1775" : "lm75", addr); | ||
| 106 | 128 | ||
| 107 | /* Usual rant about sensor names not beeing very consistent in | 129 | /* Usual rant about sensor names not beeing very consistent in |
| 108 | * the device-tree, oh well ... | 130 | * the device-tree, oh well ... |
| @@ -116,31 +138,68 @@ static int wf_lm75_probe(struct i2c_client *client, | |||
| 116 | name = "optical-drive-temp"; | 138 | name = "optical-drive-temp"; |
| 117 | else if (!strcmp(loc, "HD Temp")) | 139 | else if (!strcmp(loc, "HD Temp")) |
| 118 | name = "hard-drive-temp"; | 140 | name = "hard-drive-temp"; |
| 119 | else if (!strcmp(loc, "PCI SLOTS")) | ||
| 120 | name = "slots-temp"; | ||
| 121 | else if (!strcmp(loc, "CPU A INLET")) | ||
| 122 | name = "cpu-inlet-temp-0"; | ||
| 123 | else if (!strcmp(loc, "CPU B INLET")) | ||
| 124 | name = "cpu-inlet-temp-1"; | ||
| 125 | else | 141 | else |
| 126 | return -ENXIO; | 142 | goto fail; |
| 127 | 143 | ||
| 144 | memset(&info, 0, sizeof(struct i2c_board_info)); | ||
| 145 | info.addr = (addr >> 1) & 0x7f; | ||
| 146 | info.platform_data = name; | ||
| 147 | strlcpy(info.type, ds1775 ? "wf_ds1775" : "wf_lm75", I2C_NAME_SIZE); | ||
| 148 | |||
| 149 | client = i2c_new_device(adapter, &info); | ||
| 150 | if (client == NULL) { | ||
| 151 | printk(KERN_ERR "windfarm: failed to attach %s %s to i2c\n", | ||
| 152 | ds1775 ? "ds1775" : "lm75", name); | ||
| 153 | goto fail; | ||
| 154 | } | ||
| 128 | 155 | ||
| 129 | lm = kzalloc(sizeof(struct wf_lm75_sensor), GFP_KERNEL); | 156 | /* |
| 130 | if (lm == NULL) | 157 | * Let i2c-core delete that device on driver removal. |
| 158 | * This is safe because i2c-core holds the core_lock mutex for us. | ||
| 159 | */ | ||
| 160 | list_add_tail(&client->detected, &wf_lm75_driver.clients); | ||
| 161 | return client; | ||
| 162 | fail: | ||
| 163 | return NULL; | ||
| 164 | } | ||
| 165 | |||
| 166 | static int wf_lm75_attach(struct i2c_adapter *adapter) | ||
| 167 | { | ||
| 168 | struct device_node *busnode, *dev; | ||
| 169 | struct pmac_i2c_bus *bus; | ||
| 170 | |||
| 171 | DBG("wf_lm75: adapter %s detected\n", adapter->name); | ||
| 172 | |||
| 173 | bus = pmac_i2c_adapter_to_bus(adapter); | ||
| 174 | if (bus == NULL) | ||
| 131 | return -ENODEV; | 175 | return -ENODEV; |
| 176 | busnode = pmac_i2c_get_bus_node(bus); | ||
| 132 | 177 | ||
| 133 | lm->inited = 0; | 178 | DBG("wf_lm75: bus found, looking for device...\n"); |
| 134 | lm->ds1775 = ds1775; | ||
| 135 | lm->i2c = client; | ||
| 136 | lm->sens.name = (char *)name; /* XXX fix constness in structure */ | ||
| 137 | lm->sens.ops = &wf_lm75_ops; | ||
| 138 | i2c_set_clientdata(client, lm); | ||
| 139 | 179 | ||
| 140 | rc = wf_register_sensor(&lm->sens); | 180 | /* Now look for lm75(s) in there */ |
| 141 | if (rc) | 181 | for (dev = NULL; |
| 142 | kfree(lm); | 182 | (dev = of_get_next_child(busnode, dev)) != NULL;) { |
| 143 | return rc; | 183 | const char *loc = |
| 184 | of_get_property(dev, "hwsensor-location", NULL); | ||
| 185 | u8 addr; | ||
| 186 | |||
| 187 | /* We must re-match the adapter in order to properly check | ||
| 188 | * the channel on multibus setups | ||
| 189 | */ | ||
| 190 | if (!pmac_i2c_match_adapter(dev, adapter)) | ||
| 191 | continue; | ||
| 192 | addr = pmac_i2c_get_dev_addr(dev); | ||
| 193 | if (loc == NULL || addr == 0) | ||
| 194 | continue; | ||
| 195 | /* real lm75 */ | ||
| 196 | if (of_device_is_compatible(dev, "lm75")) | ||
| 197 | wf_lm75_create(adapter, addr, 0, loc); | ||
| 198 | /* ds1775 (compatible, better resolution */ | ||
| 199 | else if (of_device_is_compatible(dev, "ds1775")) | ||
| 200 | wf_lm75_create(adapter, addr, 1, loc); | ||
| 201 | } | ||
| 202 | return 0; | ||
| 144 | } | 203 | } |
| 145 | 204 | ||
| 146 | static int wf_lm75_remove(struct i2c_client *client) | 205 | static int wf_lm75_remove(struct i2c_client *client) |
| @@ -159,22 +218,39 @@ static int wf_lm75_remove(struct i2c_client *client) | |||
| 159 | } | 218 | } |
| 160 | 219 | ||
| 161 | static const struct i2c_device_id wf_lm75_id[] = { | 220 | static const struct i2c_device_id wf_lm75_id[] = { |
| 162 | { "MAC,lm75", 0 }, | 221 | { "wf_lm75", 0 }, |
| 163 | { "MAC,ds1775", 1 }, | 222 | { "wf_ds1775", 1 }, |
| 164 | { } | 223 | { } |
| 165 | }; | 224 | }; |
| 166 | MODULE_DEVICE_TABLE(i2c, wf_lm75_id); | ||
| 167 | 225 | ||
| 168 | static struct i2c_driver wf_lm75_driver = { | 226 | static struct i2c_driver wf_lm75_driver = { |
| 169 | .driver = { | 227 | .driver = { |
| 170 | .name = "wf_lm75", | 228 | .name = "wf_lm75", |
| 171 | }, | 229 | }, |
| 230 | .attach_adapter = wf_lm75_attach, | ||
| 172 | .probe = wf_lm75_probe, | 231 | .probe = wf_lm75_probe, |
| 173 | .remove = wf_lm75_remove, | 232 | .remove = wf_lm75_remove, |
| 174 | .id_table = wf_lm75_id, | 233 | .id_table = wf_lm75_id, |
| 175 | }; | 234 | }; |
| 176 | 235 | ||
| 177 | module_i2c_driver(wf_lm75_driver); | 236 | static int __init wf_lm75_sensor_init(void) |
| 237 | { | ||
| 238 | /* Don't register on old machines that use therm_pm72 for now */ | ||
| 239 | if (of_machine_is_compatible("PowerMac7,2") || | ||
| 240 | of_machine_is_compatible("PowerMac7,3") || | ||
| 241 | of_machine_is_compatible("RackMac3,1")) | ||
| 242 | return -ENODEV; | ||
| 243 | return i2c_add_driver(&wf_lm75_driver); | ||
| 244 | } | ||
| 245 | |||
| 246 | static void __exit wf_lm75_sensor_exit(void) | ||
| 247 | { | ||
| 248 | i2c_del_driver(&wf_lm75_driver); | ||
| 249 | } | ||
| 250 | |||
| 251 | |||
| 252 | module_init(wf_lm75_sensor_init); | ||
| 253 | module_exit(wf_lm75_sensor_exit); | ||
| 178 | 254 | ||
| 179 | MODULE_AUTHOR("Benjamin Herrenschmidt <benh@kernel.crashing.org>"); | 255 | MODULE_AUTHOR("Benjamin Herrenschmidt <benh@kernel.crashing.org>"); |
| 180 | MODULE_DESCRIPTION("LM75 sensor objects for PowerMacs thermal control"); | 256 | MODULE_DESCRIPTION("LM75 sensor objects for PowerMacs thermal control"); |
diff --git a/drivers/macintosh/windfarm_lm87_sensor.c b/drivers/macintosh/windfarm_lm87_sensor.c deleted file mode 100644 index c071aab79dd..00000000000 --- a/drivers/macintosh/windfarm_lm87_sensor.c +++ /dev/null | |||
| @@ -1,201 +0,0 @@ | |||
| 1 | /* | ||
| 2 | * Windfarm PowerMac thermal control. LM87 sensor | ||
| 3 | * | ||
| 4 | * Copyright 2012 Benjamin Herrenschmidt, IBM Corp. | ||
| 5 | * | ||
| 6 | * Released under the term of the GNU GPL v2. | ||
| 7 | * | ||
| 8 | */ | ||
| 9 | |||
| 10 | #include <linux/types.h> | ||
| 11 | #include <linux/errno.h> | ||
| 12 | #include <linux/kernel.h> | ||
| 13 | #include <linux/delay.h> | ||
| 14 | #include <linux/slab.h> | ||
| 15 | #include <linux/init.h> | ||
| 16 | #include <linux/wait.h> | ||
| 17 | #include <linux/i2c.h> | ||
| 18 | #include <asm/prom.h> | ||
| 19 | #include <asm/machdep.h> | ||
| 20 | #include <asm/io.h> | ||
| 21 | #include <asm/sections.h> | ||
| 22 | #include <asm/pmac_low_i2c.h> | ||
| 23 | |||
| 24 | #include "windfarm.h" | ||
| 25 | |||
| 26 | #define VERSION "1.0" | ||
| 27 | |||
| 28 | #undef DEBUG | ||
| 29 | |||
| 30 | #ifdef DEBUG | ||
| 31 | #define DBG(args...) printk(args) | ||
| 32 | #else | ||
| 33 | #define DBG(args...) do { } while(0) | ||
| 34 | #endif | ||
| 35 | |||
| 36 | struct wf_lm87_sensor { | ||
| 37 | struct i2c_client *i2c; | ||
| 38 | struct wf_sensor sens; | ||
| 39 | }; | ||
| 40 | #define wf_to_lm87(c) container_of(c, struct wf_lm87_sensor, sens) | ||
| 41 | |||
| 42 | |||
| 43 | static int wf_lm87_read_reg(struct i2c_client *chip, int reg) | ||
| 44 | { | ||
| 45 | int rc, tries = 0; | ||
| 46 | u8 buf; | ||
| 47 | |||
| 48 | for (;;) { | ||
| 49 | /* Set address */ | ||
| 50 | buf = (u8)reg; | ||
| 51 | rc = i2c_master_send(chip, &buf, 1); | ||
| 52 | if (rc <= 0) | ||
| 53 | goto error; | ||
| 54 | rc = i2c_master_recv(chip, &buf, 1); | ||
| 55 | if (rc <= 0) | ||
| 56 | goto error; | ||
| 57 | return (int)buf; | ||
| 58 | error: | ||
| 59 | DBG("wf_lm87: Error reading LM87, retrying...\n"); | ||
| 60 | if (++tries > 10) { | ||
| 61 | printk(KERN_ERR "wf_lm87: Error reading LM87 !\n"); | ||
| 62 | return -EIO; | ||
| 63 | } | ||
| 64 | msleep(10); | ||
| 65 | } | ||
| 66 | } | ||
| 67 | |||
| 68 | static int wf_lm87_get(struct wf_sensor *sr, s32 *value) | ||
| 69 | { | ||
| 70 | struct wf_lm87_sensor *lm = sr->priv; | ||
| 71 | s32 temp; | ||
| 72 | |||
| 73 | if (lm->i2c == NULL) | ||
| 74 | return -ENODEV; | ||
| 75 | |||
| 76 | #define LM87_INT_TEMP 0x27 | ||
| 77 | |||
| 78 | /* Read temperature register */ | ||
| 79 | temp = wf_lm87_read_reg(lm->i2c, LM87_INT_TEMP); | ||
| 80 | if (temp < 0) | ||
| 81 | return temp; | ||
| 82 | *value = temp << 16; | ||
| 83 | |||
| 84 | return 0; | ||
| 85 | } | ||
| 86 | |||
| 87 | static void wf_lm87_release(struct wf_sensor *sr) | ||
| 88 | { | ||
| 89 | struct wf_lm87_sensor *lm = wf_to_lm87(sr); | ||
| 90 | |||
| 91 | kfree(lm); | ||
| 92 | } | ||
| 93 | |||
| 94 | static struct wf_sensor_ops wf_lm87_ops = { | ||
| 95 | .get_value = wf_lm87_get, | ||
| 96 | .release = wf_lm87_release, | ||
| 97 | .owner = THIS_MODULE, | ||
| 98 | }; | ||
| 99 | |||
| 100 | static int wf_lm87_probe(struct i2c_client *client, | ||
| 101 | const struct i2c_device_id *id) | ||
| 102 | { | ||
| 103 | struct wf_lm87_sensor *lm; | ||
| 104 | const char *name = NULL, *loc; | ||
| 105 | struct device_node *np = NULL; | ||
| 106 | int rc; | ||
| 107 | |||
| 108 | /* | ||
| 109 | * The lm87 contains a whole pile of sensors, additionally, | ||
| 110 | * the Xserve G5 has several lm87's. However, for now we only | ||
| 111 | * care about the internal temperature sensor | ||
| 112 | */ | ||
| 113 | while ((np = of_get_next_child(client->dev.of_node, np)) != NULL) { | ||
| 114 | if (strcmp(np->name, "int-temp")) | ||
| 115 | continue; | ||
| 116 | loc = of_get_property(np, "location", NULL); | ||
| 117 | if (!loc) | ||
| 118 | continue; | ||
| 119 | if (strstr(loc, "DIMM")) | ||
| 120 | name = "dimms-temp"; | ||
| 121 | else if (strstr(loc, "Processors")) | ||
| 122 | name = "between-cpus-temp"; | ||
| 123 | if (name) { | ||
| 124 | of_node_put(np); | ||
| 125 | break; | ||
| 126 | } | ||
| 127 | } | ||
| 128 | if (!name) { | ||
| 129 | pr_warning("wf_lm87: Unsupported sensor %s\n", | ||
| 130 | client->dev.of_node->full_name); | ||
| 131 | return -ENODEV; | ||
| 132 | } | ||
| 133 | |||
| 134 | lm = kzalloc(sizeof(struct wf_lm87_sensor), GFP_KERNEL); | ||
| 135 | if (lm == NULL) | ||
| 136 | return -ENODEV; | ||
| 137 | |||
| 138 | lm->i2c = client; | ||
| 139 | lm->sens.name = name; | ||
| 140 | lm->sens.ops = &wf_lm87_ops; | ||
| 141 | lm->sens.priv = lm; | ||
| 142 | i2c_set_clientdata(client, lm); | ||
| 143 | |||
| 144 | rc = wf_register_sensor(&lm->sens); | ||
| 145 | if (rc) | ||
| 146 | kfree(lm); | ||
| 147 | return rc; | ||
| 148 | } | ||
| 149 | |||
| 150 | static int wf_lm87_remove(struct i2c_client *client) | ||
| 151 | { | ||
| 152 | struct wf_lm87_sensor *lm = i2c_get_clientdata(client); | ||
| 153 | |||
| 154 | DBG("wf_lm87: i2c detatch called for %s\n", lm->sens.name); | ||
| 155 | |||
| 156 | /* Mark client detached */ | ||
| 157 | lm->i2c = NULL; | ||
| 158 | |||
| 159 | /* release sensor */ | ||
| 160 | wf_unregister_sensor(&lm->sens); | ||
| 161 | |||
| 162 | return 0; | ||
| 163 | } | ||
| 164 | |||
| 165 | static const struct i2c_device_id wf_lm87_id[] = { | ||
| 166 | { "MAC,lm87cimt", 0 }, | ||
| 167 | { } | ||
| 168 | }; | ||
| 169 | MODULE_DEVICE_TABLE(i2c, wf_lm87_id); | ||
| 170 | |||
| 171 | static struct i2c_driver wf_lm87_driver = { | ||
| 172 | .driver = { | ||
| 173 | .name = "wf_lm87", | ||
| 174 | }, | ||
| 175 | .probe = wf_lm87_probe, | ||
| 176 | .remove = wf_lm87_remove, | ||
| 177 | .id_table = wf_lm87_id, | ||
| 178 | }; | ||
| 179 | |||
| 180 | static int __init wf_lm87_sensor_init(void) | ||
| 181 | { | ||
| 182 | /* We only support this on the Xserve */ | ||
| 183 | if (!of_machine_is_compatible("RackMac3,1")) | ||
| 184 | return -ENODEV; | ||
| 185 | |||
| 186 | return i2c_add_driver(&wf_lm87_driver); | ||
| 187 | } | ||
| 188 | |||
| 189 | static void __exit wf_lm87_sensor_exit(void) | ||
| 190 | { | ||
| 191 | i2c_del_driver(&wf_lm87_driver); | ||
| 192 | } | ||
| 193 | |||
| 194 | |||
| 195 | module_init(wf_lm87_sensor_init); | ||
| 196 | module_exit(wf_lm87_sensor_exit); | ||
| 197 | |||
| 198 | MODULE_AUTHOR("Benjamin Herrenschmidt <benh@kernel.crashing.org>"); | ||
| 199 | MODULE_DESCRIPTION("LM87 sensor objects for PowerMacs thermal control"); | ||
| 200 | MODULE_LICENSE("GPL"); | ||
| 201 | |||
diff --git a/drivers/macintosh/windfarm_max6690_sensor.c b/drivers/macintosh/windfarm_max6690_sensor.c index 945a25b2f31..8204113268f 100644 --- a/drivers/macintosh/windfarm_max6690_sensor.c +++ b/drivers/macintosh/windfarm_max6690_sensor.c | |||
| @@ -16,7 +16,7 @@ | |||
| 16 | 16 | ||
| 17 | #include "windfarm.h" | 17 | #include "windfarm.h" |
| 18 | 18 | ||
| 19 | #define VERSION "1.0" | 19 | #define VERSION "0.2" |
| 20 | 20 | ||
| 21 | /* This currently only exports the external temperature sensor, | 21 | /* This currently only exports the external temperature sensor, |
| 22 | since that's all the control loops need. */ | 22 | since that's all the control loops need. */ |
| @@ -64,29 +64,9 @@ static struct wf_sensor_ops wf_max6690_ops = { | |||
| 64 | static int wf_max6690_probe(struct i2c_client *client, | 64 | static int wf_max6690_probe(struct i2c_client *client, |
| 65 | const struct i2c_device_id *id) | 65 | const struct i2c_device_id *id) |
| 66 | { | 66 | { |
| 67 | const char *name, *loc; | ||
| 68 | struct wf_6690_sensor *max; | 67 | struct wf_6690_sensor *max; |
| 69 | int rc; | 68 | int rc; |
| 70 | 69 | ||
| 71 | loc = of_get_property(client->dev.of_node, "hwsensor-location", NULL); | ||
| 72 | if (!loc) { | ||
| 73 | dev_warn(&client->dev, "Missing hwsensor-location property!\n"); | ||
| 74 | return -ENXIO; | ||
| 75 | } | ||
| 76 | |||
| 77 | /* | ||
| 78 | * We only expose the external temperature register for | ||
| 79 | * now as this is all we need for our control loops | ||
| 80 | */ | ||
| 81 | if (!strcmp(loc, "BACKSIDE") || !strcmp(loc, "SYS CTRLR AMBIENT")) | ||
| 82 | name = "backside-temp"; | ||
| 83 | else if (!strcmp(loc, "NB Ambient")) | ||
| 84 | name = "north-bridge-temp"; | ||
| 85 | else if (!strcmp(loc, "GPU Ambient")) | ||
| 86 | name = "gpu-temp"; | ||
| 87 | else | ||
| 88 | return -ENXIO; | ||
| 89 | |||
| 90 | max = kzalloc(sizeof(struct wf_6690_sensor), GFP_KERNEL); | 70 | max = kzalloc(sizeof(struct wf_6690_sensor), GFP_KERNEL); |
| 91 | if (max == NULL) { | 71 | if (max == NULL) { |
| 92 | printk(KERN_ERR "windfarm: Couldn't create MAX6690 sensor: " | 72 | printk(KERN_ERR "windfarm: Couldn't create MAX6690 sensor: " |
| @@ -95,16 +75,90 @@ static int wf_max6690_probe(struct i2c_client *client, | |||
| 95 | } | 75 | } |
| 96 | 76 | ||
| 97 | max->i2c = client; | 77 | max->i2c = client; |
| 98 | max->sens.name = (char *)name; /* XXX fix constness in structure */ | 78 | max->sens.name = client->dev.platform_data; |
| 99 | max->sens.ops = &wf_max6690_ops; | 79 | max->sens.ops = &wf_max6690_ops; |
| 100 | i2c_set_clientdata(client, max); | 80 | i2c_set_clientdata(client, max); |
| 101 | 81 | ||
| 102 | rc = wf_register_sensor(&max->sens); | 82 | rc = wf_register_sensor(&max->sens); |
| 103 | if (rc) | 83 | if (rc) { |
| 104 | kfree(max); | 84 | kfree(max); |
| 85 | } | ||
| 86 | |||
| 105 | return rc; | 87 | return rc; |
| 106 | } | 88 | } |
| 107 | 89 | ||
| 90 | static struct i2c_driver wf_max6690_driver; | ||
| 91 | |||
| 92 | static struct i2c_client *wf_max6690_create(struct i2c_adapter *adapter, | ||
| 93 | u8 addr, const char *loc) | ||
| 94 | { | ||
| 95 | struct i2c_board_info info; | ||
| 96 | struct i2c_client *client; | ||
| 97 | char *name; | ||
| 98 | |||
| 99 | if (!strcmp(loc, "BACKSIDE")) | ||
| 100 | name = "backside-temp"; | ||
| 101 | else if (!strcmp(loc, "NB Ambient")) | ||
| 102 | name = "north-bridge-temp"; | ||
| 103 | else if (!strcmp(loc, "GPU Ambient")) | ||
| 104 | name = "gpu-temp"; | ||
| 105 | else | ||
| 106 | goto fail; | ||
| 107 | |||
| 108 | memset(&info, 0, sizeof(struct i2c_board_info)); | ||
| 109 | info.addr = addr >> 1; | ||
| 110 | info.platform_data = name; | ||
| 111 | strlcpy(info.type, "wf_max6690", I2C_NAME_SIZE); | ||
| 112 | |||
| 113 | client = i2c_new_device(adapter, &info); | ||
| 114 | if (client == NULL) { | ||
| 115 | printk(KERN_ERR "windfarm: failed to attach MAX6690 sensor\n"); | ||
| 116 | goto fail; | ||
| 117 | } | ||
| 118 | |||
| 119 | /* | ||
| 120 | * Let i2c-core delete that device on driver removal. | ||
| 121 | * This is safe because i2c-core holds the core_lock mutex for us. | ||
| 122 | */ | ||
| 123 | list_add_tail(&client->detected, &wf_max6690_driver.clients); | ||
| 124 | return client; | ||
| 125 | |||
| 126 | fail: | ||
| 127 | return NULL; | ||
| 128 | } | ||
| 129 | |||
| 130 | static int wf_max6690_attach(struct i2c_adapter *adapter) | ||
| 131 | { | ||
| 132 | struct device_node *busnode, *dev = NULL; | ||
| 133 | struct pmac_i2c_bus *bus; | ||
| 134 | const char *loc; | ||
| 135 | |||
| 136 | bus = pmac_i2c_adapter_to_bus(adapter); | ||
| 137 | if (bus == NULL) | ||
| 138 | return -ENODEV; | ||
| 139 | busnode = pmac_i2c_get_bus_node(bus); | ||
| 140 | |||
| 141 | while ((dev = of_get_next_child(busnode, dev)) != NULL) { | ||
| 142 | u8 addr; | ||
| 143 | |||
| 144 | /* We must re-match the adapter in order to properly check | ||
| 145 | * the channel on multibus setups | ||
| 146 | */ | ||
| 147 | if (!pmac_i2c_match_adapter(dev, adapter)) | ||
| 148 | continue; | ||
| 149 | if (!of_device_is_compatible(dev, "max6690")) | ||
| 150 | continue; | ||
| 151 | addr = pmac_i2c_get_dev_addr(dev); | ||
| 152 | loc = of_get_property(dev, "hwsensor-location", NULL); | ||
| 153 | if (loc == NULL || addr == 0) | ||
| 154 | continue; | ||
| 155 | printk("found max6690, loc=%s addr=0x%02x\n", loc, addr); | ||
| 156 | wf_max6690_create(adapter, addr, loc); | ||
| 157 | } | ||
| 158 | |||
| 159 | return 0; | ||
| 160 | } | ||
| 161 | |||
| 108 | static int wf_max6690_remove(struct i2c_client *client) | 162 | static int wf_max6690_remove(struct i2c_client *client) |
| 109 | { | 163 | { |
| 110 | struct wf_6690_sensor *max = i2c_get_clientdata(client); | 164 | struct wf_6690_sensor *max = i2c_get_clientdata(client); |
| @@ -116,21 +170,37 @@ static int wf_max6690_remove(struct i2c_client *client) | |||
| 116 | } | 170 | } |
| 117 | 171 | ||
| 118 | static const struct i2c_device_id wf_max6690_id[] = { | 172 | static const struct i2c_device_id wf_max6690_id[] = { |
| 119 | { "MAC,max6690", 0 }, | 173 | { "wf_max6690", 0 }, |
| 120 | { } | 174 | { } |
| 121 | }; | 175 | }; |
| 122 | MODULE_DEVICE_TABLE(i2c, wf_max6690_id); | ||
| 123 | 176 | ||
| 124 | static struct i2c_driver wf_max6690_driver = { | 177 | static struct i2c_driver wf_max6690_driver = { |
| 125 | .driver = { | 178 | .driver = { |
| 126 | .name = "wf_max6690", | 179 | .name = "wf_max6690", |
| 127 | }, | 180 | }, |
| 181 | .attach_adapter = wf_max6690_attach, | ||
| 128 | .probe = wf_max6690_probe, | 182 | .probe = wf_max6690_probe, |
| 129 | .remove = wf_max6690_remove, | 183 | .remove = wf_max6690_remove, |
| 130 | .id_table = wf_max6690_id, | 184 | .id_table = wf_max6690_id, |
| 131 | }; | 185 | }; |
| 132 | 186 | ||
| 133 | module_i2c_driver(wf_max6690_driver); | 187 | static int __init wf_max6690_sensor_init(void) |
| 188 | { | ||
| 189 | /* Don't register on old machines that use therm_pm72 for now */ | ||
| 190 | if (of_machine_is_compatible("PowerMac7,2") || | ||
| 191 | of_machine_is_compatible("PowerMac7,3") || | ||
| 192 | of_machine_is_compatible("RackMac3,1")) | ||
| 193 | return -ENODEV; | ||
| 194 | return i2c_add_driver(&wf_max6690_driver); | ||
| 195 | } | ||
| 196 | |||
| 197 | static void __exit wf_max6690_sensor_exit(void) | ||
| 198 | { | ||
| 199 | i2c_del_driver(&wf_max6690_driver); | ||
| 200 | } | ||
| 201 | |||
| 202 | module_init(wf_max6690_sensor_init); | ||
| 203 | module_exit(wf_max6690_sensor_exit); | ||
| 134 | 204 | ||
| 135 | MODULE_AUTHOR("Paul Mackerras <paulus@samba.org>"); | 205 | MODULE_AUTHOR("Paul Mackerras <paulus@samba.org>"); |
| 136 | MODULE_DESCRIPTION("MAX6690 sensor objects for PowerMac thermal control"); | 206 | MODULE_DESCRIPTION("MAX6690 sensor objects for PowerMac thermal control"); |
diff --git a/drivers/macintosh/windfarm_mpu.h b/drivers/macintosh/windfarm_mpu.h deleted file mode 100644 index 046edc8c2ec..00000000000 --- a/drivers/macintosh/windfarm_mpu.h +++ /dev/null | |||
| @@ -1,105 +0,0 @@ | |||
| 1 | /* | ||
| 2 | * Windfarm PowerMac thermal control | ||
| 3 | * | ||
| 4 | * Copyright 2012 Benjamin Herrenschmidt, IBM Corp. | ||
| 5 | * | ||
| 6 | * Released under the term of the GNU GPL v2. | ||
| 7 | */ | ||
| 8 | |||
| 9 | #ifndef __WINDFARM_MPU_H | ||
| 10 | #define __WINDFARM_MPU_H | ||
| 11 | |||
| 12 | typedef unsigned short fu16; | ||
| 13 | typedef int fs32; | ||
| 14 | typedef short fs16; | ||
| 15 | |||
| 16 | /* Definition of the MPU data structure which contains per CPU | ||
| 17 | * calibration information (among others) for the G5 machines | ||
| 18 | */ | ||
| 19 | struct mpu_data | ||
| 20 | { | ||
| 21 | u8 signature; /* 0x00 - EEPROM sig. */ | ||
| 22 | u8 bytes_used; /* 0x01 - Bytes used in eeprom (160 ?) */ | ||
| 23 | u8 size; /* 0x02 - EEPROM size (256 ?) */ | ||
| 24 | u8 version; /* 0x03 - EEPROM version */ | ||
| 25 | u32 data_revision; /* 0x04 - Dataset revision */ | ||
| 26 | u8 processor_bin_code[3]; /* 0x08 - Processor BIN code */ | ||
| 27 | u8 bin_code_expansion; /* 0x0b - ??? (padding ?) */ | ||
| 28 | u8 processor_num; /* 0x0c - Number of CPUs on this MPU */ | ||
| 29 | u8 input_mul_bus_div; /* 0x0d - Clock input multiplier/bus divider */ | ||
| 30 | u8 reserved1[2]; /* 0x0e - */ | ||
| 31 | u32 input_clk_freq_high; /* 0x10 - Input clock frequency high */ | ||
| 32 | u8 cpu_nb_target_cycles; /* 0x14 - ??? */ | ||
| 33 | u8 cpu_statlat; /* 0x15 - ??? */ | ||
| 34 | u8 cpu_snooplat; /* 0x16 - ??? */ | ||
| 35 | u8 cpu_snoopacc; /* 0x17 - ??? */ | ||
| 36 | u8 nb_paamwin; /* 0x18 - ??? */ | ||
| 37 | u8 nb_statlat; /* 0x19 - ??? */ | ||
| 38 | u8 nb_snooplat; /* 0x1a - ??? */ | ||
| 39 | u8 nb_snoopwin; /* 0x1b - ??? */ | ||
| 40 | u8 api_bus_mode; /* 0x1c - ??? */ | ||
| 41 | u8 reserved2[3]; /* 0x1d - */ | ||
| 42 | u32 input_clk_freq_low; /* 0x20 - Input clock frequency low */ | ||
| 43 | u8 processor_card_slot; /* 0x24 - Processor card slot number */ | ||
| 44 | u8 reserved3[2]; /* 0x25 - */ | ||
| 45 | u8 padjmax; /* 0x27 - Max power adjustment (Not in OF!) */ | ||
| 46 | u8 ttarget; /* 0x28 - Target temperature */ | ||
| 47 | u8 tmax; /* 0x29 - Max temperature */ | ||
| 48 | u8 pmaxh; /* 0x2a - Max power */ | ||
| 49 | u8 tguardband; /* 0x2b - Guardband temp ??? Hist. len in OSX */ | ||
| 50 | fs32 pid_gp; /* 0x2c - PID proportional gain */ | ||
| 51 | fs32 pid_gr; /* 0x30 - PID reset gain */ | ||
| 52 | fs32 pid_gd; /* 0x34 - PID derivative gain */ | ||
| 53 | fu16 voph; /* 0x38 - Vop High */ | ||
| 54 | fu16 vopl; /* 0x3a - Vop Low */ | ||
| 55 | fs16 nactual_die; /* 0x3c - nActual Die */ | ||
| 56 | fs16 nactual_heatsink; /* 0x3e - nActual Heatsink */ | ||
| 57 | fs16 nactual_system; /* 0x40 - nActual System */ | ||
| 58 | u16 calibration_flags; /* 0x42 - Calibration flags */ | ||
| 59 | fu16 mdiode; /* 0x44 - Diode M value (scaling factor) */ | ||
| 60 | fs16 bdiode; /* 0x46 - Diode B value (offset) */ | ||
| 61 | fs32 theta_heat_sink; /* 0x48 - Theta heat sink */ | ||
| 62 | u16 rminn_intake_fan; /* 0x4c - Intake fan min RPM */ | ||
| 63 | u16 rmaxn_intake_fan; /* 0x4e - Intake fan max RPM */ | ||
| 64 | u16 rminn_exhaust_fan; /* 0x50 - Exhaust fan min RPM */ | ||
| 65 | u16 rmaxn_exhaust_fan; /* 0x52 - Exhaust fan max RPM */ | ||
| 66 | u8 processor_part_num[8]; /* 0x54 - Processor part number XX pumps min/max */ | ||
| 67 | u32 processor_lot_num; /* 0x5c - Processor lot number */ | ||
| 68 | u8 orig_card_sernum[0x10]; /* 0x60 - Card original serial number */ | ||
| 69 | u8 curr_card_sernum[0x10]; /* 0x70 - Card current serial number */ | ||
| 70 | u8 mlb_sernum[0x18]; /* 0x80 - MLB serial number */ | ||
| 71 | u32 checksum1; /* 0x98 - */ | ||
| 72 | u32 checksum2; /* 0x9c - */ | ||
| 73 | }; /* Total size = 0xa0 */ | ||
| 74 | |||
| 75 | static inline const struct mpu_data *wf_get_mpu(int cpu) | ||
| 76 | { | ||
| 77 | struct device_node *np; | ||
| 78 | char nodename[64]; | ||
| 79 | const void *data; | ||
| 80 | int len; | ||
| 81 | |||
| 82 | /* | ||
| 83 | * prom.c routine for finding a node by path is a bit brain dead | ||
| 84 | * and requires exact @xxx unit numbers. This is a bit ugly but | ||
| 85 | * will work for these machines | ||
| 86 | */ | ||
| 87 | sprintf(nodename, "/u3@0,f8000000/i2c@f8001000/cpuid@a%d", cpu ? 2 : 0); | ||
| 88 | np = of_find_node_by_path(nodename); | ||
| 89 | if (!np) | ||
| 90 | return NULL; | ||
| 91 | data = of_get_property(np, "cpuid", &len); | ||
| 92 | of_node_put(np); | ||
| 93 | if (!data) | ||
| 94 | return NULL; | ||
| 95 | |||
| 96 | /* | ||
| 97 | * We are naughty, we have dropped the reference to the device | ||
| 98 | * node and still return a pointer to the content. We know we | ||
| 99 | * can do that though as this is only ever called on PowerMac | ||
| 100 | * which cannot remove those nodes | ||
| 101 | */ | ||
| 102 | return data; | ||
| 103 | } | ||
| 104 | |||
| 105 | #endif /* __WINDFARM_MPU_H */ | ||
diff --git a/drivers/macintosh/windfarm_pm112.c b/drivers/macintosh/windfarm_pm112.c index 35ef6e2582b..e0ee80700cd 100644 --- a/drivers/macintosh/windfarm_pm112.c +++ b/drivers/macintosh/windfarm_pm112.c | |||
| @@ -656,7 +656,7 @@ static int wf_pm112_probe(struct platform_device *dev) | |||
| 656 | return 0; | 656 | return 0; |
| 657 | } | 657 | } |
| 658 | 658 | ||
| 659 | static int wf_pm112_remove(struct platform_device *dev) | 659 | static int __devexit wf_pm112_remove(struct platform_device *dev) |
| 660 | { | 660 | { |
| 661 | wf_unregister_client(&pm112_events); | 661 | wf_unregister_client(&pm112_events); |
| 662 | /* should release all sensors and controls */ | 662 | /* should release all sensors and controls */ |
| @@ -665,7 +665,7 @@ static int wf_pm112_remove(struct platform_device *dev) | |||
| 665 | 665 | ||
| 666 | static struct platform_driver wf_pm112_driver = { | 666 | static struct platform_driver wf_pm112_driver = { |
| 667 | .probe = wf_pm112_probe, | 667 | .probe = wf_pm112_probe, |
| 668 | .remove = wf_pm112_remove, | 668 | .remove = __devexit_p(wf_pm112_remove), |
| 669 | .driver = { | 669 | .driver = { |
| 670 | .name = "windfarm", | 670 | .name = "windfarm", |
| 671 | .owner = THIS_MODULE, | 671 | .owner = THIS_MODULE, |
diff --git a/drivers/macintosh/windfarm_pm121.c b/drivers/macintosh/windfarm_pm121.c index af605e915d4..30e6195e19d 100644 --- a/drivers/macintosh/windfarm_pm121.c +++ b/drivers/macintosh/windfarm_pm121.c | |||
| @@ -215,6 +215,7 @@ | |||
| 215 | #include <asm/prom.h> | 215 | #include <asm/prom.h> |
| 216 | #include <asm/machdep.h> | 216 | #include <asm/machdep.h> |
| 217 | #include <asm/io.h> | 217 | #include <asm/io.h> |
| 218 | #include <asm/system.h> | ||
| 218 | #include <asm/sections.h> | 219 | #include <asm/sections.h> |
| 219 | #include <asm/smu.h> | 220 | #include <asm/smu.h> |
| 220 | 221 | ||
| @@ -987,7 +988,7 @@ static int pm121_probe(struct platform_device *ddev) | |||
| 987 | return 0; | 988 | return 0; |
| 988 | } | 989 | } |
| 989 | 990 | ||
| 990 | static int pm121_remove(struct platform_device *ddev) | 991 | static int __devexit pm121_remove(struct platform_device *ddev) |
| 991 | { | 992 | { |
| 992 | wf_unregister_client(&pm121_events); | 993 | wf_unregister_client(&pm121_events); |
| 993 | return 0; | 994 | return 0; |
| @@ -995,7 +996,7 @@ static int pm121_remove(struct platform_device *ddev) | |||
| 995 | 996 | ||
| 996 | static struct platform_driver pm121_driver = { | 997 | static struct platform_driver pm121_driver = { |
| 997 | .probe = pm121_probe, | 998 | .probe = pm121_probe, |
| 998 | .remove = pm121_remove, | 999 | .remove = __devexit_p(pm121_remove), |
| 999 | .driver = { | 1000 | .driver = { |
| 1000 | .name = "windfarm", | 1001 | .name = "windfarm", |
| 1001 | .bus = &platform_bus_type, | 1002 | .bus = &platform_bus_type, |
diff --git a/drivers/macintosh/windfarm_pm72.c b/drivers/macintosh/windfarm_pm72.c deleted file mode 100644 index 6e5585357cd..00000000000 --- a/drivers/macintosh/windfarm_pm72.c +++ /dev/null | |||
| @@ -1,847 +0,0 @@ | |||
| 1 | /* | ||
| 2 | * Windfarm PowerMac thermal control. | ||
| 3 | * Control loops for PowerMac7,2 and 7,3 | ||
| 4 | * | ||
| 5 | * Copyright (C) 2012 Benjamin Herrenschmidt, IBM Corp. | ||
| 6 | * | ||
| 7 | * Use and redistribute under the terms of the GNU GPL v2. | ||
| 8 | */ | ||
| 9 | #include <linux/types.h> | ||
| 10 | #include <linux/errno.h> | ||
| 11 | #include <linux/kernel.h> | ||
| 12 | #include <linux/device.h> | ||
| 13 | #include <linux/platform_device.h> | ||
| 14 | #include <linux/reboot.h> | ||
| 15 | #include <asm/prom.h> | ||
| 16 | #include <asm/smu.h> | ||
| 17 | |||
| 18 | #include "windfarm.h" | ||
| 19 | #include "windfarm_pid.h" | ||
| 20 | #include "windfarm_mpu.h" | ||
| 21 | |||
| 22 | #define VERSION "1.0" | ||
| 23 | |||
| 24 | #undef DEBUG | ||
| 25 | #undef LOTSA_DEBUG | ||
| 26 | |||
| 27 | #ifdef DEBUG | ||
| 28 | #define DBG(args...) printk(args) | ||
| 29 | #else | ||
| 30 | #define DBG(args...) do { } while(0) | ||
| 31 | #endif | ||
| 32 | |||
| 33 | #ifdef LOTSA_DEBUG | ||
| 34 | #define DBG_LOTS(args...) printk(args) | ||
| 35 | #else | ||
| 36 | #define DBG_LOTS(args...) do { } while(0) | ||
| 37 | #endif | ||
| 38 | |||
| 39 | /* define this to force CPU overtemp to 60 degree, useful for testing | ||
| 40 | * the overtemp code | ||
| 41 | */ | ||
| 42 | #undef HACKED_OVERTEMP | ||
| 43 | |||
| 44 | /* We currently only handle 2 chips */ | ||
| 45 | #define NR_CHIPS 2 | ||
| 46 | #define NR_CPU_FANS 3 * NR_CHIPS | ||
| 47 | |||
| 48 | /* Controls and sensors */ | ||
| 49 | static struct wf_sensor *sens_cpu_temp[NR_CHIPS]; | ||
| 50 | static struct wf_sensor *sens_cpu_volts[NR_CHIPS]; | ||
| 51 | static struct wf_sensor *sens_cpu_amps[NR_CHIPS]; | ||
| 52 | static struct wf_sensor *backside_temp; | ||
| 53 | static struct wf_sensor *drives_temp; | ||
| 54 | |||
| 55 | static struct wf_control *cpu_front_fans[NR_CHIPS]; | ||
| 56 | static struct wf_control *cpu_rear_fans[NR_CHIPS]; | ||
| 57 | static struct wf_control *cpu_pumps[NR_CHIPS]; | ||
| 58 | static struct wf_control *backside_fan; | ||
| 59 | static struct wf_control *drives_fan; | ||
| 60 | static struct wf_control *slots_fan; | ||
| 61 | static struct wf_control *cpufreq_clamp; | ||
| 62 | |||
| 63 | /* We keep a temperature history for average calculation of 180s */ | ||
| 64 | #define CPU_TEMP_HIST_SIZE 180 | ||
| 65 | |||
| 66 | /* Fixed speed for slot fan */ | ||
| 67 | #define SLOTS_FAN_DEFAULT_PWM 40 | ||
| 68 | |||
| 69 | /* Scale value for CPU intake fans */ | ||
| 70 | #define CPU_INTAKE_SCALE 0x0000f852 | ||
| 71 | |||
| 72 | /* PID loop state */ | ||
| 73 | static const struct mpu_data *cpu_mpu_data[NR_CHIPS]; | ||
| 74 | static struct wf_cpu_pid_state cpu_pid[NR_CHIPS]; | ||
| 75 | static bool cpu_pid_combined; | ||
| 76 | static u32 cpu_thist[CPU_TEMP_HIST_SIZE]; | ||
| 77 | static int cpu_thist_pt; | ||
| 78 | static s64 cpu_thist_total; | ||
| 79 | static s32 cpu_all_tmax = 100 << 16; | ||
| 80 | static struct wf_pid_state backside_pid; | ||
| 81 | static int backside_tick; | ||
| 82 | static struct wf_pid_state drives_pid; | ||
| 83 | static int drives_tick; | ||
| 84 | |||
| 85 | static int nr_chips; | ||
| 86 | static bool have_all_controls; | ||
| 87 | static bool have_all_sensors; | ||
| 88 | static bool started; | ||
| 89 | |||
| 90 | static int failure_state; | ||
| 91 | #define FAILURE_SENSOR 1 | ||
| 92 | #define FAILURE_FAN 2 | ||
| 93 | #define FAILURE_PERM 4 | ||
| 94 | #define FAILURE_LOW_OVERTEMP 8 | ||
| 95 | #define FAILURE_HIGH_OVERTEMP 16 | ||
| 96 | |||
| 97 | /* Overtemp values */ | ||
| 98 | #define LOW_OVER_AVERAGE 0 | ||
| 99 | #define LOW_OVER_IMMEDIATE (10 << 16) | ||
| 100 | #define LOW_OVER_CLEAR ((-10) << 16) | ||
| 101 | #define HIGH_OVER_IMMEDIATE (14 << 16) | ||
| 102 | #define HIGH_OVER_AVERAGE (10 << 16) | ||
| 103 | #define HIGH_OVER_IMMEDIATE (14 << 16) | ||
| 104 | |||
| 105 | |||
| 106 | static void cpu_max_all_fans(void) | ||
| 107 | { | ||
| 108 | int i; | ||
| 109 | |||
| 110 | /* We max all CPU fans in case of a sensor error. We also do the | ||
| 111 | * cpufreq clamping now, even if it's supposedly done later by the | ||
| 112 | * generic code anyway, we do it earlier here to react faster | ||
| 113 | */ | ||
| 114 | if (cpufreq_clamp) | ||
| 115 | wf_control_set_max(cpufreq_clamp); | ||
| 116 | for (i = 0; i < nr_chips; i++) { | ||
| 117 | if (cpu_front_fans[i]) | ||
| 118 | wf_control_set_max(cpu_front_fans[i]); | ||
| 119 | if (cpu_rear_fans[i]) | ||
| 120 | wf_control_set_max(cpu_rear_fans[i]); | ||
| 121 | if (cpu_pumps[i]) | ||
| 122 | wf_control_set_max(cpu_pumps[i]); | ||
| 123 | } | ||
| 124 | } | ||
| 125 | |||
| 126 | static int cpu_check_overtemp(s32 temp) | ||
| 127 | { | ||
| 128 | int new_state = 0; | ||
| 129 | s32 t_avg, t_old; | ||
| 130 | static bool first = true; | ||
| 131 | |||
| 132 | /* First check for immediate overtemps */ | ||
| 133 | if (temp >= (cpu_all_tmax + LOW_OVER_IMMEDIATE)) { | ||
| 134 | new_state |= FAILURE_LOW_OVERTEMP; | ||
| 135 | if ((failure_state & FAILURE_LOW_OVERTEMP) == 0) | ||
| 136 | printk(KERN_ERR "windfarm: Overtemp due to immediate CPU" | ||
| 137 | " temperature !\n"); | ||
| 138 | } | ||
| 139 | if (temp >= (cpu_all_tmax + HIGH_OVER_IMMEDIATE)) { | ||
| 140 | new_state |= FAILURE_HIGH_OVERTEMP; | ||
| 141 | if ((failure_state & FAILURE_HIGH_OVERTEMP) == 0) | ||
| 142 | printk(KERN_ERR "windfarm: Critical overtemp due to" | ||
| 143 | " immediate CPU temperature !\n"); | ||
| 144 | } | ||
| 145 | |||
| 146 | /* | ||
| 147 | * The first time around, initialize the array with the first | ||
| 148 | * temperature reading | ||
| 149 | */ | ||
| 150 | if (first) { | ||
| 151 | int i; | ||
| 152 | |||
| 153 | cpu_thist_total = 0; | ||
| 154 | for (i = 0; i < CPU_TEMP_HIST_SIZE; i++) { | ||
| 155 | cpu_thist[i] = temp; | ||
| 156 | cpu_thist_total += temp; | ||
| 157 | } | ||
| 158 | first = false; | ||
| 159 | } | ||
| 160 | |||
| 161 | /* | ||
| 162 | * We calculate a history of max temperatures and use that for the | ||
| 163 | * overtemp management | ||
| 164 | */ | ||
| 165 | t_old = cpu_thist[cpu_thist_pt]; | ||
| 166 | cpu_thist[cpu_thist_pt] = temp; | ||
| 167 | cpu_thist_pt = (cpu_thist_pt + 1) % CPU_TEMP_HIST_SIZE; | ||
| 168 | cpu_thist_total -= t_old; | ||
| 169 | cpu_thist_total += temp; | ||
| 170 | t_avg = cpu_thist_total / CPU_TEMP_HIST_SIZE; | ||
| 171 | |||
| 172 | DBG_LOTS(" t_avg = %d.%03d (out: %d.%03d, in: %d.%03d)\n", | ||
| 173 | FIX32TOPRINT(t_avg), FIX32TOPRINT(t_old), FIX32TOPRINT(temp)); | ||
| 174 | |||
| 175 | /* Now check for average overtemps */ | ||
| 176 | if (t_avg >= (cpu_all_tmax + LOW_OVER_AVERAGE)) { | ||
| 177 | new_state |= FAILURE_LOW_OVERTEMP; | ||
| 178 | if ((failure_state & FAILURE_LOW_OVERTEMP) == 0) | ||
| 179 | printk(KERN_ERR "windfarm: Overtemp due to average CPU" | ||
| 180 | " temperature !\n"); | ||
| 181 | } | ||
| 182 | if (t_avg >= (cpu_all_tmax + HIGH_OVER_AVERAGE)) { | ||
| 183 | new_state |= FAILURE_HIGH_OVERTEMP; | ||
| 184 | if ((failure_state & FAILURE_HIGH_OVERTEMP) == 0) | ||
| 185 | printk(KERN_ERR "windfarm: Critical overtemp due to" | ||
| 186 | " average CPU temperature !\n"); | ||
| 187 | } | ||
| 188 | |||
| 189 | /* Now handle overtemp conditions. We don't currently use the windfarm | ||
| 190 | * overtemp handling core as it's not fully suited to the needs of those | ||
| 191 | * new machine. This will be fixed later. | ||
| 192 | */ | ||
| 193 | if (new_state) { | ||
| 194 | /* High overtemp -> immediate shutdown */ | ||
| 195 | if (new_state & FAILURE_HIGH_OVERTEMP) | ||
| 196 | machine_power_off(); | ||
| 197 | if ((failure_state & new_state) != new_state) | ||
| 198 | cpu_max_all_fans(); | ||
| 199 | failure_state |= new_state; | ||
| 200 | } else if ((failure_state & FAILURE_LOW_OVERTEMP) && | ||
| 201 | (temp < (cpu_all_tmax + LOW_OVER_CLEAR))) { | ||
| 202 | printk(KERN_ERR "windfarm: Overtemp condition cleared !\n"); | ||
| 203 | failure_state &= ~FAILURE_LOW_OVERTEMP; | ||
| 204 | } | ||
| 205 | |||
| 206 | return failure_state & (FAILURE_LOW_OVERTEMP | FAILURE_HIGH_OVERTEMP); | ||
| 207 | } | ||
| 208 | |||
| 209 | static int read_one_cpu_vals(int cpu, s32 *temp, s32 *power) | ||
| 210 | { | ||
| 211 | s32 dtemp, volts, amps; | ||
| 212 | int rc; | ||
| 213 | |||
| 214 | /* Get diode temperature */ | ||
| 215 | rc = wf_sensor_get(sens_cpu_temp[cpu], &dtemp); | ||
| 216 | if (rc) { | ||
| 217 | DBG(" CPU%d: temp reading error !\n", cpu); | ||
| 218 | return -EIO; | ||
| 219 | } | ||
| 220 | DBG_LOTS(" CPU%d: temp = %d.%03d\n", cpu, FIX32TOPRINT((dtemp))); | ||
| 221 | *temp = dtemp; | ||
| 222 | |||
| 223 | /* Get voltage */ | ||
| 224 | rc = wf_sensor_get(sens_cpu_volts[cpu], &volts); | ||
| 225 | if (rc) { | ||
| 226 | DBG(" CPU%d, volts reading error !\n", cpu); | ||
| 227 | return -EIO; | ||
| 228 | } | ||
| 229 | DBG_LOTS(" CPU%d: volts = %d.%03d\n", cpu, FIX32TOPRINT((volts))); | ||
| 230 | |||
| 231 | /* Get current */ | ||
| 232 | rc = wf_sensor_get(sens_cpu_amps[cpu], &s); | ||
| 233 | if (rc) { | ||
| 234 | DBG(" CPU%d, current reading error !\n", cpu); | ||
| 235 | return -EIO; | ||
| 236 | } | ||
| 237 | DBG_LOTS(" CPU%d: amps = %d.%03d\n", cpu, FIX32TOPRINT((amps))); | ||
| 238 | |||
| 239 | /* Calculate power */ | ||
| 240 | |||
| 241 | /* Scale voltage and current raw sensor values according to fixed scales | ||
| 242 | * obtained in Darwin and calculate power from I and V | ||
| 243 | */ | ||
| 244 | *power = (((u64)volts) * ((u64)amps)) >> 16; | ||
| 245 | |||
| 246 | DBG_LOTS(" CPU%d: power = %d.%03d\n", cpu, FIX32TOPRINT((*power))); | ||
| 247 | |||
| 248 | return 0; | ||
| 249 | |||
| 250 | } | ||
| 251 | |||
| 252 | static void cpu_fans_tick_split(void) | ||
| 253 | { | ||
| 254 | int err, cpu; | ||
| 255 | s32 intake, temp, power, t_max = 0; | ||
| 256 | |||
| 257 | DBG_LOTS("* cpu fans_tick_split()\n"); | ||
| 258 | |||
| 259 | for (cpu = 0; cpu < nr_chips; ++cpu) { | ||
| 260 | struct wf_cpu_pid_state *sp = &cpu_pid[cpu]; | ||
| 261 | |||
| 262 | /* Read current speed */ | ||
| 263 | wf_control_get(cpu_rear_fans[cpu], &sp->target); | ||
| 264 | |||
| 265 | DBG_LOTS(" CPU%d: cur_target = %d RPM\n", cpu, sp->target); | ||
| 266 | |||
| 267 | err = read_one_cpu_vals(cpu, &temp, &power); | ||
| 268 | if (err) { | ||
| 269 | failure_state |= FAILURE_SENSOR; | ||
| 270 | cpu_max_all_fans(); | ||
| 271 | return; | ||
| 272 | } | ||
| 273 | |||
| 274 | /* Keep track of highest temp */ | ||
| 275 | t_max = max(t_max, temp); | ||
| 276 | |||
| 277 | /* Handle possible overtemps */ | ||
| 278 | if (cpu_check_overtemp(t_max)) | ||
| 279 | return; | ||
| 280 | |||
| 281 | /* Run PID */ | ||
| 282 | wf_cpu_pid_run(sp, power, temp); | ||
| 283 | |||
| 284 | DBG_LOTS(" CPU%d: target = %d RPM\n", cpu, sp->target); | ||
| 285 | |||
| 286 | /* Apply result directly to exhaust fan */ | ||
| 287 | err = wf_control_set(cpu_rear_fans[cpu], sp->target); | ||
| 288 | if (err) { | ||
| 289 | pr_warning("wf_pm72: Fan %s reports error %d\n", | ||
| 290 | cpu_rear_fans[cpu]->name, err); | ||
| 291 | failure_state |= FAILURE_FAN; | ||
| 292 | break; | ||
| 293 | } | ||
| 294 | |||
| 295 | /* Scale result for intake fan */ | ||
| 296 | intake = (sp->target * CPU_INTAKE_SCALE) >> 16; | ||
| 297 | DBG_LOTS(" CPU%d: intake = %d RPM\n", cpu, intake); | ||
| 298 | err = wf_control_set(cpu_front_fans[cpu], intake); | ||
| 299 | if (err) { | ||
| 300 | pr_warning("wf_pm72: Fan %s reports error %d\n", | ||
| 301 | cpu_front_fans[cpu]->name, err); | ||
| 302 | failure_state |= FAILURE_FAN; | ||
| 303 | break; | ||
| 304 | } | ||
| 305 | } | ||
| 306 | } | ||
| 307 | |||
| 308 | static void cpu_fans_tick_combined(void) | ||
| 309 | { | ||
| 310 | s32 temp0, power0, temp1, power1, t_max = 0; | ||
| 311 | s32 temp, power, intake, pump; | ||
| 312 | struct wf_control *pump0, *pump1; | ||
| 313 | struct wf_cpu_pid_state *sp = &cpu_pid[0]; | ||
| 314 | int err, cpu; | ||
| 315 | |||
| 316 | DBG_LOTS("* cpu fans_tick_combined()\n"); | ||
| 317 | |||
| 318 | /* Read current speed from cpu 0 */ | ||
| 319 | wf_control_get(cpu_rear_fans[0], &sp->target); | ||
| 320 | |||
| 321 | DBG_LOTS(" CPUs: cur_target = %d RPM\n", sp->target); | ||
| 322 | |||
| 323 | /* Read values for both CPUs */ | ||
| 324 | err = read_one_cpu_vals(0, &temp0, &power0); | ||
| 325 | if (err) { | ||
| 326 | failure_state |= FAILURE_SENSOR; | ||
| 327 | cpu_max_all_fans(); | ||
| 328 | return; | ||
| 329 | } | ||
| 330 | err = read_one_cpu_vals(1, &temp1, &power1); | ||
| 331 | if (err) { | ||
| 332 | failure_state |= FAILURE_SENSOR; | ||
| 333 | cpu_max_all_fans(); | ||
| 334 | return; | ||
| 335 | } | ||
| 336 | |||
| 337 | /* Keep track of highest temp */ | ||
| 338 | t_max = max(t_max, max(temp0, temp1)); | ||
| 339 | |||
| 340 | /* Handle possible overtemps */ | ||
| 341 | if (cpu_check_overtemp(t_max)) | ||
| 342 | return; | ||
| 343 | |||
| 344 | /* Use the max temp & power of both */ | ||
| 345 | temp = max(temp0, temp1); | ||
| 346 | power = max(power0, power1); | ||
| 347 | |||
| 348 | /* Run PID */ | ||
| 349 | wf_cpu_pid_run(sp, power, temp); | ||
| 350 | |||
| 351 | /* Scale result for intake fan */ | ||
| 352 | intake = (sp->target * CPU_INTAKE_SCALE) >> 16; | ||
| 353 | |||
| 354 | /* Same deal with pump speed */ | ||
| 355 | pump0 = cpu_pumps[0]; | ||
| 356 | pump1 = cpu_pumps[1]; | ||
| 357 | if (!pump0) { | ||
| 358 | pump0 = pump1; | ||
| 359 | pump1 = NULL; | ||
| 360 | } | ||
| 361 | pump = (sp->target * wf_control_get_max(pump0)) / | ||
| 362 | cpu_mpu_data[0]->rmaxn_exhaust_fan; | ||
| 363 | |||
| 364 | DBG_LOTS(" CPUs: target = %d RPM\n", sp->target); | ||
| 365 | DBG_LOTS(" CPUs: intake = %d RPM\n", intake); | ||
| 366 | DBG_LOTS(" CPUs: pump = %d RPM\n", pump); | ||
| 367 | |||
| 368 | for (cpu = 0; cpu < nr_chips; cpu++) { | ||
| 369 | err = wf_control_set(cpu_rear_fans[cpu], sp->target); | ||
| 370 | if (err) { | ||
| 371 | pr_warning("wf_pm72: Fan %s reports error %d\n", | ||
| 372 | cpu_rear_fans[cpu]->name, err); | ||
| 373 | failure_state |= FAILURE_FAN; | ||
| 374 | } | ||
| 375 | err = wf_control_set(cpu_front_fans[cpu], intake); | ||
| 376 | if (err) { | ||
| 377 | pr_warning("wf_pm72: Fan %s reports error %d\n", | ||
| 378 | cpu_front_fans[cpu]->name, err); | ||
| 379 | failure_state |= FAILURE_FAN; | ||
| 380 | } | ||
| 381 | err = 0; | ||
| 382 | if (cpu_pumps[cpu]) | ||
| 383 | err = wf_control_set(cpu_pumps[cpu], pump); | ||
| 384 | if (err) { | ||
| 385 | pr_warning("wf_pm72: Pump %s reports error %d\n", | ||
| 386 | cpu_pumps[cpu]->name, err); | ||
| 387 | failure_state |= FAILURE_FAN; | ||
| 388 | } | ||
| 389 | } | ||
| 390 | } | ||
| 391 | |||
| 392 | /* Implementation... */ | ||
| 393 | static int cpu_setup_pid(int cpu) | ||
| 394 | { | ||
| 395 | struct wf_cpu_pid_param pid; | ||
| 396 | const struct mpu_data *mpu = cpu_mpu_data[cpu]; | ||
| 397 | s32 tmax, ttarget, ptarget; | ||
| 398 | int fmin, fmax, hsize; | ||
| 399 | |||
| 400 | /* Get PID params from the appropriate MPU EEPROM */ | ||
| 401 | tmax = mpu->tmax << 16; | ||
| 402 | ttarget = mpu->ttarget << 16; | ||
| 403 | ptarget = ((s32)(mpu->pmaxh - mpu->padjmax)) << 16; | ||
| 404 | |||
| 405 | DBG("wf_72: CPU%d ttarget = %d.%03d, tmax = %d.%03d\n", | ||
| 406 | cpu, FIX32TOPRINT(ttarget), FIX32TOPRINT(tmax)); | ||
| 407 | |||
| 408 | /* We keep a global tmax for overtemp calculations */ | ||
| 409 | if (tmax < cpu_all_tmax) | ||
| 410 | cpu_all_tmax = tmax; | ||
| 411 | |||
| 412 | /* Set PID min/max by using the rear fan min/max */ | ||
| 413 | fmin = wf_control_get_min(cpu_rear_fans[cpu]); | ||
| 414 | fmax = wf_control_get_max(cpu_rear_fans[cpu]); | ||
| 415 | DBG("wf_72: CPU%d max RPM range = [%d..%d]\n", cpu, fmin, fmax); | ||
| 416 | |||
| 417 | /* History size */ | ||
| 418 | hsize = min_t(int, mpu->tguardband, WF_PID_MAX_HISTORY); | ||
| 419 | DBG("wf_72: CPU%d history size = %d\n", cpu, hsize); | ||
| 420 | |||
| 421 | /* Initialize PID loop */ | ||
| 422 | pid.interval = 1; /* seconds */ | ||
| 423 | pid.history_len = hsize; | ||
| 424 | pid.gd = mpu->pid_gd; | ||
| 425 | pid.gp = mpu->pid_gp; | ||
| 426 | pid.gr = mpu->pid_gr; | ||
| 427 | pid.tmax = tmax; | ||
| 428 | pid.ttarget = ttarget; | ||
| 429 | pid.pmaxadj = ptarget; | ||
| 430 | pid.min = fmin; | ||
| 431 | pid.max = fmax; | ||
| 432 | |||
| 433 | wf_cpu_pid_init(&cpu_pid[cpu], &pid); | ||
| 434 | cpu_pid[cpu].target = 1000; | ||
| 435 | |||
| 436 | return 0; | ||
| 437 | } | ||
| 438 | |||
| 439 | /* Backside/U3 fan */ | ||
| 440 | static struct wf_pid_param backside_u3_param = { | ||
| 441 | .interval = 5, | ||
| 442 | .history_len = 2, | ||
| 443 | .gd = 40 << 20, | ||
| 444 | .gp = 5 << 20, | ||
| 445 | .gr = 0, | ||
| 446 | .itarget = 65 << 16, | ||
| 447 | .additive = 1, | ||
| 448 | .min = 20, | ||
| 449 | .max = 100, | ||
| 450 | }; | ||
| 451 | |||
| 452 | static struct wf_pid_param backside_u3h_param = { | ||
| 453 | .interval = 5, | ||
| 454 | .history_len = 2, | ||
| 455 | .gd = 20 << 20, | ||
| 456 | .gp = 5 << 20, | ||
| 457 | .gr = 0, | ||
| 458 | .itarget = 75 << 16, | ||
| 459 | .additive = 1, | ||
| 460 | .min = 20, | ||
| 461 | .max = 100, | ||
| 462 | }; | ||
| 463 | |||
| 464 | static void backside_fan_tick(void) | ||
| 465 | { | ||
| 466 | s32 temp; | ||
| 467 | int speed; | ||
| 468 | int err; | ||
| 469 | |||
| 470 | if (!backside_fan || !backside_temp || !backside_tick) | ||
| 471 | return; | ||
| 472 | if (--backside_tick > 0) | ||
| 473 | return; | ||
| 474 | backside_tick = backside_pid.param.interval; | ||
| 475 | |||
| 476 | DBG_LOTS("* backside fans tick\n"); | ||
| 477 | |||
| 478 | /* Update fan speed from actual fans */ | ||
| 479 | err = wf_control_get(backside_fan, &speed); | ||
| 480 | if (!err) | ||
| 481 | backside_pid.target = speed; | ||
| 482 | |||
| 483 | err = wf_sensor_get(backside_temp, &temp); | ||
| 484 | if (err) { | ||
| 485 | printk(KERN_WARNING "windfarm: U4 temp sensor error %d\n", | ||
| 486 | err); | ||
| 487 | failure_state |= FAILURE_SENSOR; | ||
| 488 | wf_control_set_max(backside_fan); | ||
| 489 | return; | ||
| 490 | } | ||
| 491 | speed = wf_pid_run(&backside_pid, temp); | ||
| 492 | |||
| 493 | DBG_LOTS("backside PID temp=%d.%.3d speed=%d\n", | ||
| 494 | FIX32TOPRINT(temp), speed); | ||
| 495 | |||
| 496 | err = wf_control_set(backside_fan, speed); | ||
| 497 | if (err) { | ||
| 498 | printk(KERN_WARNING "windfarm: backside fan error %d\n", err); | ||
| 499 | failure_state |= FAILURE_FAN; | ||
| 500 | } | ||
| 501 | } | ||
| 502 | |||
| 503 | static void backside_setup_pid(void) | ||
| 504 | { | ||
| 505 | /* first time initialize things */ | ||
| 506 | s32 fmin = wf_control_get_min(backside_fan); | ||
| 507 | s32 fmax = wf_control_get_max(backside_fan); | ||
| 508 | struct wf_pid_param param; | ||
| 509 | struct device_node *u3; | ||
| 510 | int u3h = 1; /* conservative by default */ | ||
| 511 | |||
| 512 | u3 = of_find_node_by_path("/u3@0,f8000000"); | ||
| 513 | if (u3 != NULL) { | ||
| 514 | const u32 *vers = of_get_property(u3, "device-rev", NULL); | ||
| 515 | if (vers) | ||
| 516 | if (((*vers) & 0x3f) < 0x34) | ||
| 517 | u3h = 0; | ||
| 518 | of_node_put(u3); | ||
| 519 | } | ||
| 520 | |||
| 521 | param = u3h ? backside_u3h_param : backside_u3_param; | ||
| 522 | |||
| 523 | param.min = max(param.min, fmin); | ||
| 524 | param.max = min(param.max, fmax); | ||
| 525 | wf_pid_init(&backside_pid, ¶m); | ||
| 526 | backside_tick = 1; | ||
| 527 | |||
| 528 | pr_info("wf_pm72: Backside control loop started.\n"); | ||
| 529 | } | ||
| 530 | |||
| 531 | /* Drive bay fan */ | ||
| 532 | static const struct wf_pid_param drives_param = { | ||
| 533 | .interval = 5, | ||
| 534 | .history_len = 2, | ||
| 535 | .gd = 30 << 20, | ||
| 536 | .gp = 5 << 20, | ||
| 537 | .gr = 0, | ||
| 538 | .itarget = 40 << 16, | ||
| 539 | .additive = 1, | ||
| 540 | .min = 300, | ||
| 541 | .max = 4000, | ||
| 542 | }; | ||
| 543 | |||
| 544 | static void drives_fan_tick(void) | ||
| 545 | { | ||
| 546 | s32 temp; | ||
| 547 | int speed; | ||
| 548 | int err; | ||
| 549 | |||
| 550 | if (!drives_fan || !drives_temp || !drives_tick) | ||
| 551 | return; | ||
| 552 | if (--drives_tick > 0) | ||
| 553 | return; | ||
| 554 | drives_tick = drives_pid.param.interval; | ||
| 555 | |||
| 556 | DBG_LOTS("* drives fans tick\n"); | ||
| 557 | |||
| 558 | /* Update fan speed from actual fans */ | ||
| 559 | err = wf_control_get(drives_fan, &speed); | ||
| 560 | if (!err) | ||
| 561 | drives_pid.target = speed; | ||
| 562 | |||
| 563 | err = wf_sensor_get(drives_temp, &temp); | ||
| 564 | if (err) { | ||
| 565 | pr_warning("wf_pm72: drive bay temp sensor error %d\n", err); | ||
| 566 | failure_state |= FAILURE_SENSOR; | ||
| 567 | wf_control_set_max(drives_fan); | ||
| 568 | return; | ||
| 569 | } | ||
| 570 | speed = wf_pid_run(&drives_pid, temp); | ||
| 571 | |||
| 572 | DBG_LOTS("drives PID temp=%d.%.3d speed=%d\n", | ||
| 573 | FIX32TOPRINT(temp), speed); | ||
| 574 | |||
| 575 | err = wf_control_set(drives_fan, speed); | ||
| 576 | if (err) { | ||
| 577 | printk(KERN_WARNING "windfarm: drive bay fan error %d\n", err); | ||
| 578 | failure_state |= FAILURE_FAN; | ||
| 579 | } | ||
| 580 | } | ||
| 581 | |||
| 582 | static void drives_setup_pid(void) | ||
| 583 | { | ||
| 584 | /* first time initialize things */ | ||
| 585 | s32 fmin = wf_control_get_min(drives_fan); | ||
| 586 | s32 fmax = wf_control_get_max(drives_fan); | ||
| 587 | struct wf_pid_param param = drives_param; | ||
| 588 | |||
| 589 | param.min = max(param.min, fmin); | ||
| 590 | param.max = min(param.max, fmax); | ||
| 591 | wf_pid_init(&drives_pid, ¶m); | ||
| 592 | drives_tick = 1; | ||
| 593 | |||
| 594 | pr_info("wf_pm72: Drive bay control loop started.\n"); | ||
| 595 | } | ||
| 596 | |||
| 597 | static void set_fail_state(void) | ||
| 598 | { | ||
| 599 | cpu_max_all_fans(); | ||
| 600 | |||
| 601 | if (backside_fan) | ||
| 602 | wf_control_set_max(backside_fan); | ||
| 603 | if (slots_fan) | ||
| 604 | wf_control_set_max(slots_fan); | ||
| 605 | if (drives_fan) | ||
| 606 | wf_control_set_max(drives_fan); | ||
| 607 | } | ||
| 608 | |||
| 609 | static void pm72_tick(void) | ||
| 610 | { | ||
| 611 | int i, last_failure; | ||
| 612 | |||
| 613 | if (!started) { | ||
| 614 | started = 1; | ||
| 615 | printk(KERN_INFO "windfarm: CPUs control loops started.\n"); | ||
| 616 | for (i = 0; i < nr_chips; ++i) { | ||
| 617 | if (cpu_setup_pid(i) < 0) { | ||
| 618 | failure_state = FAILURE_PERM; | ||
| 619 | set_fail_state(); | ||
| 620 | break; | ||
| 621 | } | ||
| 622 | } | ||
| 623 | DBG_LOTS("cpu_all_tmax=%d.%03d\n", FIX32TOPRINT(cpu_all_tmax)); | ||
| 624 | |||
| 625 | backside_setup_pid(); | ||
| 626 | drives_setup_pid(); | ||
| 627 | |||
| 628 | /* | ||
| 629 | * We don't have the right stuff to drive the PCI fan | ||
| 630 | * so we fix it to a default value | ||
| 631 | */ | ||
| 632 | wf_control_set(slots_fan, SLOTS_FAN_DEFAULT_PWM); | ||
| 633 | |||
| 634 | #ifdef HACKED_OVERTEMP | ||
| 635 | cpu_all_tmax = 60 << 16; | ||
| 636 | #endif | ||
| 637 | } | ||
| 638 | |||
| 639 | /* Permanent failure, bail out */ | ||
| 640 | if (failure_state & FAILURE_PERM) | ||
| 641 | return; | ||
| 642 | |||
| 643 | /* | ||
| 644 | * Clear all failure bits except low overtemp which will be eventually | ||
| 645 | * cleared by the control loop itself | ||
| 646 | */ | ||
| 647 | last_failure = failure_state; | ||
| 648 | failure_state &= FAILURE_LOW_OVERTEMP; | ||
| 649 | if (cpu_pid_combined) | ||
| 650 | cpu_fans_tick_combined(); | ||
| 651 | else | ||
| 652 | cpu_fans_tick_split(); | ||
| 653 | backside_fan_tick(); | ||
| 654 | drives_fan_tick(); | ||
| 655 | |||
| 656 | DBG_LOTS(" last_failure: 0x%x, failure_state: %x\n", | ||
| 657 | last_failure, failure_state); | ||
| 658 | |||
| 659 | /* Check for failures. Any failure causes cpufreq clamping */ | ||
| 660 | if (failure_state && last_failure == 0 && cpufreq_clamp) | ||
| 661 | wf_control_set_max(cpufreq_clamp); | ||
| 662 | if (failure_state == 0 && last_failure && cpufreq_clamp) | ||
| 663 | wf_control_set_min(cpufreq_clamp); | ||
| 664 | |||
| 665 | /* That's it for now, we might want to deal with other failures | ||
| 666 | * differently in the future though | ||
| 667 | */ | ||
| 668 | } | ||
| 669 | |||
| 670 | static void pm72_new_control(struct wf_control *ct) | ||
| 671 | { | ||
| 672 | bool all_controls; | ||
| 673 | bool had_pump = cpu_pumps[0] || cpu_pumps[1]; | ||
| 674 | |||
| 675 | if (!strcmp(ct->name, "cpu-front-fan-0")) | ||
| 676 | cpu_front_fans[0] = ct; | ||
| 677 | else if (!strcmp(ct->name, "cpu-front-fan-1")) | ||
| 678 | cpu_front_fans[1] = ct; | ||
| 679 | else if (!strcmp(ct->name, "cpu-rear-fan-0")) | ||
| 680 | cpu_rear_fans[0] = ct; | ||
| 681 | else if (!strcmp(ct->name, "cpu-rear-fan-1")) | ||
| 682 | cpu_rear_fans[1] = ct; | ||
| 683 | else if (!strcmp(ct->name, "cpu-pump-0")) | ||
| 684 | cpu_pumps[0] = ct; | ||
| 685 | else if (!strcmp(ct->name, "cpu-pump-1")) | ||
| 686 | cpu_pumps[1] = ct; | ||
| 687 | else if (!strcmp(ct->name, "backside-fan")) | ||
| 688 | backside_fan = ct; | ||
| 689 | else if (!strcmp(ct->name, "slots-fan")) | ||
| 690 | slots_fan = ct; | ||
| 691 | else if (!strcmp(ct->name, "drive-bay-fan")) | ||
| 692 | drives_fan = ct; | ||
| 693 | else if (!strcmp(ct->name, "cpufreq-clamp")) | ||
| 694 | cpufreq_clamp = ct; | ||
| 695 | |||
| 696 | all_controls = | ||
| 697 | cpu_front_fans[0] && | ||
| 698 | cpu_rear_fans[0] && | ||
| 699 | backside_fan && | ||
| 700 | slots_fan && | ||
| 701 | drives_fan; | ||
| 702 | if (nr_chips > 1) | ||
| 703 | all_controls &= | ||
| 704 | cpu_front_fans[1] && | ||
| 705 | cpu_rear_fans[1]; | ||
| 706 | have_all_controls = all_controls; | ||
| 707 | |||
| 708 | if ((cpu_pumps[0] || cpu_pumps[1]) && !had_pump) { | ||
| 709 | pr_info("wf_pm72: Liquid cooling pump(s) detected," | ||
| 710 | " using new algorithm !\n"); | ||
| 711 | cpu_pid_combined = true; | ||
| 712 | } | ||
| 713 | } | ||
| 714 | |||
| 715 | |||
| 716 | static void pm72_new_sensor(struct wf_sensor *sr) | ||
| 717 | { | ||
| 718 | bool all_sensors; | ||
| 719 | |||
| 720 | if (!strcmp(sr->name, "cpu-diode-temp-0")) | ||
| 721 | sens_cpu_temp[0] = sr; | ||
| 722 | else if (!strcmp(sr->name, "cpu-diode-temp-1")) | ||
| 723 | sens_cpu_temp[1] = sr; | ||
| 724 | else if (!strcmp(sr->name, "cpu-voltage-0")) | ||
| 725 | sens_cpu_volts[0] = sr; | ||
| 726 | else if (!strcmp(sr->name, "cpu-voltage-1")) | ||
| 727 | sens_cpu_volts[1] = sr; | ||
| 728 | else if (!strcmp(sr->name, "cpu-current-0")) | ||
| 729 | sens_cpu_amps[0] = sr; | ||
| 730 | else if (!strcmp(sr->name, "cpu-current-1")) | ||
| 731 | sens_cpu_amps[1] = sr; | ||
| 732 | else if (!strcmp(sr->name, "backside-temp")) | ||
| 733 | backside_temp = sr; | ||
| 734 | else if (!strcmp(sr->name, "hd-temp")) | ||
| 735 | drives_temp = sr; | ||
| 736 | |||
| 737 | all_sensors = | ||
| 738 | sens_cpu_temp[0] && | ||
| 739 | sens_cpu_volts[0] && | ||
| 740 | sens_cpu_amps[0] && | ||
| 741 | backside_temp && | ||
| 742 | drives_temp; | ||
| 743 | if (nr_chips > 1) | ||
| 744 | all_sensors &= | ||
| 745 | sens_cpu_temp[1] && | ||
| 746 | sens_cpu_volts[1] && | ||
| 747 | sens_cpu_amps[1]; | ||
| 748 | |||
| 749 | have_all_sensors = all_sensors; | ||
| 750 | } | ||
| 751 | |||
| 752 | static int pm72_wf_notify(struct notifier_block *self, | ||
| 753 | unsigned long event, void *data) | ||
| 754 | { | ||
| 755 | switch (event) { | ||
| 756 | case WF_EVENT_NEW_SENSOR: | ||
| 757 | pm72_new_sensor(data); | ||
| 758 | break; | ||
| 759 | case WF_EVENT_NEW_CONTROL: | ||
| 760 | pm72_new_control(data); | ||
| 761 | break; | ||
| 762 | case WF_EVENT_TICK: | ||
| 763 | if (have_all_controls && have_all_sensors) | ||
| 764 | pm72_tick(); | ||
| 765 | } | ||
| 766 | return 0; | ||
| 767 | } | ||
| 768 | |||
| 769 | static struct notifier_block pm72_events = { | ||
| 770 | .notifier_call = pm72_wf_notify, | ||
| 771 | }; | ||
| 772 | |||
| 773 | static int wf_pm72_probe(struct platform_device *dev) | ||
| 774 | { | ||
| 775 | wf_register_client(&pm72_events); | ||
| 776 | return 0; | ||
| 777 | } | ||
| 778 | |||
| 779 | static int wf_pm72_remove(struct platform_device *dev) | ||
| 780 | { | ||
| 781 | wf_unregister_client(&pm72_events); | ||
| 782 | |||
| 783 | /* should release all sensors and controls */ | ||
| 784 | return 0; | ||
| 785 | } | ||
| 786 | |||
| 787 | static struct platform_driver wf_pm72_driver = { | ||
| 788 | .probe = wf_pm72_probe, | ||
| 789 | .remove = wf_pm72_remove, | ||
| 790 | .driver = { | ||
| 791 | .name = "windfarm", | ||
| 792 | .owner = THIS_MODULE, | ||
| 793 | }, | ||
| 794 | }; | ||
| 795 | |||
| 796 | static int __init wf_pm72_init(void) | ||
| 797 | { | ||
| 798 | struct device_node *cpu; | ||
| 799 | int i; | ||
| 800 | |||
| 801 | if (!of_machine_is_compatible("PowerMac7,2") && | ||
| 802 | !of_machine_is_compatible("PowerMac7,3")) | ||
| 803 | return -ENODEV; | ||
| 804 | |||
| 805 | /* Count the number of CPU cores */ | ||
| 806 | nr_chips = 0; | ||
| 807 | for (cpu = NULL; (cpu = of_find_node_by_type(cpu, "cpu")) != NULL; ) | ||
| 808 | ++nr_chips; | ||
| 809 | if (nr_chips > NR_CHIPS) | ||
| 810 | nr_chips = NR_CHIPS; | ||
| 811 | |||
| 812 | pr_info("windfarm: Initializing for desktop G5 with %d chips\n", | ||
| 813 | nr_chips); | ||
| 814 | |||
| 815 | /* Get MPU data for each CPU */ | ||
| 816 | for (i = 0; i < nr_chips; i++) { | ||
| 817 | cpu_mpu_data[i] = wf_get_mpu(i); | ||
| 818 | if (!cpu_mpu_data[i]) { | ||
| 819 | pr_err("wf_pm72: Failed to find MPU data for CPU %d\n", i); | ||
| 820 | return -ENXIO; | ||
| 821 | } | ||
| 822 | } | ||
| 823 | |||
| 824 | #ifdef MODULE | ||
| 825 | request_module("windfarm_fcu_controls"); | ||
| 826 | request_module("windfarm_lm75_sensor"); | ||
| 827 | request_module("windfarm_ad7417_sensor"); | ||
| 828 | request_module("windfarm_max6690_sensor"); | ||
| 829 | request_module("windfarm_cpufreq_clamp"); | ||
| 830 | #endif /* MODULE */ | ||
| 831 | |||
| 832 | platform_driver_register(&wf_pm72_driver); | ||
| 833 | return 0; | ||
| 834 | } | ||
| 835 | |||
| 836 | static void __exit wf_pm72_exit(void) | ||
| 837 | { | ||
| 838 | platform_driver_unregister(&wf_pm72_driver); | ||
| 839 | } | ||
| 840 | |||
| 841 | module_init(wf_pm72_init); | ||
| 842 | module_exit(wf_pm72_exit); | ||
| 843 | |||
| 844 | MODULE_AUTHOR("Benjamin Herrenschmidt <benh@kernel.crashing.org>"); | ||
| 845 | MODULE_DESCRIPTION("Thermal control for AGP PowerMac G5s"); | ||
| 846 | MODULE_LICENSE("GPL"); | ||
| 847 | MODULE_ALIAS("platform:windfarm"); | ||
diff --git a/drivers/macintosh/windfarm_pm81.c b/drivers/macintosh/windfarm_pm81.c index f84933ff329..749d174b0dc 100644 --- a/drivers/macintosh/windfarm_pm81.c +++ b/drivers/macintosh/windfarm_pm81.c | |||
| @@ -107,6 +107,7 @@ | |||
| 107 | #include <asm/prom.h> | 107 | #include <asm/prom.h> |
| 108 | #include <asm/machdep.h> | 108 | #include <asm/machdep.h> |
| 109 | #include <asm/io.h> | 109 | #include <asm/io.h> |
| 110 | #include <asm/system.h> | ||
| 110 | #include <asm/sections.h> | 111 | #include <asm/sections.h> |
| 111 | #include <asm/smu.h> | 112 | #include <asm/smu.h> |
| 112 | 113 | ||
| @@ -302,13 +303,13 @@ static void wf_smu_create_sys_fans(void) | |||
| 302 | pid_param.interval = WF_SMU_SYS_FANS_INTERVAL; | 303 | pid_param.interval = WF_SMU_SYS_FANS_INTERVAL; |
| 303 | pid_param.history_len = WF_SMU_SYS_FANS_HISTORY_SIZE; | 304 | pid_param.history_len = WF_SMU_SYS_FANS_HISTORY_SIZE; |
| 304 | pid_param.itarget = param->itarget; | 305 | pid_param.itarget = param->itarget; |
| 305 | pid_param.min = wf_control_get_min(fan_system); | 306 | pid_param.min = fan_system->ops->get_min(fan_system); |
| 306 | pid_param.max = wf_control_get_max(fan_system); | 307 | pid_param.max = fan_system->ops->get_max(fan_system); |
| 307 | if (fan_hd) { | 308 | if (fan_hd) { |
| 308 | pid_param.min = | 309 | pid_param.min = |
| 309 | max(pid_param.min, wf_control_get_min(fan_hd)); | 310 | max(pid_param.min,fan_hd->ops->get_min(fan_hd)); |
| 310 | pid_param.max = | 311 | pid_param.max = |
| 311 | min(pid_param.max, wf_control_get_max(fan_hd)); | 312 | min(pid_param.max,fan_hd->ops->get_max(fan_hd)); |
| 312 | } | 313 | } |
| 313 | wf_pid_init(&wf_smu_sys_fans->pid, &pid_param); | 314 | wf_pid_init(&wf_smu_sys_fans->pid, &pid_param); |
| 314 | 315 | ||
| @@ -337,7 +338,7 @@ static void wf_smu_sys_fans_tick(struct wf_smu_sys_fans_state *st) | |||
| 337 | } | 338 | } |
| 338 | st->ticks = WF_SMU_SYS_FANS_INTERVAL; | 339 | st->ticks = WF_SMU_SYS_FANS_INTERVAL; |
| 339 | 340 | ||
| 340 | rc = wf_sensor_get(sensor_hd_temp, &temp); | 341 | rc = sensor_hd_temp->ops->get_value(sensor_hd_temp, &temp); |
| 341 | if (rc) { | 342 | if (rc) { |
| 342 | printk(KERN_WARNING "windfarm: HD temp sensor error %d\n", | 343 | printk(KERN_WARNING "windfarm: HD temp sensor error %d\n", |
| 343 | rc); | 344 | rc); |
| @@ -373,7 +374,7 @@ static void wf_smu_sys_fans_tick(struct wf_smu_sys_fans_state *st) | |||
| 373 | st->hd_setpoint = new_setpoint; | 374 | st->hd_setpoint = new_setpoint; |
| 374 | readjust: | 375 | readjust: |
| 375 | if (fan_system && wf_smu_failure_state == 0) { | 376 | if (fan_system && wf_smu_failure_state == 0) { |
| 376 | rc = wf_control_set(fan_system, st->sys_setpoint); | 377 | rc = fan_system->ops->set_value(fan_system, st->sys_setpoint); |
| 377 | if (rc) { | 378 | if (rc) { |
| 378 | printk(KERN_WARNING "windfarm: Sys fan error %d\n", | 379 | printk(KERN_WARNING "windfarm: Sys fan error %d\n", |
| 379 | rc); | 380 | rc); |
| @@ -381,7 +382,7 @@ static void wf_smu_sys_fans_tick(struct wf_smu_sys_fans_state *st) | |||
| 381 | } | 382 | } |
| 382 | } | 383 | } |
| 383 | if (fan_hd && wf_smu_failure_state == 0) { | 384 | if (fan_hd && wf_smu_failure_state == 0) { |
| 384 | rc = wf_control_set(fan_hd, st->hd_setpoint); | 385 | rc = fan_hd->ops->set_value(fan_hd, st->hd_setpoint); |
| 385 | if (rc) { | 386 | if (rc) { |
| 386 | printk(KERN_WARNING "windfarm: HD fan error %d\n", | 387 | printk(KERN_WARNING "windfarm: HD fan error %d\n", |
| 387 | rc); | 388 | rc); |
| @@ -447,8 +448,8 @@ static void wf_smu_create_cpu_fans(void) | |||
| 447 | pid_param.ttarget = tmax - tdelta; | 448 | pid_param.ttarget = tmax - tdelta; |
| 448 | pid_param.pmaxadj = maxpow - powadj; | 449 | pid_param.pmaxadj = maxpow - powadj; |
| 449 | 450 | ||
| 450 | pid_param.min = wf_control_get_min(fan_cpu_main); | 451 | pid_param.min = fan_cpu_main->ops->get_min(fan_cpu_main); |
| 451 | pid_param.max = wf_control_get_max(fan_cpu_main); | 452 | pid_param.max = fan_cpu_main->ops->get_max(fan_cpu_main); |
| 452 | 453 | ||
| 453 | wf_cpu_pid_init(&wf_smu_cpu_fans->pid, &pid_param); | 454 | wf_cpu_pid_init(&wf_smu_cpu_fans->pid, &pid_param); |
| 454 | 455 | ||
| @@ -481,7 +482,7 @@ static void wf_smu_cpu_fans_tick(struct wf_smu_cpu_fans_state *st) | |||
| 481 | } | 482 | } |
| 482 | st->ticks = WF_SMU_CPU_FANS_INTERVAL; | 483 | st->ticks = WF_SMU_CPU_FANS_INTERVAL; |
| 483 | 484 | ||
| 484 | rc = wf_sensor_get(sensor_cpu_temp, &temp); | 485 | rc = sensor_cpu_temp->ops->get_value(sensor_cpu_temp, &temp); |
| 485 | if (rc) { | 486 | if (rc) { |
| 486 | printk(KERN_WARNING "windfarm: CPU temp sensor error %d\n", | 487 | printk(KERN_WARNING "windfarm: CPU temp sensor error %d\n", |
| 487 | rc); | 488 | rc); |
| @@ -489,7 +490,7 @@ static void wf_smu_cpu_fans_tick(struct wf_smu_cpu_fans_state *st) | |||
| 489 | return; | 490 | return; |
| 490 | } | 491 | } |
| 491 | 492 | ||
| 492 | rc = wf_sensor_get(sensor_cpu_power, &power); | 493 | rc = sensor_cpu_power->ops->get_value(sensor_cpu_power, &power); |
| 493 | if (rc) { | 494 | if (rc) { |
| 494 | printk(KERN_WARNING "windfarm: CPU power sensor error %d\n", | 495 | printk(KERN_WARNING "windfarm: CPU power sensor error %d\n", |
| 495 | rc); | 496 | rc); |
| @@ -525,7 +526,8 @@ static void wf_smu_cpu_fans_tick(struct wf_smu_cpu_fans_state *st) | |||
| 525 | st->cpu_setpoint = new_setpoint; | 526 | st->cpu_setpoint = new_setpoint; |
| 526 | readjust: | 527 | readjust: |
| 527 | if (fan_cpu_main && wf_smu_failure_state == 0) { | 528 | if (fan_cpu_main && wf_smu_failure_state == 0) { |
| 528 | rc = wf_control_set(fan_cpu_main, st->cpu_setpoint); | 529 | rc = fan_cpu_main->ops->set_value(fan_cpu_main, |
| 530 | st->cpu_setpoint); | ||
| 529 | if (rc) { | 531 | if (rc) { |
| 530 | printk(KERN_WARNING "windfarm: CPU main fan" | 532 | printk(KERN_WARNING "windfarm: CPU main fan" |
| 531 | " error %d\n", rc); | 533 | " error %d\n", rc); |
| @@ -720,7 +722,7 @@ static int wf_smu_probe(struct platform_device *ddev) | |||
| 720 | return 0; | 722 | return 0; |
| 721 | } | 723 | } |
| 722 | 724 | ||
| 723 | static int wf_smu_remove(struct platform_device *ddev) | 725 | static int __devexit wf_smu_remove(struct platform_device *ddev) |
| 724 | { | 726 | { |
| 725 | wf_unregister_client(&wf_smu_events); | 727 | wf_unregister_client(&wf_smu_events); |
| 726 | 728 | ||
| @@ -763,7 +765,7 @@ static int wf_smu_remove(struct platform_device *ddev) | |||
| 763 | 765 | ||
| 764 | static struct platform_driver wf_smu_driver = { | 766 | static struct platform_driver wf_smu_driver = { |
| 765 | .probe = wf_smu_probe, | 767 | .probe = wf_smu_probe, |
| 766 | .remove = wf_smu_remove, | 768 | .remove = __devexit_p(wf_smu_remove), |
| 767 | .driver = { | 769 | .driver = { |
| 768 | .name = "windfarm", | 770 | .name = "windfarm", |
| 769 | .owner = THIS_MODULE, | 771 | .owner = THIS_MODULE, |
diff --git a/drivers/macintosh/windfarm_pm91.c b/drivers/macintosh/windfarm_pm91.c index 2eb484f213c..34427323512 100644 --- a/drivers/macintosh/windfarm_pm91.c +++ b/drivers/macintosh/windfarm_pm91.c | |||
| @@ -41,6 +41,7 @@ | |||
| 41 | #include <asm/prom.h> | 41 | #include <asm/prom.h> |
| 42 | #include <asm/machdep.h> | 42 | #include <asm/machdep.h> |
| 43 | #include <asm/io.h> | 43 | #include <asm/io.h> |
| 44 | #include <asm/system.h> | ||
| 44 | #include <asm/sections.h> | 45 | #include <asm/sections.h> |
| 45 | #include <asm/smu.h> | 46 | #include <asm/smu.h> |
| 46 | 47 | ||
| @@ -192,8 +193,8 @@ static void wf_smu_create_cpu_fans(void) | |||
| 192 | pid_param.ttarget = tmax - tdelta; | 193 | pid_param.ttarget = tmax - tdelta; |
| 193 | pid_param.pmaxadj = maxpow - powadj; | 194 | pid_param.pmaxadj = maxpow - powadj; |
| 194 | 195 | ||
| 195 | pid_param.min = wf_control_get_min(fan_cpu_main); | 196 | pid_param.min = fan_cpu_main->ops->get_min(fan_cpu_main); |
| 196 | pid_param.max = wf_control_get_max(fan_cpu_main); | 197 | pid_param.max = fan_cpu_main->ops->get_max(fan_cpu_main); |
| 197 | 198 | ||
| 198 | wf_cpu_pid_init(&wf_smu_cpu_fans->pid, &pid_param); | 199 | wf_cpu_pid_init(&wf_smu_cpu_fans->pid, &pid_param); |
| 199 | 200 | ||
| @@ -226,7 +227,7 @@ static void wf_smu_cpu_fans_tick(struct wf_smu_cpu_fans_state *st) | |||
| 226 | } | 227 | } |
| 227 | st->ticks = WF_SMU_CPU_FANS_INTERVAL; | 228 | st->ticks = WF_SMU_CPU_FANS_INTERVAL; |
| 228 | 229 | ||
| 229 | rc = wf_sensor_get(sensor_cpu_temp, &temp); | 230 | rc = sensor_cpu_temp->ops->get_value(sensor_cpu_temp, &temp); |
| 230 | if (rc) { | 231 | if (rc) { |
| 231 | printk(KERN_WARNING "windfarm: CPU temp sensor error %d\n", | 232 | printk(KERN_WARNING "windfarm: CPU temp sensor error %d\n", |
| 232 | rc); | 233 | rc); |
| @@ -234,7 +235,7 @@ static void wf_smu_cpu_fans_tick(struct wf_smu_cpu_fans_state *st) | |||
| 234 | return; | 235 | return; |
| 235 | } | 236 | } |
| 236 | 237 | ||
| 237 | rc = wf_sensor_get(sensor_cpu_power, &power); | 238 | rc = sensor_cpu_power->ops->get_value(sensor_cpu_power, &power); |
| 238 | if (rc) { | 239 | if (rc) { |
| 239 | printk(KERN_WARNING "windfarm: CPU power sensor error %d\n", | 240 | printk(KERN_WARNING "windfarm: CPU power sensor error %d\n", |
| 240 | rc); | 241 | rc); |
| @@ -261,7 +262,8 @@ static void wf_smu_cpu_fans_tick(struct wf_smu_cpu_fans_state *st) | |||
| 261 | st->cpu_setpoint = new_setpoint; | 262 | st->cpu_setpoint = new_setpoint; |
| 262 | readjust: | 263 | readjust: |
| 263 | if (fan_cpu_main && wf_smu_failure_state == 0) { | 264 | if (fan_cpu_main && wf_smu_failure_state == 0) { |
| 264 | rc = wf_control_set(fan_cpu_main, st->cpu_setpoint); | 265 | rc = fan_cpu_main->ops->set_value(fan_cpu_main, |
| 266 | st->cpu_setpoint); | ||
| 265 | if (rc) { | 267 | if (rc) { |
| 266 | printk(KERN_WARNING "windfarm: CPU main fan" | 268 | printk(KERN_WARNING "windfarm: CPU main fan" |
| 267 | " error %d\n", rc); | 269 | " error %d\n", rc); |
| @@ -269,7 +271,8 @@ static void wf_smu_cpu_fans_tick(struct wf_smu_cpu_fans_state *st) | |||
| 269 | } | 271 | } |
| 270 | } | 272 | } |
| 271 | if (fan_cpu_second && wf_smu_failure_state == 0) { | 273 | if (fan_cpu_second && wf_smu_failure_state == 0) { |
| 272 | rc = wf_control_set(fan_cpu_second, st->cpu_setpoint); | 274 | rc = fan_cpu_second->ops->set_value(fan_cpu_second, |
| 275 | st->cpu_setpoint); | ||
| 273 | if (rc) { | 276 | if (rc) { |
| 274 | printk(KERN_WARNING "windfarm: CPU second fan" | 277 | printk(KERN_WARNING "windfarm: CPU second fan" |
| 275 | " error %d\n", rc); | 278 | " error %d\n", rc); |
| @@ -277,7 +280,8 @@ static void wf_smu_cpu_fans_tick(struct wf_smu_cpu_fans_state *st) | |||
| 277 | } | 280 | } |
| 278 | } | 281 | } |
| 279 | if (fan_cpu_third && wf_smu_failure_state == 0) { | 282 | if (fan_cpu_third && wf_smu_failure_state == 0) { |
| 280 | rc = wf_control_set(fan_cpu_third, st->cpu_setpoint); | 283 | rc = fan_cpu_main->ops->set_value(fan_cpu_third, |
| 284 | st->cpu_setpoint); | ||
| 281 | if (rc) { | 285 | if (rc) { |
| 282 | printk(KERN_WARNING "windfarm: CPU third fan" | 286 | printk(KERN_WARNING "windfarm: CPU third fan" |
| 283 | " error %d\n", rc); | 287 | " error %d\n", rc); |
| @@ -309,8 +313,8 @@ static void wf_smu_create_drive_fans(void) | |||
| 309 | 313 | ||
| 310 | /* Fill PID params */ | 314 | /* Fill PID params */ |
| 311 | param.additive = (fan_hd->type == WF_CONTROL_RPM_FAN); | 315 | param.additive = (fan_hd->type == WF_CONTROL_RPM_FAN); |
| 312 | param.min = wf_control_get_min(fan_hd); | 316 | param.min = fan_hd->ops->get_min(fan_hd); |
| 313 | param.max = wf_control_get_max(fan_hd); | 317 | param.max = fan_hd->ops->get_max(fan_hd); |
| 314 | wf_pid_init(&wf_smu_drive_fans->pid, ¶m); | 318 | wf_pid_init(&wf_smu_drive_fans->pid, ¶m); |
| 315 | 319 | ||
| 316 | DBG("wf: Drive Fan control initialized.\n"); | 320 | DBG("wf: Drive Fan control initialized.\n"); |
| @@ -335,7 +339,7 @@ static void wf_smu_drive_fans_tick(struct wf_smu_drive_fans_state *st) | |||
| 335 | } | 339 | } |
| 336 | st->ticks = st->pid.param.interval; | 340 | st->ticks = st->pid.param.interval; |
| 337 | 341 | ||
| 338 | rc = wf_sensor_get(sensor_hd_temp, &temp); | 342 | rc = sensor_hd_temp->ops->get_value(sensor_hd_temp, &temp); |
| 339 | if (rc) { | 343 | if (rc) { |
| 340 | printk(KERN_WARNING "windfarm: HD temp sensor error %d\n", | 344 | printk(KERN_WARNING "windfarm: HD temp sensor error %d\n", |
| 341 | rc); | 345 | rc); |
| @@ -358,7 +362,7 @@ static void wf_smu_drive_fans_tick(struct wf_smu_drive_fans_state *st) | |||
| 358 | st->setpoint = new_setpoint; | 362 | st->setpoint = new_setpoint; |
| 359 | readjust: | 363 | readjust: |
| 360 | if (fan_hd && wf_smu_failure_state == 0) { | 364 | if (fan_hd && wf_smu_failure_state == 0) { |
| 361 | rc = wf_control_set(fan_hd, st->setpoint); | 365 | rc = fan_hd->ops->set_value(fan_hd, st->setpoint); |
| 362 | if (rc) { | 366 | if (rc) { |
| 363 | printk(KERN_WARNING "windfarm: HD fan error %d\n", | 367 | printk(KERN_WARNING "windfarm: HD fan error %d\n", |
| 364 | rc); | 368 | rc); |
| @@ -390,8 +394,8 @@ static void wf_smu_create_slots_fans(void) | |||
| 390 | 394 | ||
| 391 | /* Fill PID params */ | 395 | /* Fill PID params */ |
| 392 | param.additive = (fan_slots->type == WF_CONTROL_RPM_FAN); | 396 | param.additive = (fan_slots->type == WF_CONTROL_RPM_FAN); |
| 393 | param.min = wf_control_get_min(fan_slots); | 397 | param.min = fan_slots->ops->get_min(fan_slots); |
| 394 | param.max = wf_control_get_max(fan_slots); | 398 | param.max = fan_slots->ops->get_max(fan_slots); |
| 395 | wf_pid_init(&wf_smu_slots_fans->pid, ¶m); | 399 | wf_pid_init(&wf_smu_slots_fans->pid, ¶m); |
| 396 | 400 | ||
| 397 | DBG("wf: Slots Fan control initialized.\n"); | 401 | DBG("wf: Slots Fan control initialized.\n"); |
| @@ -416,7 +420,7 @@ static void wf_smu_slots_fans_tick(struct wf_smu_slots_fans_state *st) | |||
| 416 | } | 420 | } |
| 417 | st->ticks = st->pid.param.interval; | 421 | st->ticks = st->pid.param.interval; |
| 418 | 422 | ||
| 419 | rc = wf_sensor_get(sensor_slots_power, &power); | 423 | rc = sensor_slots_power->ops->get_value(sensor_slots_power, &power); |
| 420 | if (rc) { | 424 | if (rc) { |
| 421 | printk(KERN_WARNING "windfarm: Slots power sensor error %d\n", | 425 | printk(KERN_WARNING "windfarm: Slots power sensor error %d\n", |
| 422 | rc); | 426 | rc); |
| @@ -441,7 +445,7 @@ static void wf_smu_slots_fans_tick(struct wf_smu_slots_fans_state *st) | |||
| 441 | st->setpoint = new_setpoint; | 445 | st->setpoint = new_setpoint; |
| 442 | readjust: | 446 | readjust: |
| 443 | if (fan_slots && wf_smu_failure_state == 0) { | 447 | if (fan_slots && wf_smu_failure_state == 0) { |
| 444 | rc = wf_control_set(fan_slots, st->setpoint); | 448 | rc = fan_slots->ops->set_value(fan_slots, st->setpoint); |
| 445 | if (rc) { | 449 | if (rc) { |
| 446 | printk(KERN_WARNING "windfarm: Slots fan error %d\n", | 450 | printk(KERN_WARNING "windfarm: Slots fan error %d\n", |
| 447 | rc); | 451 | rc); |
| @@ -642,7 +646,7 @@ static int wf_smu_probe(struct platform_device *ddev) | |||
| 642 | return 0; | 646 | return 0; |
| 643 | } | 647 | } |
| 644 | 648 | ||
| 645 | static int wf_smu_remove(struct platform_device *ddev) | 649 | static int __devexit wf_smu_remove(struct platform_device *ddev) |
| 646 | { | 650 | { |
| 647 | wf_unregister_client(&wf_smu_events); | 651 | wf_unregister_client(&wf_smu_events); |
| 648 | 652 | ||
| @@ -692,7 +696,7 @@ static int wf_smu_remove(struct platform_device *ddev) | |||
| 692 | 696 | ||
| 693 | static struct platform_driver wf_smu_driver = { | 697 | static struct platform_driver wf_smu_driver = { |
| 694 | .probe = wf_smu_probe, | 698 | .probe = wf_smu_probe, |
| 695 | .remove = wf_smu_remove, | 699 | .remove = __devexit_p(wf_smu_remove), |
| 696 | .driver = { | 700 | .driver = { |
| 697 | .name = "windfarm", | 701 | .name = "windfarm", |
| 698 | .owner = THIS_MODULE, | 702 | .owner = THIS_MODULE, |
diff --git a/drivers/macintosh/windfarm_rm31.c b/drivers/macintosh/windfarm_rm31.c deleted file mode 100644 index 844003fb4ef..00000000000 --- a/drivers/macintosh/windfarm_rm31.c +++ /dev/null | |||
| @@ -1,740 +0,0 @@ | |||
| 1 | /* | ||
| 2 | * Windfarm PowerMac thermal control. | ||
| 3 | * Control loops for RackMack3,1 (Xserve G5) | ||
| 4 | * | ||
| 5 | * Copyright (C) 2012 Benjamin Herrenschmidt, IBM Corp. | ||
| 6 | * | ||
| 7 | * Use and redistribute under the terms of the GNU GPL v2. | ||
| 8 | */ | ||
| 9 | #include <linux/types.h> | ||
| 10 | #include <linux/errno.h> | ||
| 11 | #include <linux/kernel.h> | ||
| 12 | #include <linux/device.h> | ||
| 13 | #include <linux/platform_device.h> | ||
| 14 | #include <linux/reboot.h> | ||
| 15 | #include <asm/prom.h> | ||
| 16 | #include <asm/smu.h> | ||
| 17 | |||
| 18 | #include "windfarm.h" | ||
| 19 | #include "windfarm_pid.h" | ||
| 20 | #include "windfarm_mpu.h" | ||
| 21 | |||
| 22 | #define VERSION "1.0" | ||
| 23 | |||
| 24 | #undef DEBUG | ||
| 25 | #undef LOTSA_DEBUG | ||
| 26 | |||
| 27 | #ifdef DEBUG | ||
| 28 | #define DBG(args...) printk(args) | ||
| 29 | #else | ||
| 30 | #define DBG(args...) do { } while(0) | ||
| 31 | #endif | ||
| 32 | |||
| 33 | #ifdef LOTSA_DEBUG | ||
| 34 | #define DBG_LOTS(args...) printk(args) | ||
| 35 | #else | ||
| 36 | #define DBG_LOTS(args...) do { } while(0) | ||
| 37 | #endif | ||
| 38 | |||
| 39 | /* define this to force CPU overtemp to 60 degree, useful for testing | ||
| 40 | * the overtemp code | ||
| 41 | */ | ||
| 42 | #undef HACKED_OVERTEMP | ||
| 43 | |||
| 44 | /* We currently only handle 2 chips */ | ||
| 45 | #define NR_CHIPS 2 | ||
| 46 | #define NR_CPU_FANS 3 * NR_CHIPS | ||
| 47 | |||
| 48 | /* Controls and sensors */ | ||
| 49 | static struct wf_sensor *sens_cpu_temp[NR_CHIPS]; | ||
| 50 | static struct wf_sensor *sens_cpu_volts[NR_CHIPS]; | ||
| 51 | static struct wf_sensor *sens_cpu_amps[NR_CHIPS]; | ||
| 52 | static struct wf_sensor *backside_temp; | ||
| 53 | static struct wf_sensor *slots_temp; | ||
| 54 | static struct wf_sensor *dimms_temp; | ||
| 55 | |||
| 56 | static struct wf_control *cpu_fans[NR_CHIPS][3]; | ||
| 57 | static struct wf_control *backside_fan; | ||
| 58 | static struct wf_control *slots_fan; | ||
| 59 | static struct wf_control *cpufreq_clamp; | ||
| 60 | |||
| 61 | /* We keep a temperature history for average calculation of 180s */ | ||
| 62 | #define CPU_TEMP_HIST_SIZE 180 | ||
| 63 | |||
| 64 | /* PID loop state */ | ||
| 65 | static const struct mpu_data *cpu_mpu_data[NR_CHIPS]; | ||
| 66 | static struct wf_cpu_pid_state cpu_pid[NR_CHIPS]; | ||
| 67 | static u32 cpu_thist[CPU_TEMP_HIST_SIZE]; | ||
| 68 | static int cpu_thist_pt; | ||
| 69 | static s64 cpu_thist_total; | ||
| 70 | static s32 cpu_all_tmax = 100 << 16; | ||
| 71 | static struct wf_pid_state backside_pid; | ||
| 72 | static int backside_tick; | ||
| 73 | static struct wf_pid_state slots_pid; | ||
| 74 | static int slots_tick; | ||
| 75 | static int slots_speed; | ||
| 76 | static struct wf_pid_state dimms_pid; | ||
| 77 | static int dimms_output_clamp; | ||
| 78 | |||
| 79 | static int nr_chips; | ||
| 80 | static bool have_all_controls; | ||
| 81 | static bool have_all_sensors; | ||
| 82 | static bool started; | ||
| 83 | |||
| 84 | static int failure_state; | ||
| 85 | #define FAILURE_SENSOR 1 | ||
| 86 | #define FAILURE_FAN 2 | ||
| 87 | #define FAILURE_PERM 4 | ||
| 88 | #define FAILURE_LOW_OVERTEMP 8 | ||
| 89 | #define FAILURE_HIGH_OVERTEMP 16 | ||
| 90 | |||
| 91 | /* Overtemp values */ | ||
| 92 | #define LOW_OVER_AVERAGE 0 | ||
| 93 | #define LOW_OVER_IMMEDIATE (10 << 16) | ||
| 94 | #define LOW_OVER_CLEAR ((-10) << 16) | ||
| 95 | #define HIGH_OVER_IMMEDIATE (14 << 16) | ||
| 96 | #define HIGH_OVER_AVERAGE (10 << 16) | ||
| 97 | #define HIGH_OVER_IMMEDIATE (14 << 16) | ||
| 98 | |||
| 99 | |||
| 100 | static void cpu_max_all_fans(void) | ||
| 101 | { | ||
| 102 | int i; | ||
| 103 | |||
| 104 | /* We max all CPU fans in case of a sensor error. We also do the | ||
| 105 | * cpufreq clamping now, even if it's supposedly done later by the | ||
| 106 | * generic code anyway, we do it earlier here to react faster | ||
| 107 | */ | ||
| 108 | if (cpufreq_clamp) | ||
| 109 | wf_control_set_max(cpufreq_clamp); | ||
| 110 | for (i = 0; i < nr_chips; i++) { | ||
| 111 | if (cpu_fans[i][0]) | ||
| 112 | wf_control_set_max(cpu_fans[i][0]); | ||
| 113 | if (cpu_fans[i][1]) | ||
| 114 | wf_control_set_max(cpu_fans[i][1]); | ||
| 115 | if (cpu_fans[i][2]) | ||
| 116 | wf_control_set_max(cpu_fans[i][2]); | ||
| 117 | } | ||
| 118 | } | ||
| 119 | |||
| 120 | static int cpu_check_overtemp(s32 temp) | ||
| 121 | { | ||
| 122 | int new_state = 0; | ||
| 123 | s32 t_avg, t_old; | ||
| 124 | static bool first = true; | ||
| 125 | |||
| 126 | /* First check for immediate overtemps */ | ||
| 127 | if (temp >= (cpu_all_tmax + LOW_OVER_IMMEDIATE)) { | ||
| 128 | new_state |= FAILURE_LOW_OVERTEMP; | ||
| 129 | if ((failure_state & FAILURE_LOW_OVERTEMP) == 0) | ||
| 130 | printk(KERN_ERR "windfarm: Overtemp due to immediate CPU" | ||
| 131 | " temperature !\n"); | ||
| 132 | } | ||
| 133 | if (temp >= (cpu_all_tmax + HIGH_OVER_IMMEDIATE)) { | ||
| 134 | new_state |= FAILURE_HIGH_OVERTEMP; | ||
| 135 | if ((failure_state & FAILURE_HIGH_OVERTEMP) == 0) | ||
| 136 | printk(KERN_ERR "windfarm: Critical overtemp due to" | ||
| 137 | " immediate CPU temperature !\n"); | ||
| 138 | } | ||
| 139 | |||
| 140 | /* | ||
| 141 | * The first time around, initialize the array with the first | ||
| 142 | * temperature reading | ||
| 143 | */ | ||
| 144 | if (first) { | ||
| 145 | int i; | ||
| 146 | |||
| 147 | cpu_thist_total = 0; | ||
| 148 | for (i = 0; i < CPU_TEMP_HIST_SIZE; i++) { | ||
| 149 | cpu_thist[i] = temp; | ||
| 150 | cpu_thist_total += temp; | ||
| 151 | } | ||
| 152 | first = false; | ||
| 153 | } | ||
| 154 | |||
| 155 | /* | ||
| 156 | * We calculate a history of max temperatures and use that for the | ||
| 157 | * overtemp management | ||
| 158 | */ | ||
| 159 | t_old = cpu_thist[cpu_thist_pt]; | ||
| 160 | cpu_thist[cpu_thist_pt] = temp; | ||
| 161 | cpu_thist_pt = (cpu_thist_pt + 1) % CPU_TEMP_HIST_SIZE; | ||
| 162 | cpu_thist_total -= t_old; | ||
| 163 | cpu_thist_total += temp; | ||
| 164 | t_avg = cpu_thist_total / CPU_TEMP_HIST_SIZE; | ||
| 165 | |||
| 166 | DBG_LOTS(" t_avg = %d.%03d (out: %d.%03d, in: %d.%03d)\n", | ||
| 167 | FIX32TOPRINT(t_avg), FIX32TOPRINT(t_old), FIX32TOPRINT(temp)); | ||
| 168 | |||
| 169 | /* Now check for average overtemps */ | ||
| 170 | if (t_avg >= (cpu_all_tmax + LOW_OVER_AVERAGE)) { | ||
| 171 | new_state |= FAILURE_LOW_OVERTEMP; | ||
| 172 | if ((failure_state & FAILURE_LOW_OVERTEMP) == 0) | ||
| 173 | printk(KERN_ERR "windfarm: Overtemp due to average CPU" | ||
| 174 | " temperature !\n"); | ||
| 175 | } | ||
| 176 | if (t_avg >= (cpu_all_tmax + HIGH_OVER_AVERAGE)) { | ||
| 177 | new_state |= FAILURE_HIGH_OVERTEMP; | ||
| 178 | if ((failure_state & FAILURE_HIGH_OVERTEMP) == 0) | ||
| 179 | printk(KERN_ERR "windfarm: Critical overtemp due to" | ||
| 180 | " average CPU temperature !\n"); | ||
| 181 | } | ||
| 182 | |||
| 183 | /* Now handle overtemp conditions. We don't currently use the windfarm | ||
| 184 | * overtemp handling core as it's not fully suited to the needs of those | ||
| 185 | * new machine. This will be fixed later. | ||
| 186 | */ | ||
| 187 | if (new_state) { | ||
| 188 | /* High overtemp -> immediate shutdown */ | ||
| 189 | if (new_state & FAILURE_HIGH_OVERTEMP) | ||
| 190 | machine_power_off(); | ||
| 191 | if ((failure_state & new_state) != new_state) | ||
| 192 | cpu_max_all_fans(); | ||
| 193 | failure_state |= new_state; | ||
| 194 | } else if ((failure_state & FAILURE_LOW_OVERTEMP) && | ||
| 195 | (temp < (cpu_all_tmax + LOW_OVER_CLEAR))) { | ||
| 196 | printk(KERN_ERR "windfarm: Overtemp condition cleared !\n"); | ||
| 197 | failure_state &= ~FAILURE_LOW_OVERTEMP; | ||
| 198 | } | ||
| 199 | |||
| 200 | return failure_state & (FAILURE_LOW_OVERTEMP | FAILURE_HIGH_OVERTEMP); | ||
| 201 | } | ||
| 202 | |||
| 203 | static int read_one_cpu_vals(int cpu, s32 *temp, s32 *power) | ||
| 204 | { | ||
| 205 | s32 dtemp, volts, amps; | ||
| 206 | int rc; | ||
| 207 | |||
| 208 | /* Get diode temperature */ | ||
| 209 | rc = wf_sensor_get(sens_cpu_temp[cpu], &dtemp); | ||
| 210 | if (rc) { | ||
| 211 | DBG(" CPU%d: temp reading error !\n", cpu); | ||
| 212 | return -EIO; | ||
| 213 | } | ||
| 214 | DBG_LOTS(" CPU%d: temp = %d.%03d\n", cpu, FIX32TOPRINT((dtemp))); | ||
| 215 | *temp = dtemp; | ||
| 216 | |||
| 217 | /* Get voltage */ | ||
| 218 | rc = wf_sensor_get(sens_cpu_volts[cpu], &volts); | ||
| 219 | if (rc) { | ||
| 220 | DBG(" CPU%d, volts reading error !\n", cpu); | ||
| 221 | return -EIO; | ||
| 222 | } | ||
| 223 | DBG_LOTS(" CPU%d: volts = %d.%03d\n", cpu, FIX32TOPRINT((volts))); | ||
| 224 | |||
| 225 | /* Get current */ | ||
| 226 | rc = wf_sensor_get(sens_cpu_amps[cpu], &s); | ||
| 227 | if (rc) { | ||
| 228 | DBG(" CPU%d, current reading error !\n", cpu); | ||
| 229 | return -EIO; | ||
| 230 | } | ||
| 231 | DBG_LOTS(" CPU%d: amps = %d.%03d\n", cpu, FIX32TOPRINT((amps))); | ||
| 232 | |||
| 233 | /* Calculate power */ | ||
| 234 | |||
| 235 | /* Scale voltage and current raw sensor values according to fixed scales | ||
| 236 | * obtained in Darwin and calculate power from I and V | ||
| 237 | */ | ||
| 238 | *power = (((u64)volts) * ((u64)amps)) >> 16; | ||
| 239 | |||
| 240 | DBG_LOTS(" CPU%d: power = %d.%03d\n", cpu, FIX32TOPRINT((*power))); | ||
| 241 | |||
| 242 | return 0; | ||
| 243 | |||
| 244 | } | ||
| 245 | |||
| 246 | static void cpu_fans_tick(void) | ||
| 247 | { | ||
| 248 | int err, cpu, i; | ||
| 249 | s32 speed, temp, power, t_max = 0; | ||
| 250 | |||
| 251 | DBG_LOTS("* cpu fans_tick_split()\n"); | ||
| 252 | |||
| 253 | for (cpu = 0; cpu < nr_chips; ++cpu) { | ||
| 254 | struct wf_cpu_pid_state *sp = &cpu_pid[cpu]; | ||
| 255 | |||
| 256 | /* Read current speed */ | ||
| 257 | wf_control_get(cpu_fans[cpu][0], &sp->target); | ||
| 258 | |||
| 259 | err = read_one_cpu_vals(cpu, &temp, &power); | ||
| 260 | if (err) { | ||
| 261 | failure_state |= FAILURE_SENSOR; | ||
| 262 | cpu_max_all_fans(); | ||
| 263 | return; | ||
| 264 | } | ||
| 265 | |||
| 266 | /* Keep track of highest temp */ | ||
| 267 | t_max = max(t_max, temp); | ||
| 268 | |||
| 269 | /* Handle possible overtemps */ | ||
| 270 | if (cpu_check_overtemp(t_max)) | ||
| 271 | return; | ||
| 272 | |||
| 273 | /* Run PID */ | ||
| 274 | wf_cpu_pid_run(sp, power, temp); | ||
| 275 | |||
| 276 | DBG_LOTS(" CPU%d: target = %d RPM\n", cpu, sp->target); | ||
| 277 | |||
| 278 | /* Apply DIMMs clamp */ | ||
| 279 | speed = max(sp->target, dimms_output_clamp); | ||
| 280 | |||
| 281 | /* Apply result to all cpu fans */ | ||
| 282 | for (i = 0; i < 3; i++) { | ||
| 283 | err = wf_control_set(cpu_fans[cpu][i], speed); | ||
| 284 | if (err) { | ||
| 285 | pr_warning("wf_rm31: Fan %s reports error %d\n", | ||
| 286 | cpu_fans[cpu][i]->name, err); | ||
| 287 | failure_state |= FAILURE_FAN; | ||
| 288 | } | ||
| 289 | } | ||
| 290 | } | ||
| 291 | } | ||
| 292 | |||
| 293 | /* Implementation... */ | ||
| 294 | static int cpu_setup_pid(int cpu) | ||
| 295 | { | ||
| 296 | struct wf_cpu_pid_param pid; | ||
| 297 | const struct mpu_data *mpu = cpu_mpu_data[cpu]; | ||
| 298 | s32 tmax, ttarget, ptarget; | ||
| 299 | int fmin, fmax, hsize; | ||
| 300 | |||
| 301 | /* Get PID params from the appropriate MPU EEPROM */ | ||
| 302 | tmax = mpu->tmax << 16; | ||
| 303 | ttarget = mpu->ttarget << 16; | ||
| 304 | ptarget = ((s32)(mpu->pmaxh - mpu->padjmax)) << 16; | ||
| 305 | |||
| 306 | DBG("wf_72: CPU%d ttarget = %d.%03d, tmax = %d.%03d\n", | ||
| 307 | cpu, FIX32TOPRINT(ttarget), FIX32TOPRINT(tmax)); | ||
| 308 | |||
| 309 | /* We keep a global tmax for overtemp calculations */ | ||
| 310 | if (tmax < cpu_all_tmax) | ||
| 311 | cpu_all_tmax = tmax; | ||
| 312 | |||
| 313 | /* Set PID min/max by using the rear fan min/max */ | ||
| 314 | fmin = wf_control_get_min(cpu_fans[cpu][0]); | ||
| 315 | fmax = wf_control_get_max(cpu_fans[cpu][0]); | ||
| 316 | DBG("wf_72: CPU%d max RPM range = [%d..%d]\n", cpu, fmin, fmax); | ||
| 317 | |||
| 318 | /* History size */ | ||
| 319 | hsize = min_t(int, mpu->tguardband, WF_PID_MAX_HISTORY); | ||
| 320 | DBG("wf_72: CPU%d history size = %d\n", cpu, hsize); | ||
| 321 | |||
| 322 | /* Initialize PID loop */ | ||
| 323 | pid.interval = 1; /* seconds */ | ||
| 324 | pid.history_len = hsize; | ||
| 325 | pid.gd = mpu->pid_gd; | ||
| 326 | pid.gp = mpu->pid_gp; | ||
| 327 | pid.gr = mpu->pid_gr; | ||
| 328 | pid.tmax = tmax; | ||
| 329 | pid.ttarget = ttarget; | ||
| 330 | pid.pmaxadj = ptarget; | ||
| 331 | pid.min = fmin; | ||
| 332 | pid.max = fmax; | ||
| 333 | |||
| 334 | wf_cpu_pid_init(&cpu_pid[cpu], &pid); | ||
| 335 | cpu_pid[cpu].target = 4000; | ||
| 336 | |||
| 337 | return 0; | ||
| 338 | } | ||
| 339 | |||
| 340 | /* Backside/U3 fan */ | ||
| 341 | static struct wf_pid_param backside_param = { | ||
| 342 | .interval = 1, | ||
| 343 | .history_len = 2, | ||
| 344 | .gd = 0x00500000, | ||
| 345 | .gp = 0x0004cccc, | ||
| 346 | .gr = 0, | ||
| 347 | .itarget = 70 << 16, | ||
| 348 | .additive = 0, | ||
| 349 | .min = 20, | ||
| 350 | .max = 100, | ||
| 351 | }; | ||
| 352 | |||
| 353 | /* DIMMs temperature (clamp the backside fan) */ | ||
| 354 | static struct wf_pid_param dimms_param = { | ||
| 355 | .interval = 1, | ||
| 356 | .history_len = 20, | ||
| 357 | .gd = 0, | ||
| 358 | .gp = 0, | ||
| 359 | .gr = 0x06553600, | ||
| 360 | .itarget = 50 << 16, | ||
| 361 | .additive = 0, | ||
| 362 | .min = 4000, | ||
| 363 | .max = 14000, | ||
| 364 | }; | ||
| 365 | |||
| 366 | static void backside_fan_tick(void) | ||
| 367 | { | ||
| 368 | s32 temp, dtemp; | ||
| 369 | int speed, dspeed, fan_min; | ||
| 370 | int err; | ||
| 371 | |||
| 372 | if (!backside_fan || !backside_temp || !dimms_temp || !backside_tick) | ||
| 373 | return; | ||
| 374 | if (--backside_tick > 0) | ||
| 375 | return; | ||
| 376 | backside_tick = backside_pid.param.interval; | ||
| 377 | |||
| 378 | DBG_LOTS("* backside fans tick\n"); | ||
| 379 | |||
| 380 | /* Update fan speed from actual fans */ | ||
| 381 | err = wf_control_get(backside_fan, &speed); | ||
| 382 | if (!err) | ||
| 383 | backside_pid.target = speed; | ||
| 384 | |||
| 385 | err = wf_sensor_get(backside_temp, &temp); | ||
| 386 | if (err) { | ||
| 387 | printk(KERN_WARNING "windfarm: U3 temp sensor error %d\n", | ||
| 388 | err); | ||
| 389 | failure_state |= FAILURE_SENSOR; | ||
| 390 | wf_control_set_max(backside_fan); | ||
| 391 | return; | ||
| 392 | } | ||
| 393 | speed = wf_pid_run(&backside_pid, temp); | ||
| 394 | |||
| 395 | DBG_LOTS("backside PID temp=%d.%.3d speed=%d\n", | ||
| 396 | FIX32TOPRINT(temp), speed); | ||
| 397 | |||
| 398 | err = wf_sensor_get(dimms_temp, &dtemp); | ||
| 399 | if (err) { | ||
| 400 | printk(KERN_WARNING "windfarm: DIMMs temp sensor error %d\n", | ||
| 401 | err); | ||
| 402 | failure_state |= FAILURE_SENSOR; | ||
| 403 | wf_control_set_max(backside_fan); | ||
| 404 | return; | ||
| 405 | } | ||
| 406 | dspeed = wf_pid_run(&dimms_pid, dtemp); | ||
| 407 | dimms_output_clamp = dspeed; | ||
| 408 | |||
| 409 | fan_min = (dspeed * 100) / 14000; | ||
| 410 | fan_min = max(fan_min, backside_param.min); | ||
| 411 | speed = max(speed, fan_min); | ||
| 412 | |||
| 413 | err = wf_control_set(backside_fan, speed); | ||
| 414 | if (err) { | ||
| 415 | printk(KERN_WARNING "windfarm: backside fan error %d\n", err); | ||
| 416 | failure_state |= FAILURE_FAN; | ||
| 417 | } | ||
| 418 | } | ||
| 419 | |||
| 420 | static void backside_setup_pid(void) | ||
| 421 | { | ||
| 422 | /* first time initialize things */ | ||
| 423 | s32 fmin = wf_control_get_min(backside_fan); | ||
| 424 | s32 fmax = wf_control_get_max(backside_fan); | ||
| 425 | struct wf_pid_param param; | ||
| 426 | |||
| 427 | param = backside_param; | ||
| 428 | param.min = max(param.min, fmin); | ||
| 429 | param.max = min(param.max, fmax); | ||
| 430 | wf_pid_init(&backside_pid, ¶m); | ||
| 431 | |||
| 432 | param = dimms_param; | ||
| 433 | wf_pid_init(&dimms_pid, ¶m); | ||
| 434 | |||
| 435 | backside_tick = 1; | ||
| 436 | |||
| 437 | pr_info("wf_rm31: Backside control loop started.\n"); | ||
| 438 | } | ||
| 439 | |||
| 440 | /* Slots fan */ | ||
| 441 | static const struct wf_pid_param slots_param = { | ||
| 442 | .interval = 5, | ||
| 443 | .history_len = 2, | ||
| 444 | .gd = 30 << 20, | ||
| 445 | .gp = 5 << 20, | ||
| 446 | .gr = 0, | ||
| 447 | .itarget = 40 << 16, | ||
| 448 | .additive = 1, | ||
| 449 | .min = 300, | ||
| 450 | .max = 4000, | ||
| 451 | }; | ||
| 452 | |||
| 453 | static void slots_fan_tick(void) | ||
| 454 | { | ||
| 455 | s32 temp; | ||
| 456 | int speed; | ||
| 457 | int err; | ||
| 458 | |||
| 459 | if (!slots_fan || !slots_temp || !slots_tick) | ||
| 460 | return; | ||
| 461 | if (--slots_tick > 0) | ||
| 462 | return; | ||
| 463 | slots_tick = slots_pid.param.interval; | ||
| 464 | |||
| 465 | DBG_LOTS("* slots fans tick\n"); | ||
| 466 | |||
| 467 | err = wf_sensor_get(slots_temp, &temp); | ||
| 468 | if (err) { | ||
| 469 | pr_warning("wf_rm31: slots temp sensor error %d\n", err); | ||
| 470 | failure_state |= FAILURE_SENSOR; | ||
| 471 | wf_control_set_max(slots_fan); | ||
| 472 | return; | ||
| 473 | } | ||
| 474 | speed = wf_pid_run(&slots_pid, temp); | ||
| 475 | |||
| 476 | DBG_LOTS("slots PID temp=%d.%.3d speed=%d\n", | ||
| 477 | FIX32TOPRINT(temp), speed); | ||
| 478 | |||
| 479 | slots_speed = speed; | ||
| 480 | err = wf_control_set(slots_fan, speed); | ||
| 481 | if (err) { | ||
| 482 | printk(KERN_WARNING "windfarm: slots bay fan error %d\n", err); | ||
| 483 | failure_state |= FAILURE_FAN; | ||
| 484 | } | ||
| 485 | } | ||
| 486 | |||
| 487 | static void slots_setup_pid(void) | ||
| 488 | { | ||
| 489 | /* first time initialize things */ | ||
| 490 | s32 fmin = wf_control_get_min(slots_fan); | ||
| 491 | s32 fmax = wf_control_get_max(slots_fan); | ||
| 492 | struct wf_pid_param param = slots_param; | ||
| 493 | |||
| 494 | param.min = max(param.min, fmin); | ||
| 495 | param.max = min(param.max, fmax); | ||
| 496 | wf_pid_init(&slots_pid, ¶m); | ||
| 497 | slots_tick = 1; | ||
| 498 | |||
| 499 | pr_info("wf_rm31: Slots control loop started.\n"); | ||
| 500 | } | ||
| 501 | |||
| 502 | static void set_fail_state(void) | ||
| 503 | { | ||
| 504 | cpu_max_all_fans(); | ||
| 505 | |||
| 506 | if (backside_fan) | ||
| 507 | wf_control_set_max(backside_fan); | ||
| 508 | if (slots_fan) | ||
| 509 | wf_control_set_max(slots_fan); | ||
| 510 | } | ||
| 511 | |||
| 512 | static void rm31_tick(void) | ||
| 513 | { | ||
| 514 | int i, last_failure; | ||
| 515 | |||
| 516 | if (!started) { | ||
| 517 | started = 1; | ||
| 518 | printk(KERN_INFO "windfarm: CPUs control loops started.\n"); | ||
| 519 | for (i = 0; i < nr_chips; ++i) { | ||
| 520 | if (cpu_setup_pid(i) < 0) { | ||
| 521 | failure_state = FAILURE_PERM; | ||
| 522 | set_fail_state(); | ||
| 523 | break; | ||
| 524 | } | ||
| 525 | } | ||
| 526 | DBG_LOTS("cpu_all_tmax=%d.%03d\n", FIX32TOPRINT(cpu_all_tmax)); | ||
| 527 | |||
| 528 | backside_setup_pid(); | ||
| 529 | slots_setup_pid(); | ||
| 530 | |||
| 531 | #ifdef HACKED_OVERTEMP | ||
| 532 | cpu_all_tmax = 60 << 16; | ||
| 533 | #endif | ||
| 534 | } | ||
| 535 | |||
| 536 | /* Permanent failure, bail out */ | ||
| 537 | if (failure_state & FAILURE_PERM) | ||
| 538 | return; | ||
| 539 | |||
| 540 | /* | ||
| 541 | * Clear all failure bits except low overtemp which will be eventually | ||
| 542 | * cleared by the control loop itself | ||
| 543 | */ | ||
| 544 | last_failure = failure_state; | ||
| 545 | failure_state &= FAILURE_LOW_OVERTEMP; | ||
| 546 | backside_fan_tick(); | ||
| 547 | slots_fan_tick(); | ||
| 548 | |||
| 549 | /* We do CPUs last because they can be clamped high by | ||
| 550 | * DIMM temperature | ||
| 551 | */ | ||
| 552 | cpu_fans_tick(); | ||
| 553 | |||
| 554 | DBG_LOTS(" last_failure: 0x%x, failure_state: %x\n", | ||
| 555 | last_failure, failure_state); | ||
| 556 | |||
| 557 | /* Check for failures. Any failure causes cpufreq clamping */ | ||
| 558 | if (failure_state && last_failure == 0 && cpufreq_clamp) | ||
| 559 | wf_control_set_max(cpufreq_clamp); | ||
| 560 | if (failure_state == 0 && last_failure && cpufreq_clamp) | ||
| 561 | wf_control_set_min(cpufreq_clamp); | ||
| 562 | |||
| 563 | /* That's it for now, we might want to deal with other failures | ||
| 564 | * differently in the future though | ||
| 565 | */ | ||
| 566 | } | ||
| 567 | |||
| 568 | static void rm31_new_control(struct wf_control *ct) | ||
| 569 | { | ||
| 570 | bool all_controls; | ||
| 571 | |||
| 572 | if (!strcmp(ct->name, "cpu-fan-a-0")) | ||
| 573 | cpu_fans[0][0] = ct; | ||
| 574 | else if (!strcmp(ct->name, "cpu-fan-b-0")) | ||
| 575 | cpu_fans[0][1] = ct; | ||
| 576 | else if (!strcmp(ct->name, "cpu-fan-c-0")) | ||
| 577 | cpu_fans[0][2] = ct; | ||
| 578 | else if (!strcmp(ct->name, "cpu-fan-a-1")) | ||
| 579 | cpu_fans[1][0] = ct; | ||
| 580 | else if (!strcmp(ct->name, "cpu-fan-b-1")) | ||
| 581 | cpu_fans[1][1] = ct; | ||
| 582 | else if (!strcmp(ct->name, "cpu-fan-c-1")) | ||
| 583 | cpu_fans[1][2] = ct; | ||
| 584 | else if (!strcmp(ct->name, "backside-fan")) | ||
| 585 | backside_fan = ct; | ||
| 586 | else if (!strcmp(ct->name, "slots-fan")) | ||
| 587 | slots_fan = ct; | ||
| 588 | else if (!strcmp(ct->name, "cpufreq-clamp")) | ||
| 589 | cpufreq_clamp = ct; | ||
| 590 | |||
| 591 | all_controls = | ||
| 592 | cpu_fans[0][0] && | ||
| 593 | cpu_fans[0][1] && | ||
| 594 | cpu_fans[0][2] && | ||
| 595 | backside_fan && | ||
| 596 | slots_fan; | ||
| 597 | if (nr_chips > 1) | ||
| 598 | all_controls &= | ||
| 599 | cpu_fans[1][0] && | ||
| 600 | cpu_fans[1][1] && | ||
| 601 | cpu_fans[1][2]; | ||
| 602 | have_all_controls = all_controls; | ||
| 603 | } | ||
| 604 | |||
| 605 | |||
| 606 | static void rm31_new_sensor(struct wf_sensor *sr) | ||
| 607 | { | ||
| 608 | bool all_sensors; | ||
| 609 | |||
| 610 | if (!strcmp(sr->name, "cpu-diode-temp-0")) | ||
| 611 | sens_cpu_temp[0] = sr; | ||
| 612 | else if (!strcmp(sr->name, "cpu-diode-temp-1")) | ||
| 613 | sens_cpu_temp[1] = sr; | ||
| 614 | else if (!strcmp(sr->name, "cpu-voltage-0")) | ||
| 615 | sens_cpu_volts[0] = sr; | ||
| 616 | else if (!strcmp(sr->name, "cpu-voltage-1")) | ||
| 617 | sens_cpu_volts[1] = sr; | ||
| 618 | else if (!strcmp(sr->name, "cpu-current-0")) | ||
| 619 | sens_cpu_amps[0] = sr; | ||
| 620 | else if (!strcmp(sr->name, "cpu-current-1")) | ||
| 621 | sens_cpu_amps[1] = sr; | ||
| 622 | else if (!strcmp(sr->name, "backside-temp")) | ||
| 623 | backside_temp = sr; | ||
| 624 | else if (!strcmp(sr->name, "slots-temp")) | ||
| 625 | slots_temp = sr; | ||
| 626 | else if (!strcmp(sr->name, "dimms-temp")) | ||
| 627 | dimms_temp = sr; | ||
| 628 | |||
| 629 | all_sensors = | ||
| 630 | sens_cpu_temp[0] && | ||
| 631 | sens_cpu_volts[0] && | ||
| 632 | sens_cpu_amps[0] && | ||
| 633 | backside_temp && | ||
| 634 | slots_temp && | ||
| 635 | dimms_temp; | ||
| 636 | if (nr_chips > 1) | ||
| 637 | all_sensors &= | ||
| 638 | sens_cpu_temp[1] && | ||
| 639 | sens_cpu_volts[1] && | ||
| 640 | sens_cpu_amps[1]; | ||
| 641 | |||
| 642 | have_all_sensors = all_sensors; | ||
| 643 | } | ||
| 644 | |||
| 645 | static int rm31_wf_notify(struct notifier_block *self, | ||
| 646 | unsigned long event, void *data) | ||
| 647 | { | ||
| 648 | switch (event) { | ||
| 649 | case WF_EVENT_NEW_SENSOR: | ||
| 650 | rm31_new_sensor(data); | ||
| 651 | break; | ||
| 652 | case WF_EVENT_NEW_CONTROL: | ||
| 653 | rm31_new_control(data); | ||
| 654 | break; | ||
| 655 | case WF_EVENT_TICK: | ||
| 656 | if (have_all_controls && have_all_sensors) | ||
| 657 | rm31_tick(); | ||
| 658 | } | ||
| 659 | return 0; | ||
| 660 | } | ||
| 661 | |||
| 662 | static struct notifier_block rm31_events = { | ||
| 663 | .notifier_call = rm31_wf_notify, | ||
| 664 | }; | ||
| 665 | |||
| 666 | static int wf_rm31_probe(struct platform_device *dev) | ||
| 667 | { | ||
| 668 | wf_register_client(&rm31_events); | ||
| 669 | return 0; | ||
| 670 | } | ||
| 671 | |||
| 672 | static int wf_rm31_remove(struct platform_device *dev) | ||
| 673 | { | ||
| 674 | wf_unregister_client(&rm31_events); | ||
| 675 | |||
| 676 | /* should release all sensors and controls */ | ||
| 677 | return 0; | ||
| 678 | } | ||
| 679 | |||
| 680 | static struct platform_driver wf_rm31_driver = { | ||
| 681 | .probe = wf_rm31_probe, | ||
| 682 | .remove = wf_rm31_remove, | ||
| 683 | .driver = { | ||
| 684 | .name = "windfarm", | ||
| 685 | .owner = THIS_MODULE, | ||
| 686 | }, | ||
| 687 | }; | ||
| 688 | |||
| 689 | static int __init wf_rm31_init(void) | ||
| 690 | { | ||
| 691 | struct device_node *cpu; | ||
| 692 | int i; | ||
| 693 | |||
| 694 | if (!of_machine_is_compatible("RackMac3,1")) | ||
| 695 | return -ENODEV; | ||
| 696 | |||
| 697 | /* Count the number of CPU cores */ | ||
| 698 | nr_chips = 0; | ||
| 699 | for (cpu = NULL; (cpu = of_find_node_by_type(cpu, "cpu")) != NULL; ) | ||
| 700 | ++nr_chips; | ||
| 701 | if (nr_chips > NR_CHIPS) | ||
| 702 | nr_chips = NR_CHIPS; | ||
| 703 | |||
| 704 | pr_info("windfarm: Initializing for desktop G5 with %d chips\n", | ||
| 705 | nr_chips); | ||
| 706 | |||
| 707 | /* Get MPU data for each CPU */ | ||
| 708 | for (i = 0; i < nr_chips; i++) { | ||
| 709 | cpu_mpu_data[i] = wf_get_mpu(i); | ||
| 710 | if (!cpu_mpu_data[i]) { | ||
| 711 | pr_err("wf_rm31: Failed to find MPU data for CPU %d\n", i); | ||
| 712 | return -ENXIO; | ||
| 713 | } | ||
| 714 | } | ||
| 715 | |||
| 716 | #ifdef MODULE | ||
| 717 | request_module("windfarm_fcu_controls"); | ||
| 718 | request_module("windfarm_lm75_sensor"); | ||
| 719 | request_module("windfarm_lm87_sensor"); | ||
| 720 | request_module("windfarm_ad7417_sensor"); | ||
| 721 | request_module("windfarm_max6690_sensor"); | ||
| 722 | request_module("windfarm_cpufreq_clamp"); | ||
| 723 | #endif /* MODULE */ | ||
| 724 | |||
| 725 | platform_driver_register(&wf_rm31_driver); | ||
| 726 | return 0; | ||
| 727 | } | ||
| 728 | |||
| 729 | static void __exit wf_rm31_exit(void) | ||
| 730 | { | ||
| 731 | platform_driver_unregister(&wf_rm31_driver); | ||
| 732 | } | ||
| 733 | |||
| 734 | module_init(wf_rm31_init); | ||
| 735 | module_exit(wf_rm31_exit); | ||
| 736 | |||
| 737 | MODULE_AUTHOR("Benjamin Herrenschmidt <benh@kernel.crashing.org>"); | ||
| 738 | MODULE_DESCRIPTION("Thermal control for Xserve G5"); | ||
| 739 | MODULE_LICENSE("GPL"); | ||
| 740 | MODULE_ALIAS("platform:windfarm"); | ||
diff --git a/drivers/macintosh/windfarm_smu_controls.c b/drivers/macintosh/windfarm_smu_controls.c index c155a54e863..43137b421f9 100644 --- a/drivers/macintosh/windfarm_smu_controls.c +++ b/drivers/macintosh/windfarm_smu_controls.c | |||
| @@ -18,6 +18,7 @@ | |||
| 18 | #include <asm/prom.h> | 18 | #include <asm/prom.h> |
| 19 | #include <asm/machdep.h> | 19 | #include <asm/machdep.h> |
| 20 | #include <asm/io.h> | 20 | #include <asm/io.h> |
| 21 | #include <asm/system.h> | ||
| 21 | #include <asm/sections.h> | 22 | #include <asm/sections.h> |
| 22 | #include <asm/smu.h> | 23 | #include <asm/smu.h> |
| 23 | 24 | ||
| @@ -172,6 +173,7 @@ static struct smu_fan_control *smu_fan_create(struct device_node *node, | |||
| 172 | 173 | ||
| 173 | fct->fan_type = pwm_fan; | 174 | fct->fan_type = pwm_fan; |
| 174 | fct->ctrl.type = pwm_fan ? WF_CONTROL_PWM_FAN : WF_CONTROL_RPM_FAN; | 175 | fct->ctrl.type = pwm_fan ? WF_CONTROL_PWM_FAN : WF_CONTROL_RPM_FAN; |
| 176 | sysfs_attr_init(&fct->ctrl.attr.attr); | ||
| 175 | 177 | ||
| 176 | /* We use the name & location here the same way we do for SMU sensors, | 178 | /* We use the name & location here the same way we do for SMU sensors, |
| 177 | * see the comment in windfarm_smu_sensors.c. The locations are a bit | 179 | * see the comment in windfarm_smu_sensors.c. The locations are a bit |
diff --git a/drivers/macintosh/windfarm_smu_sat.c b/drivers/macintosh/windfarm_smu_sat.c index d87f5ee04ca..65a8ff3e1f8 100644 --- a/drivers/macintosh/windfarm_smu_sat.c +++ b/drivers/macintosh/windfarm_smu_sat.c | |||
| @@ -20,7 +20,7 @@ | |||
| 20 | 20 | ||
| 21 | #include "windfarm.h" | 21 | #include "windfarm.h" |
| 22 | 22 | ||
| 23 | #define VERSION "1.0" | 23 | #define VERSION "0.2" |
| 24 | 24 | ||
| 25 | #define DEBUG | 25 | #define DEBUG |
| 26 | 26 | ||
| @@ -34,12 +34,11 @@ | |||
| 34 | #define MAX_AGE msecs_to_jiffies(800) | 34 | #define MAX_AGE msecs_to_jiffies(800) |
| 35 | 35 | ||
| 36 | struct wf_sat { | 36 | struct wf_sat { |
| 37 | struct kref ref; | ||
| 38 | int nr; | 37 | int nr; |
| 38 | atomic_t refcnt; | ||
| 39 | struct mutex mutex; | 39 | struct mutex mutex; |
| 40 | unsigned long last_read; /* jiffies when cache last updated */ | 40 | unsigned long last_read; /* jiffies when cache last updated */ |
| 41 | u8 cache[16]; | 41 | u8 cache[16]; |
| 42 | struct list_head sensors; | ||
| 43 | struct i2c_client *i2c; | 42 | struct i2c_client *i2c; |
| 44 | struct device_node *node; | 43 | struct device_node *node; |
| 45 | }; | 44 | }; |
| @@ -47,12 +46,11 @@ struct wf_sat { | |||
| 47 | static struct wf_sat *sats[2]; | 46 | static struct wf_sat *sats[2]; |
| 48 | 47 | ||
| 49 | struct wf_sat_sensor { | 48 | struct wf_sat_sensor { |
| 50 | struct list_head link; | 49 | int index; |
| 51 | int index; | 50 | int index2; /* used for power sensors */ |
| 52 | int index2; /* used for power sensors */ | 51 | int shift; |
| 53 | int shift; | 52 | struct wf_sat *sat; |
| 54 | struct wf_sat *sat; | 53 | struct wf_sensor sens; |
| 55 | struct wf_sensor sens; | ||
| 56 | }; | 54 | }; |
| 57 | 55 | ||
| 58 | #define wf_to_sat(c) container_of(c, struct wf_sat_sensor, sens) | 56 | #define wf_to_sat(c) container_of(c, struct wf_sat_sensor, sens) |
| @@ -144,7 +142,7 @@ static int wf_sat_read_cache(struct wf_sat *sat) | |||
| 144 | return 0; | 142 | return 0; |
| 145 | } | 143 | } |
| 146 | 144 | ||
| 147 | static int wf_sat_sensor_get(struct wf_sensor *sr, s32 *value) | 145 | static int wf_sat_get(struct wf_sensor *sr, s32 *value) |
| 148 | { | 146 | { |
| 149 | struct wf_sat_sensor *sens = wf_to_sat(sr); | 147 | struct wf_sat_sensor *sens = wf_to_sat(sr); |
| 150 | struct wf_sat *sat = sens->sat; | 148 | struct wf_sat *sat = sens->sat; |
| @@ -177,34 +175,62 @@ static int wf_sat_sensor_get(struct wf_sensor *sr, s32 *value) | |||
| 177 | return err; | 175 | return err; |
| 178 | } | 176 | } |
| 179 | 177 | ||
| 180 | static void wf_sat_release(struct kref *ref) | 178 | static void wf_sat_release(struct wf_sensor *sr) |
| 181 | { | ||
| 182 | struct wf_sat *sat = container_of(ref, struct wf_sat, ref); | ||
| 183 | |||
| 184 | if (sat->nr >= 0) | ||
| 185 | sats[sat->nr] = NULL; | ||
| 186 | kfree(sat); | ||
| 187 | } | ||
| 188 | |||
| 189 | static void wf_sat_sensor_release(struct wf_sensor *sr) | ||
| 190 | { | 179 | { |
| 191 | struct wf_sat_sensor *sens = wf_to_sat(sr); | 180 | struct wf_sat_sensor *sens = wf_to_sat(sr); |
| 192 | struct wf_sat *sat = sens->sat; | 181 | struct wf_sat *sat = sens->sat; |
| 193 | 182 | ||
| 183 | if (atomic_dec_and_test(&sat->refcnt)) { | ||
| 184 | if (sat->nr >= 0) | ||
| 185 | sats[sat->nr] = NULL; | ||
| 186 | kfree(sat); | ||
| 187 | } | ||
| 194 | kfree(sens); | 188 | kfree(sens); |
| 195 | kref_put(&sat->ref, wf_sat_release); | ||
| 196 | } | 189 | } |
| 197 | 190 | ||
| 198 | static struct wf_sensor_ops wf_sat_ops = { | 191 | static struct wf_sensor_ops wf_sat_ops = { |
| 199 | .get_value = wf_sat_sensor_get, | 192 | .get_value = wf_sat_get, |
| 200 | .release = wf_sat_sensor_release, | 193 | .release = wf_sat_release, |
| 201 | .owner = THIS_MODULE, | 194 | .owner = THIS_MODULE, |
| 202 | }; | 195 | }; |
| 203 | 196 | ||
| 197 | static struct i2c_driver wf_sat_driver; | ||
| 198 | |||
| 199 | static void wf_sat_create(struct i2c_adapter *adapter, struct device_node *dev) | ||
| 200 | { | ||
| 201 | struct i2c_board_info info; | ||
| 202 | struct i2c_client *client; | ||
| 203 | const u32 *reg; | ||
| 204 | u8 addr; | ||
| 205 | |||
| 206 | reg = of_get_property(dev, "reg", NULL); | ||
| 207 | if (reg == NULL) | ||
| 208 | return; | ||
| 209 | addr = *reg; | ||
| 210 | DBG(KERN_DEBUG "wf_sat: creating sat at address %x\n", addr); | ||
| 211 | |||
| 212 | memset(&info, 0, sizeof(struct i2c_board_info)); | ||
| 213 | info.addr = (addr >> 1) & 0x7f; | ||
| 214 | info.platform_data = dev; | ||
| 215 | strlcpy(info.type, "wf_sat", I2C_NAME_SIZE); | ||
| 216 | |||
| 217 | client = i2c_new_device(adapter, &info); | ||
| 218 | if (client == NULL) { | ||
| 219 | printk(KERN_ERR "windfarm: failed to attach smu-sat to i2c\n"); | ||
| 220 | return; | ||
| 221 | } | ||
| 222 | |||
| 223 | /* | ||
| 224 | * Let i2c-core delete that device on driver removal. | ||
| 225 | * This is safe because i2c-core holds the core_lock mutex for us. | ||
| 226 | */ | ||
| 227 | list_add_tail(&client->detected, &wf_sat_driver.clients); | ||
| 228 | } | ||
| 229 | |||
| 204 | static int wf_sat_probe(struct i2c_client *client, | 230 | static int wf_sat_probe(struct i2c_client *client, |
| 205 | const struct i2c_device_id *id) | 231 | const struct i2c_device_id *id) |
| 206 | { | 232 | { |
| 207 | struct device_node *dev = client->dev.of_node; | 233 | struct device_node *dev = client->dev.platform_data; |
| 208 | struct wf_sat *sat; | 234 | struct wf_sat *sat; |
| 209 | struct wf_sat_sensor *sens; | 235 | struct wf_sat_sensor *sens; |
| 210 | const u32 *reg; | 236 | const u32 *reg; |
| @@ -220,10 +246,9 @@ static int wf_sat_probe(struct i2c_client *client, | |||
| 220 | return -ENOMEM; | 246 | return -ENOMEM; |
| 221 | sat->nr = -1; | 247 | sat->nr = -1; |
| 222 | sat->node = of_node_get(dev); | 248 | sat->node = of_node_get(dev); |
| 223 | kref_init(&sat->ref); | 249 | atomic_set(&sat->refcnt, 0); |
| 224 | mutex_init(&sat->mutex); | 250 | mutex_init(&sat->mutex); |
| 225 | sat->i2c = client; | 251 | sat->i2c = client; |
| 226 | INIT_LIST_HEAD(&sat->sensors); | ||
| 227 | i2c_set_clientdata(client, sat); | 252 | i2c_set_clientdata(client, sat); |
| 228 | 253 | ||
| 229 | vsens[0] = vsens[1] = -1; | 254 | vsens[0] = vsens[1] = -1; |
| @@ -285,15 +310,14 @@ static int wf_sat_probe(struct i2c_client *client, | |||
| 285 | sens->index2 = -1; | 310 | sens->index2 = -1; |
| 286 | sens->shift = shift; | 311 | sens->shift = shift; |
| 287 | sens->sat = sat; | 312 | sens->sat = sat; |
| 313 | atomic_inc(&sat->refcnt); | ||
| 288 | sens->sens.ops = &wf_sat_ops; | 314 | sens->sens.ops = &wf_sat_ops; |
| 289 | sens->sens.name = (char *) (sens + 1); | 315 | sens->sens.name = (char *) (sens + 1); |
| 290 | snprintf((char *)sens->sens.name, 16, "%s-%d", name, cpu); | 316 | snprintf(sens->sens.name, 16, "%s-%d", name, cpu); |
| 291 | 317 | ||
| 292 | if (wf_register_sensor(&sens->sens)) | 318 | if (wf_register_sensor(&sens->sens)) { |
| 319 | atomic_dec(&sat->refcnt); | ||
| 293 | kfree(sens); | 320 | kfree(sens); |
| 294 | else { | ||
| 295 | list_add(&sens->link, &sat->sensors); | ||
| 296 | kref_get(&sat->ref); | ||
| 297 | } | 321 | } |
| 298 | } | 322 | } |
| 299 | 323 | ||
| @@ -312,15 +336,14 @@ static int wf_sat_probe(struct i2c_client *client, | |||
| 312 | sens->index2 = isens[core]; | 336 | sens->index2 = isens[core]; |
| 313 | sens->shift = 0; | 337 | sens->shift = 0; |
| 314 | sens->sat = sat; | 338 | sens->sat = sat; |
| 339 | atomic_inc(&sat->refcnt); | ||
| 315 | sens->sens.ops = &wf_sat_ops; | 340 | sens->sens.ops = &wf_sat_ops; |
| 316 | sens->sens.name = (char *) (sens + 1); | 341 | sens->sens.name = (char *) (sens + 1); |
| 317 | snprintf((char *)sens->sens.name, 16, "cpu-power-%d", cpu); | 342 | snprintf(sens->sens.name, 16, "cpu-power-%d", cpu); |
| 318 | 343 | ||
| 319 | if (wf_register_sensor(&sens->sens)) | 344 | if (wf_register_sensor(&sens->sens)) { |
| 345 | atomic_dec(&sat->refcnt); | ||
| 320 | kfree(sens); | 346 | kfree(sens); |
| 321 | else { | ||
| 322 | list_add(&sens->link, &sat->sensors); | ||
| 323 | kref_get(&sat->ref); | ||
| 324 | } | 347 | } |
| 325 | } | 348 | } |
| 326 | 349 | ||
| @@ -330,41 +353,61 @@ static int wf_sat_probe(struct i2c_client *client, | |||
| 330 | return 0; | 353 | return 0; |
| 331 | } | 354 | } |
| 332 | 355 | ||
| 356 | static int wf_sat_attach(struct i2c_adapter *adapter) | ||
| 357 | { | ||
| 358 | struct device_node *busnode, *dev = NULL; | ||
| 359 | struct pmac_i2c_bus *bus; | ||
| 360 | |||
| 361 | bus = pmac_i2c_adapter_to_bus(adapter); | ||
| 362 | if (bus == NULL) | ||
| 363 | return -ENODEV; | ||
| 364 | busnode = pmac_i2c_get_bus_node(bus); | ||
| 365 | |||
| 366 | while ((dev = of_get_next_child(busnode, dev)) != NULL) | ||
| 367 | if (of_device_is_compatible(dev, "smu-sat")) | ||
| 368 | wf_sat_create(adapter, dev); | ||
| 369 | return 0; | ||
| 370 | } | ||
| 371 | |||
| 333 | static int wf_sat_remove(struct i2c_client *client) | 372 | static int wf_sat_remove(struct i2c_client *client) |
| 334 | { | 373 | { |
| 335 | struct wf_sat *sat = i2c_get_clientdata(client); | 374 | struct wf_sat *sat = i2c_get_clientdata(client); |
| 336 | struct wf_sat_sensor *sens; | ||
| 337 | 375 | ||
| 338 | /* release sensors */ | 376 | /* XXX TODO */ |
| 339 | while(!list_empty(&sat->sensors)) { | ||
| 340 | sens = list_first_entry(&sat->sensors, | ||
| 341 | struct wf_sat_sensor, link); | ||
| 342 | list_del(&sens->link); | ||
| 343 | wf_unregister_sensor(&sens->sens); | ||
| 344 | } | ||
| 345 | sat->i2c = NULL; | ||
| 346 | i2c_set_clientdata(client, NULL); | ||
| 347 | kref_put(&sat->ref, wf_sat_release); | ||
| 348 | 377 | ||
| 378 | sat->i2c = NULL; | ||
| 349 | return 0; | 379 | return 0; |
| 350 | } | 380 | } |
| 351 | 381 | ||
| 352 | static const struct i2c_device_id wf_sat_id[] = { | 382 | static const struct i2c_device_id wf_sat_id[] = { |
| 353 | { "MAC,smu-sat", 0 }, | 383 | { "wf_sat", 0 }, |
| 354 | { } | 384 | { } |
| 355 | }; | 385 | }; |
| 356 | MODULE_DEVICE_TABLE(i2c, wf_sat_id); | ||
| 357 | 386 | ||
| 358 | static struct i2c_driver wf_sat_driver = { | 387 | static struct i2c_driver wf_sat_driver = { |
| 359 | .driver = { | 388 | .driver = { |
| 360 | .name = "wf_smu_sat", | 389 | .name = "wf_smu_sat", |
| 361 | }, | 390 | }, |
| 391 | .attach_adapter = wf_sat_attach, | ||
| 362 | .probe = wf_sat_probe, | 392 | .probe = wf_sat_probe, |
| 363 | .remove = wf_sat_remove, | 393 | .remove = wf_sat_remove, |
| 364 | .id_table = wf_sat_id, | 394 | .id_table = wf_sat_id, |
| 365 | }; | 395 | }; |
| 366 | 396 | ||
| 367 | module_i2c_driver(wf_sat_driver); | 397 | static int __init sat_sensors_init(void) |
| 398 | { | ||
| 399 | return i2c_add_driver(&wf_sat_driver); | ||
| 400 | } | ||
| 401 | |||
| 402 | #if 0 /* uncomment when module_exit() below is uncommented */ | ||
| 403 | static void __exit sat_sensors_exit(void) | ||
| 404 | { | ||
| 405 | i2c_del_driver(&wf_sat_driver); | ||
| 406 | } | ||
| 407 | #endif | ||
| 408 | |||
| 409 | module_init(sat_sensors_init); | ||
| 410 | /*module_exit(sat_sensors_exit); Uncomment when cleanup is implemented */ | ||
| 368 | 411 | ||
| 369 | MODULE_AUTHOR("Paul Mackerras <paulus@samba.org>"); | 412 | MODULE_AUTHOR("Paul Mackerras <paulus@samba.org>"); |
| 370 | MODULE_DESCRIPTION("SMU satellite sensors for PowerMac thermal control"); | 413 | MODULE_DESCRIPTION("SMU satellite sensors for PowerMac thermal control"); |
diff --git a/drivers/macintosh/windfarm_smu_sensors.c b/drivers/macintosh/windfarm_smu_sensors.c index 1cc4e4953d8..3c193504bb8 100644 --- a/drivers/macintosh/windfarm_smu_sensors.c +++ b/drivers/macintosh/windfarm_smu_sensors.c | |||
| @@ -18,6 +18,7 @@ | |||
| 18 | #include <asm/prom.h> | 18 | #include <asm/prom.h> |
| 19 | #include <asm/machdep.h> | 19 | #include <asm/machdep.h> |
| 20 | #include <asm/io.h> | 20 | #include <asm/io.h> |
| 21 | #include <asm/system.h> | ||
| 21 | #include <asm/sections.h> | 22 | #include <asm/sections.h> |
| 22 | #include <asm/smu.h> | 23 | #include <asm/smu.h> |
| 23 | 24 | ||
