diff options
Diffstat (limited to 'drivers/macintosh')
-rw-r--r-- | drivers/macintosh/Kconfig | 8 | ||||
-rw-r--r-- | drivers/macintosh/Makefile | 5 | ||||
-rw-r--r-- | drivers/macintosh/adb.c | 32 | ||||
-rw-r--r-- | drivers/macintosh/mac_hid.c | 6 | ||||
-rw-r--r-- | drivers/macintosh/mediabay.c | 22 | ||||
-rw-r--r-- | drivers/macintosh/smu.c | 5 | ||||
-rw-r--r-- | drivers/macintosh/therm_adt746x.c | 13 | ||||
-rw-r--r-- | drivers/macintosh/therm_pm72.c | 31 | ||||
-rw-r--r-- | drivers/macintosh/windfarm_lm75_sensor.c | 6 | ||||
-rw-r--r-- | drivers/macintosh/windfarm_max6690_sensor.c | 20 | ||||
-rw-r--r-- | drivers/macintosh/windfarm_pm112.c | 3 | ||||
-rw-r--r-- | drivers/macintosh/windfarm_pm121.c | 1040 | ||||
-rw-r--r-- | drivers/macintosh/windfarm_pm81.c | 4 | ||||
-rw-r--r-- | drivers/macintosh/windfarm_pm91.c | 3 | ||||
-rw-r--r-- | drivers/macintosh/windfarm_smu_controls.c | 4 | ||||
-rw-r--r-- | drivers/macintosh/windfarm_smu_sat.c | 10 |
16 files changed, 1150 insertions, 62 deletions
diff --git a/drivers/macintosh/Kconfig b/drivers/macintosh/Kconfig index 77f50b63a97..b52659620d5 100644 --- a/drivers/macintosh/Kconfig +++ b/drivers/macintosh/Kconfig @@ -234,6 +234,14 @@ config WINDFARM_PM112 which are the recent dual and quad G5 machines using the 970MP dual-core processor. +config WINDFARM_PM121 + tristate "Support for thermal management on PowerMac12,1" + depends on WINDFARM && I2C && PMAC_SMU + select I2C_POWERMAC + help + This driver provides thermal control for the PowerMac12,1 + which is the iMac G5 (iSight). + config ANSLCD tristate "Support for ANS LCD display" depends on ADB_CUDA && PPC_PMAC diff --git a/drivers/macintosh/Makefile b/drivers/macintosh/Makefile index 2dfc3f4eaf4..e3132efa17c 100644 --- a/drivers/macintosh/Makefile +++ b/drivers/macintosh/Makefile @@ -42,4 +42,9 @@ obj-$(CONFIG_WINDFARM_PM112) += windfarm_pm112.o windfarm_smu_sat.o \ windfarm_smu_sensors.o \ windfarm_max6690_sensor.o \ windfarm_lm75_sensor.o windfarm_pid.o +obj-$(CONFIG_WINDFARM_PM121) += windfarm_pm121.o windfarm_smu_sat.o \ + windfarm_smu_controls.o \ + windfarm_smu_sensors.o \ + windfarm_max6690_sensor.o \ + windfarm_lm75_sensor.o windfarm_pid.o obj-$(CONFIG_PMAC_RACKMETER) += rack-meter.o diff --git a/drivers/macintosh/adb.c b/drivers/macintosh/adb.c index 28958101061..dbaad39020a 100644 --- a/drivers/macintosh/adb.c +++ b/drivers/macintosh/adb.c @@ -37,9 +37,9 @@ #include <linux/device.h> #include <linux/kthread.h> #include <linux/platform_device.h> +#include <linux/mutex.h> #include <asm/uaccess.h> -#include <asm/semaphore.h> #ifdef CONFIG_PPC #include <asm/prom.h> #include <asm/machdep.h> @@ -102,7 +102,7 @@ static struct adb_handler { } adb_handler[16]; /* - * The adb_handler_sem mutex protects all accesses to the original_address + * The adb_handler_mutex mutex protects all accesses to the original_address * and handler_id fields of adb_handler[i] for all i, and changes to the * handler field. * Accesses to the handler field are protected by the adb_handler_lock @@ -110,7 +110,7 @@ static struct adb_handler { * time adb_unregister returns, we know that the old handler isn't being * called. */ -static DECLARE_MUTEX(adb_handler_sem); +static DEFINE_MUTEX(adb_handler_mutex); static DEFINE_RWLOCK(adb_handler_lock); #if 0 @@ -334,7 +334,7 @@ int __init adb_init(void) return 0; } -__initcall(adb_init); +device_initcall(adb_init); static int do_adb_reset_bus(void) @@ -355,7 +355,7 @@ do_adb_reset_bus(void) msleep(500); } - down(&adb_handler_sem); + mutex_lock(&adb_handler_mutex); write_lock_irq(&adb_handler_lock); memset(adb_handler, 0, sizeof(adb_handler)); write_unlock_irq(&adb_handler_lock); @@ -376,7 +376,7 @@ do_adb_reset_bus(void) if (adb_controller->autopoll) adb_controller->autopoll(autopoll_devs); } - up(&adb_handler_sem); + mutex_unlock(&adb_handler_mutex); blocking_notifier_call_chain(&adb_client_list, ADB_MSG_POST_RESET, NULL); @@ -454,7 +454,7 @@ adb_register(int default_id, int handler_id, struct adb_ids *ids, { int i; - down(&adb_handler_sem); + mutex_lock(&adb_handler_mutex); ids->nids = 0; for (i = 1; i < 16; i++) { if ((adb_handler[i].original_address == default_id) && @@ -472,7 +472,7 @@ adb_register(int default_id, int handler_id, struct adb_ids *ids, ids->id[ids->nids++] = i; } } - up(&adb_handler_sem); + mutex_unlock(&adb_handler_mutex); return ids->nids; } @@ -481,7 +481,7 @@ adb_unregister(int index) { int ret = -ENODEV; - down(&adb_handler_sem); + mutex_lock(&adb_handler_mutex); write_lock_irq(&adb_handler_lock); if (adb_handler[index].handler) { while(adb_handler[index].busy) { @@ -493,7 +493,7 @@ adb_unregister(int index) adb_handler[index].handler = NULL; } write_unlock_irq(&adb_handler_lock); - up(&adb_handler_sem); + mutex_unlock(&adb_handler_mutex); return ret; } @@ -557,19 +557,19 @@ adb_try_handler_change(int address, int new_id) { int ret; - down(&adb_handler_sem); + mutex_lock(&adb_handler_mutex); ret = try_handler_change(address, new_id); - up(&adb_handler_sem); + mutex_unlock(&adb_handler_mutex); return ret; } int adb_get_infos(int address, int *original_address, int *handler_id) { - down(&adb_handler_sem); + mutex_lock(&adb_handler_mutex); *original_address = adb_handler[address].original_address; *handler_id = adb_handler[address].handler_id; - up(&adb_handler_sem); + mutex_unlock(&adb_handler_mutex); return (*original_address != 0); } @@ -628,10 +628,10 @@ do_adb_query(struct adb_request *req) case ADB_QUERY_GETDEVINFO: if (req->nbytes < 3) break; - down(&adb_handler_sem); + mutex_lock(&adb_handler_mutex); req->reply[0] = adb_handler[req->data[2]].original_address; req->reply[1] = adb_handler[req->data[2]].handler_id; - up(&adb_handler_sem); + mutex_unlock(&adb_handler_mutex); req->complete = 1; req->reply_len = 2; adb_write_done(req); diff --git a/drivers/macintosh/mac_hid.c b/drivers/macintosh/mac_hid.c index 89302309da9..cc9f27514ae 100644 --- a/drivers/macintosh/mac_hid.c +++ b/drivers/macintosh/mac_hid.c @@ -103,6 +103,9 @@ int mac_hid_mouse_emulate_buttons(int caller, unsigned int keycode, int down) return 0; } +static struct lock_class_key emumousebtn_event_class; +static struct lock_class_key emumousebtn_mutex_class; + static int emumousebtn_input_register(void) { int ret; @@ -111,6 +114,9 @@ static int emumousebtn_input_register(void) if (!emumousebtn) return -ENOMEM; + lockdep_set_class(&emumousebtn->event_lock, &emumousebtn_event_class); + lockdep_set_class(&emumousebtn->mutex, &emumousebtn_mutex_class); + emumousebtn->name = "Macintosh mouse button emulation"; emumousebtn->id.bustype = BUS_ADB; emumousebtn->id.vendor = 0x0001; diff --git a/drivers/macintosh/mediabay.c b/drivers/macintosh/mediabay.c index bd8a1d14b45..818aba36854 100644 --- a/drivers/macintosh/mediabay.c +++ b/drivers/macintosh/mediabay.c @@ -79,11 +79,12 @@ struct media_bay_info { int sleeping; struct semaphore lock; #ifdef CONFIG_BLK_DEV_IDE_PMAC + ide_hwif_t *cd_port; void __iomem *cd_base; int cd_irq; int cd_retry; #endif -#if defined(CONFIG_BLK_DEV_IDE_PMAC) || defined(CONFIG_MAC_FLOPPY) +#if defined(CONFIG_BLK_DEV_IDE_PMAC) int cd_index; #endif }; @@ -416,6 +417,7 @@ static void poll_media_bay(struct media_bay_info* bay) } } +#ifdef CONFIG_BLK_DEV_IDE_PMAC int check_media_bay(struct device_node *which_bay, int what) { int i; @@ -431,7 +433,6 @@ int check_media_bay(struct device_node *which_bay, int what) } EXPORT_SYMBOL(check_media_bay); -#ifdef CONFIG_BLK_DEV_IDE_PMAC int check_media_bay_by_base(unsigned long base, int what) { int i; @@ -448,7 +449,7 @@ int check_media_bay_by_base(unsigned long base, int what) } int media_bay_set_ide_infos(struct device_node* which_bay, unsigned long base, - int irq, int index) + int irq, ide_hwif_t *hwif) { int i; @@ -456,10 +457,11 @@ int media_bay_set_ide_infos(struct device_node* which_bay, unsigned long base, struct media_bay_info* bay = &media_bays[i]; if (bay->mdev && which_bay == bay->mdev->ofdev.node) { - int timeout = 5000; + int timeout = 5000, index = hwif->index; down(&bay->lock); + bay->cd_port = hwif; bay->cd_base = (void __iomem *) base; bay->cd_irq = irq; @@ -551,15 +553,11 @@ static void media_bay_step(int i) bay->timer = 0; bay->state = mb_up; if (bay->cd_index < 0) { - hw_regs_t hw; - printk("mediabay %d, registering IDE...\n", i); pmu_suspend(); - ide_init_hwif_ports(&hw, (unsigned long) bay->cd_base, (unsigned long) 0, NULL); - hw.irq = bay->cd_irq; - hw.chipset = ide_pmac; - bay->cd_index = - ide_register_hw(&hw, NULL, NULL); + ide_port_scan(bay->cd_port); + if (bay->cd_port->present) + bay->cd_index = bay->cd_port->index; pmu_resume(); } if (bay->cd_index == -1) { @@ -589,7 +587,7 @@ static void media_bay_step(int i) if (bay->cd_index >= 0) { printk(KERN_DEBUG "Unregistering mb %d ide, index:%d\n", i, bay->cd_index); - ide_unregister(bay->cd_index, 1, 1); + ide_port_unregister_devices(bay->cd_port); bay->cd_index = -1; } if (bay->cd_retry) { diff --git a/drivers/macintosh/smu.c b/drivers/macintosh/smu.c index 77ad192962c..d86d57af282 100644 --- a/drivers/macintosh/smu.c +++ b/drivers/macintosh/smu.c @@ -483,12 +483,15 @@ int __init smu_init (void) if (smu_cmdbuf_abs == 0) { printk(KERN_ERR "SMU: Command buffer not allocated !\n"); + of_node_put(np); return -EINVAL; } smu = alloc_bootmem(sizeof(struct smu_device)); - if (smu == NULL) + if (smu == NULL) { + of_node_put(np); return -ENOMEM; + } memset(smu, 0, sizeof(*smu)); spin_lock_init(&smu->lock); diff --git a/drivers/macintosh/therm_adt746x.c b/drivers/macintosh/therm_adt746x.c index 54f4942a296..5366dc93fb3 100644 --- a/drivers/macintosh/therm_adt746x.c +++ b/drivers/macintosh/therm_adt746x.c @@ -562,18 +562,24 @@ thermostat_init(void) therm_type = ADT7460; else if (of_device_is_compatible(np, "adt7467")) therm_type = ADT7467; - else + else { + of_node_put(np); return -ENODEV; + } prop = of_get_property(np, "hwsensor-params-version", NULL); printk(KERN_INFO "adt746x: version %d (%ssupported)\n", *prop, (*prop == 1)?"":"un"); - if (*prop != 1) + if (*prop != 1) { + of_node_put(np); return -ENODEV; + } prop = of_get_property(np, "reg", NULL); - if (!prop) + if (!prop) { + of_node_put(np); return -ENODEV; + } /* look for bus either by path or using "reg" */ if (strstr(np->full_name, "/i2c-bus@") != NULL) { @@ -610,6 +616,7 @@ thermostat_init(void) if (of_dev == NULL) { printk(KERN_ERR "Can't register temperatures device !\n"); + of_node_put(np); return -ENODEV; } diff --git a/drivers/macintosh/therm_pm72.c b/drivers/macintosh/therm_pm72.c index 1e0a69a5e81..ddfb426a9ab 100644 --- a/drivers/macintosh/therm_pm72.c +++ b/drivers/macintosh/therm_pm72.c @@ -122,6 +122,7 @@ #include <linux/kmod.h> #include <linux/i2c.h> #include <linux/kthread.h> +#include <linux/mutex.h> #include <asm/prom.h> #include <asm/machdep.h> #include <asm/io.h> @@ -169,7 +170,7 @@ static int rackmac; static s32 dimm_output_clamp; static int fcu_rpm_shift; static int fcu_tickle_ticks; -static DECLARE_MUTEX(driver_lock); +static DEFINE_MUTEX(driver_lock); /* * We have 3 types of CPU PID control. One is "split" old style control @@ -729,9 +730,9 @@ static void fetch_cpu_pumps_minmax(void) static ssize_t show_##name(struct device *dev, struct device_attribute *attr, char *buf) \ { \ ssize_t r; \ - down(&driver_lock); \ + mutex_lock(&driver_lock); \ r = sprintf(buf, "%d.%03d", FIX32TOPRINT(data)); \ - up(&driver_lock); \ + mutex_unlock(&driver_lock); \ return r; \ } #define BUILD_SHOW_FUNC_INT(name, data) \ @@ -1803,11 +1804,11 @@ static int main_control_loop(void *x) { DBG("main_control_loop started\n"); - down(&driver_lock); + mutex_lock(&driver_lock); if (start_fcu() < 0) { printk(KERN_ERR "kfand: failed to start FCU\n"); - up(&driver_lock); + mutex_unlock(&driver_lock); goto out; } @@ -1822,14 +1823,14 @@ static int main_control_loop(void *x) fcu_tickle_ticks = FCU_TICKLE_TICKS; - up(&driver_lock); + mutex_unlock(&driver_lock); while (state == state_attached) { unsigned long elapsed, start; start = jiffies; - down(&driver_lock); + mutex_lock(&driver_lock); /* Tickle the FCU just in case */ if (--fcu_tickle_ticks < 0) { @@ -1861,7 +1862,7 @@ static int main_control_loop(void *x) do_monitor_slots(&slots_state); else do_monitor_drives(&drives_state); - up(&driver_lock); + mutex_unlock(&driver_lock); if (critical_state == 1) { printk(KERN_WARNING "Temperature control detected a critical condition\n"); @@ -2019,13 +2020,13 @@ static void detach_fcu(void) */ static int therm_pm72_attach(struct i2c_adapter *adapter) { - down(&driver_lock); + mutex_lock(&driver_lock); /* Check state */ if (state == state_detached) state = state_attaching; if (state != state_attaching) { - up(&driver_lock); + mutex_unlock(&driver_lock); return 0; } @@ -2054,7 +2055,7 @@ static int therm_pm72_attach(struct i2c_adapter *adapter) state = state_attached; start_control_loops(); } - up(&driver_lock); + mutex_unlock(&driver_lock); return 0; } @@ -2065,16 +2066,16 @@ static int therm_pm72_attach(struct i2c_adapter *adapter) */ static int therm_pm72_detach(struct i2c_adapter *adapter) { - down(&driver_lock); + mutex_lock(&driver_lock); if (state != state_detached) state = state_detaching; /* Stop control loops if any */ DBG("stopping control loops\n"); - up(&driver_lock); + mutex_unlock(&driver_lock); stop_control_loops(); - down(&driver_lock); + mutex_lock(&driver_lock); if (u3_0 != NULL && !strcmp(adapter->name, "u3 0")) { DBG("lost U3-0, disposing control loops\n"); @@ -2090,7 +2091,7 @@ static int therm_pm72_detach(struct i2c_adapter *adapter) if (u3_0 == NULL && u3_1 == NULL) state = state_detached; - up(&driver_lock); + mutex_unlock(&driver_lock); return 0; } diff --git a/drivers/macintosh/windfarm_lm75_sensor.c b/drivers/macintosh/windfarm_lm75_sensor.c index 7e10c3ab4d5..b92b959fe16 100644 --- a/drivers/macintosh/windfarm_lm75_sensor.c +++ b/drivers/macintosh/windfarm_lm75_sensor.c @@ -127,6 +127,12 @@ static struct wf_lm75_sensor *wf_lm75_create(struct i2c_adapter *adapter, */ if (!strcmp(loc, "Hard drive") || !strcmp(loc, "DRIVE BAY")) lm->sens.name = "hd-temp"; + else if (!strcmp(loc, "Incoming Air Temp")) + lm->sens.name = "incoming-air-temp"; + else if (!strcmp(loc, "ODD Temp")) + lm->sens.name = "optical-drive-temp"; + else if (!strcmp(loc, "HD Temp")) + lm->sens.name = "hard-drive-temp"; else goto fail; diff --git a/drivers/macintosh/windfarm_max6690_sensor.c b/drivers/macintosh/windfarm_max6690_sensor.c index 5f03aab9fb5..e207a90d6b2 100644 --- a/drivers/macintosh/windfarm_max6690_sensor.c +++ b/drivers/macintosh/windfarm_max6690_sensor.c @@ -77,18 +77,28 @@ static struct wf_sensor_ops wf_max6690_ops = { .owner = THIS_MODULE, }; -static void wf_max6690_create(struct i2c_adapter *adapter, u8 addr) +static void wf_max6690_create(struct i2c_adapter *adapter, u8 addr, + const char *loc) { struct wf_6690_sensor *max; - char *name = "backside-temp"; + char *name; max = kzalloc(sizeof(struct wf_6690_sensor), GFP_KERNEL); if (max == NULL) { printk(KERN_ERR "windfarm: Couldn't create MAX6690 sensor %s: " - "no memory\n", name); + "no memory\n", loc); return; } + if (!strcmp(loc, "BACKSIDE")) + name = "backside-temp"; + else if (!strcmp(loc, "NB Ambient")) + name = "north-bridge-temp"; + else if (!strcmp(loc, "GPU Ambient")) + name = "gpu-temp"; + else + goto fail; + max->sens.ops = &wf_max6690_ops; max->sens.name = name; max->i2c.addr = addr >> 1; @@ -138,9 +148,7 @@ static int wf_max6690_attach(struct i2c_adapter *adapter) if (loc == NULL || addr == 0) continue; printk("found max6690, loc=%s addr=0x%02x\n", loc, addr); - if (strcmp(loc, "BACKSIDE")) - continue; - wf_max6690_create(adapter, addr); + wf_max6690_create(adapter, addr, loc); } return 0; diff --git a/drivers/macintosh/windfarm_pm112.c b/drivers/macintosh/windfarm_pm112.c index b3fbb45bc90..73d695dc9e5 100644 --- a/drivers/macintosh/windfarm_pm112.c +++ b/drivers/macintosh/windfarm_pm112.c @@ -668,7 +668,7 @@ static struct platform_driver wf_pm112_driver = { .remove = __devexit_p(wf_pm112_remove), .driver = { .name = "windfarm", - .bus = &platform_bus_type, + .owner = THIS_MODULE, }, }; @@ -711,3 +711,4 @@ module_exit(wf_pm112_exit); MODULE_AUTHOR("Paul Mackerras <paulus@samba.org>"); MODULE_DESCRIPTION("Thermal control for PowerMac11,2"); MODULE_LICENSE("GPL"); +MODULE_ALIAS("platform:windfarm"); diff --git a/drivers/macintosh/windfarm_pm121.c b/drivers/macintosh/windfarm_pm121.c new file mode 100644 index 00000000000..66ec4fb115b --- /dev/null +++ b/drivers/macintosh/windfarm_pm121.c @@ -0,0 +1,1040 @@ +/* + * Windfarm PowerMac thermal control. iMac G5 iSight + * + * (c) Copyright 2007 Étienne Bersac <bersace@gmail.com> + * + * Bits & pieces from windfarm_pm81.c by (c) Copyright 2005 Benjamin + * Herrenschmidt, IBM Corp. <benh@kernel.crashing.org> + * + * Released under the term of the GNU GPL v2. + * + * + * + * PowerMac12,1 + * ============ + * + * + * The algorithm used is the PID control algorithm, used the same way + * the published Darwin code does, using the same values that are + * present in the Darwin 8.10 snapshot property lists (note however + * that none of the code has been re-used, it's a complete + * re-implementation + * + * There is two models using PowerMac12,1. Model 2 is iMac G5 iSight + * 17" while Model 3 is iMac G5 20". They do have both the same + * controls with a tiny difference. The control-ids of hard-drive-fan + * and cpu-fan is swapped. + * + * + * Target Correction : + * + * controls have a target correction calculated as : + * + * new_min = ((((average_power * slope) >> 16) + offset) >> 16) + min_value + * new_value = max(new_value, max(new_min, 0)) + * + * OD Fan control correction. + * + * # model_id: 2 + * offset : -19563152 + * slope : 1956315 + * + * # model_id: 3 + * offset : -15650652 + * slope : 1565065 + * + * HD Fan control correction. + * + * # model_id: 2 + * offset : -15650652 + * slope : 1565065 + * + * # model_id: 3 + * offset : -19563152 + * slope : 1956315 + * + * CPU Fan control correction. + * + * # model_id: 2 + * offset : -25431900 + * slope : 2543190 + * + * # model_id: 3 + * offset : -15650652 + * slope : 1565065 + * + * + * Target rubber-banding : + * + * Some controls have a target correction which depends on another + * control value. The correction is computed in the following way : + * + * new_min = ref_value * slope + offset + * + * ref_value is the value of the reference control. If new_min is + * greater than 0, then we correct the target value using : + * + * new_target = max (new_target, new_min >> 16) + * + * + * # model_id : 2 + * control : cpu-fan + * ref : optical-drive-fan + * offset : -15650652 + * slope : 1565065 + * + * # model_id : 3 + * control : optical-drive-fan + * ref : hard-drive-fan + * offset : -32768000 + * slope : 65536 + * + * + * In order to have the moste efficient correction with those + * dependencies, we must trigger HD loop before OD loop before CPU + * loop. + * + * + * The various control loops found in Darwin config file are: + * + * HD Fan control loop. + * + * # model_id: 2 + * control : hard-drive-fan + * sensor : hard-drive-temp + * PID params : G_d = 0x00000000 + * G_p = 0x002D70A3 + * G_r = 0x00019999 + * History = 2 entries + * Input target = 0x370000 + * Interval = 5s + * + * # model_id: 3 + * control : hard-drive-fan + * sensor : hard-drive-temp + * PID params : G_d = 0x00000000 + * G_p = 0x002170A3 + * G_r = 0x00019999 + * History = 2 entries + * Input target = 0x370000 + * Interval = 5s + * + * OD Fan control loop. + * + * # model_id: 2 + * control : optical-drive-fan + * sensor : optical-drive-temp + * PID params : G_d = 0x00000000 + * G_p = 0x001FAE14 + * G_r = 0x00019999 + * History = 2 entries + * Input target = 0x320000 + * Interval = 5s + * + * # model_id: 3 + * control : optical-drive-fan + * sensor : optical-drive-temp + * PID params : G_d = 0x00000000 + * G_p = 0x001FAE14 + * G_r = 0x00019999 + * History = 2 entries + * Input target = 0x320000 + * Interval = 5s + * + * GPU Fan control loop. + * + * # model_id: 2 + * control : hard-drive-fan + * sensor : gpu-temp + * PID params : G_d = 0x00000000 + * G_p = 0x002A6666 + * G_r = 0x00019999 + * History = 2 entries + * Input target = 0x5A0000 + * Interval = 5s + * + * # model_id: 3 + * control : cpu-fan + * sensor : gpu-temp + * PID params : G_d = 0x00000000 + * G_p = 0x0010CCCC + * G_r = 0x00019999 + * History = 2 entries + * Input target = 0x500000 + * Interval = 5s + * + * KODIAK (aka northbridge) Fan control loop. + * + * # model_id: 2 + * control : optical-drive-fan + * sensor : north-bridge-temp + * PID params : G_d = 0x00000000 + * G_p = 0x003BD70A + * G_r = 0x00019999 + * History = 2 entries + * Input target = 0x550000 + * Interval = 5s + * + * # model_id: 3 + * control : hard-drive-fan + * sensor : north-bridge-temp + * PID params : G_d = 0x00000000 + * G_p = 0x0030F5C2 + * G_r = 0x00019999 + * History = 2 entries + * Input target = 0x550000 + * Interval = 5s + * + * CPU Fan control loop. + * + * control : cpu-fan + * sensors : cpu-temp, cpu-power + * PID params : from SDB partition + * + * + * CPU Slew control loop. + * + * control : cpufreq-clamp + * sensor : cpu-temp + * + */ + +#undef DEBUG + +#include <linux/types.h> +#include <linux/errno.h> +#include <linux/kernel.h> +#include <linux/delay.h> +#include <linux/slab.h> +#include <linux/init.h> +#include <linux/spinlock.h> +#include <linux/wait.h> +#include <linux/kmod.h> +#include <linux/device.h> +#include <linux/platform_device.h> +#include <asm/prom.h> +#include <asm/machdep.h> +#include <asm/io.h> +#include <asm/system.h> +#include <asm/sections.h> +#include <asm/smu.h> + +#include "windfarm.h" +#include "windfarm_pid.h" + +#define VERSION "0.3" + +static int pm121_mach_model; /* machine model id */ + +/* Controls & sensors */ +static struct wf_sensor *sensor_cpu_power; +static struct wf_sensor *sensor_cpu_temp; +static struct wf_sensor *sensor_cpu_voltage; +static struct wf_sensor *sensor_cpu_current; +static struct wf_sensor *sensor_gpu_temp; +static struct wf_sensor *sensor_north_bridge_temp; +static struct wf_sensor *sensor_hard_drive_temp; +static struct wf_sensor *sensor_optical_drive_temp; +static struct wf_sensor *sensor_incoming_air_temp; /* unused ! */ + +enum { + FAN_CPU, + FAN_HD, + FAN_OD, + CPUFREQ, + N_CONTROLS +}; +static struct wf_control *controls[N_CONTROLS] = {}; + +/* Set to kick the control loop into life */ +static int pm121_all_controls_ok, pm121_all_sensors_ok, pm121_started; + +enum { + FAILURE_FAN = 1 << 0, + FAILURE_SENSOR = 1 << 1, + FAILURE_OVERTEMP = 1 << 2 +}; + +/* All sys loops. Note the HD before the OD loop in order to have it + run before. */ +enum { + LOOP_GPU, /* control = hd or cpu, but luckily, + it doesn't matter */ + LOOP_HD, /* control = hd */ + LOOP_KODIAK, /* control = hd or od */ + LOOP_OD, /* control = od */ + N_LOOPS +}; + +static const char *loop_names[N_LOOPS] = { + "GPU", + "HD", + "KODIAK", + "OD", +}; + +#define PM121_NUM_CONFIGS 2 + +static unsigned int pm121_failure_state; +static int pm121_readjust, pm121_skipping; +static s32 average_power; + +struct pm121_correction { + int offset; + int slope; +}; + +static struct pm121_correction corrections[N_CONTROLS][PM121_NUM_CONFIGS] = { + /* FAN_OD */ + { + /* MODEL 2 */ + { .offset = -19563152, + .slope = 1956315 + }, + /* MODEL 3 */ + { .offset = -15650652, + .slope = 1565065 + }, + }, + /* FAN_HD */ + { + /* MODEL 2 */ + { .offset = -15650652, + .slope = 1565065 + }, + /* MODEL 3 */ + { .offset = -19563152, + .slope = 1956315 + }, + }, + /* FAN_CPU */ + { + /* MODEL 2 */ + { .offset = -25431900, + .slope = 2543190 + }, + /* MODEL 3 */ + { .offset = -15650652, + .slope = 1565065 + }, + }, + /* CPUFREQ has no correction (and is not implemented at all) */ +}; + +struct pm121_connection { + unsigned int control_id; + unsigned int ref_id; + struct pm121_correction correction; +}; + +static struct pm121_connection pm121_connections[] = { + /* MODEL 2 */ + { .control_id = FAN_CPU, + .ref_id = FAN_OD, + { .offset = -32768000, + .slope = 65536 + } + }, + /* MODEL 3 */ + { .control_id = FAN_OD, + .ref_id = FAN_HD, + { .offset = -32768000, + .slope = 65536 + } + }, +}; + +/* pointer to the current model connection */ +static struct pm121_connection *pm121_connection; + +/* + * ****** System Fans Control Loop ****** + * + */ + +/* Since each loop handles only one control and we want to avoid + * writing virtual control, we store the control correction with the + * loop params. Some data are not set, there are common to all loop + * and thus, hardcoded. + */ +struct pm121_sys_param { + /* purely informative since we use mach_model-2 as index */ + int model_id; + struct wf_sensor **sensor; /* use sensor_id instead ? */ + s32 gp, itarget; + unsigned int control_id; +}; + +static struct pm121_sys_param +pm121_sys_all_params[N_LOOPS][PM121_NUM_CONFIGS] = { + /* GPU Fan control loop */ + { + { .model_id = 2, + .sensor = &sensor_gpu_temp, + .gp = 0x002A6666, + .itarget = 0x5A0000, + .control_id = FAN_HD, + }, + { .model_id = 3, + .sensor = &sensor_gpu_temp, + .gp = 0x0010CCCC, + .itarget = 0x500000, + .control_id = FAN_CPU, + }, + }, + /* HD Fan control loop */ + { + { .model_id = 2, + .sensor = &sensor_hard_drive_temp, + .gp = 0x002D70A3, + .itarget = 0x370000, + .control_id = FAN_HD, + }, + { .model_id = 3, + .sensor = &sensor_hard_drive_temp, + .gp = 0x002170A3, + .itarget = 0x370000, + .control_id = FAN_HD, + }, + }, + /* KODIAK Fan control loop */ + { + { .model_id = 2, + .sensor = &sensor_north_bridge_temp, + .gp = 0x003BD70A, + .itarget = 0x550000, + .control_id = FAN_OD, + }, + { .model_id = 3, + .sensor = &sensor_north_bridge_temp, + .gp = 0x0030F5C2, + .itarget = 0x550000, + .control_id = FAN_HD, + }, + }, + /* OD Fan control loop */ + { + { .model_id = 2, + .sensor = &sensor_optical_drive_temp, + .gp = 0x001FAE14, + .itarget = 0x320000, + .control_id = FAN_OD, + }, + { .model_id = 3, + .sensor = &sensor_optical_drive_temp, + .gp = 0x001FAE14, + .itarget = 0x320000, + .control_id = FAN_OD, + }, + }, +}; + +/* the hardcoded values */ +#define PM121_SYS_GD 0x00000000 +#define PM121_SYS_GR 0x00019999 +#define PM121_SYS_HISTORY_SIZE 2 +#define PM121_SYS_INTERVAL 5 + +/* State data used by the system fans control loop + */ +struct pm121_sys_state { + int ticks; + s32 setpoint; + struct wf_pid_state pid; +}; + +struct pm121_sys_state *pm121_sys_state[N_LOOPS] = {}; + +/* + * ****** CPU Fans Control Loop ****** + * + */ + +#define PM121_CPU_INTERVAL 1 + +/* State data used by the cpu fans control loop + */ +struct pm121_cpu_state { + int ticks; + s32 setpoint; + struct wf_cpu_pid_state pid; +}; + +static struct pm121_cpu_state *pm121_cpu_state; + + + +/* + * ***** Implementation ***** + * + */ + +/* correction the value using the output-low-bound correction algo */ +static s32 pm121_correct(s32 new_setpoint, + unsigned int control_id, + s32 min) +{ + s32 new_min; + struct pm121_correction *correction; + correction = &corrections[control_id][pm121_mach_model - 2]; + + new_min = (average_power * correction->slope) >> 16; + new_min += correction->offset; + new_min = (new_min >> 16) + min; + + return max(new_setpoint, max(new_min, 0)); +} + +static s32 pm121_connect(unsigned int control_id, s32 setpoint) +{ + s32 new_min, value, new_setpoint; + + if (pm121_connection->control_id == control_id) { + controls[control_id]->ops->get_value(controls[control_id], + &value); + new_min = value * pm121_connection->correction.slope; + new_min += pm121_connection->correction.offset; + if (new_min > 0) { + new_setpoint = max(setpoint, (new_min >> 16)); + if (new_setpoint != setpoint) { + pr_debug("pm121: %s depending on %s, " + "corrected from %d to %d RPM\n", + controls[control_id]->name, + controls[pm121_connection->ref_id]->name, + (int) setpoint, (int) new_setpoint); + } + } else + new_setpoint = setpoint; + } + /* no connection */ + else + new_setpoint = setpoint; + + return new_setpoint; +} + +/* FAN LOOPS */ +static void pm121_create_sys_fans(int loop_id) +{ + struct pm121_sys_param *param = NULL; + struct wf_pid_param pid_param; + struct wf_control *control = NULL; + int i; + + /* First, locate the params for this model */ + for (i = 0; i < PM121_NUM_CONFIGS; i++) { + if (pm121_sys_all_params[loop_id][i].model_id == pm121_mach_model) { + param = &(pm121_sys_all_params[loop_id][i]); + break; + } + } + + /* No params found, put fans to max */ + if (param == NULL) { + printk(KERN_WARNING "pm121: %s fan config not found " + " for this machine model\n", + loop_names[loop_id]); + goto fail; + } + + control = controls[param->control_id]; + + /* Alloc & initialize state */ + pm121_sys_state[loop_id] = kmalloc(sizeof(struct pm121_sys_state), + GFP_KERNEL); + if (pm121_sys_state[loop_id] == NULL) { + printk(KERN_WARNING "pm121: Memory allocation error\n"); + goto fail; + } + pm121_sys_state[loop_id]->ticks = 1; + + /* Fill PID params */ + pid_param.gd = PM121_SYS_GD; + pid_param.gp = param->gp; + pid_param.gr = PM121_SYS_GR; + pid_param.interval = PM121_SYS_INTERVAL; + pid_param.history_len = PM121_SYS_HISTORY_SIZE; + pid_param.itarget = param->itarget; + pid_param.min = control->ops->get_min(control); + pid_param.max = control->ops->get_max(control); + + wf_pid_init(&pm121_sys_state[loop_id]->pid, &pid_param); + + pr_debug("pm121: %s Fan control loop initialized.\n" + " itarged=%d.%03d, min=%d RPM, max=%d RPM\n", + loop_names[loop_id], FIX32TOPRINT(pid_param.itarget), + pid_param.min, pid_param.max); + return; + + fail: + /* note that this is not optimal since another loop may still + control the same control */ + printk(KERN_WARNING "pm121: failed to set up %s loop " + "setting \"%s\" to max speed.\n", + loop_names[loop_id], control->name); + + if (control) + wf_control_set_max(control); +} + +static void pm121_sys_fans_tick(int loop_id) +{ + struct pm121_sys_param *param; + struct pm121_sys_state *st; + struct wf_sensor *sensor; + struct wf_control *control; + s32 temp, new_setpoint; + int rc; + + param = &(pm121_sys_all_params[loop_id][pm121_mach_model-2]); + st = pm121_sys_state[loop_id]; + sensor = *(param->sensor); + control = controls[param->control_id]; + + if (--st->ticks != 0) { + if (pm121_readjust) + goto readjust; + return; + } + st->ticks = PM121_SYS_INTERVAL; + + rc = sensor->ops->get_value(sensor, &temp); + if (rc) { + printk(KERN_WARNING "windfarm: %s sensor error %d\n", + sensor->name, rc); + pm121_failure_state |= FAILURE_SENSOR; + return; + } + + pr_debug("pm121: %s Fan tick ! %s: %d.%03d\n", + loop_names[loop_id], sensor->name, + FIX32TOPRINT(temp)); + + new_setpoint = wf_pid_run(&st->pid, temp); + + /* correction */ + new_setpoint = pm121_correct(new_setpoint, + param->control_id, + st->pid.param.min); + /* linked corretion */ + new_setpoint = pm121_connect(param->control_id, new_setpoint); + + if (new_setpoint == st->setpoint) + return; + st->setpoint = new_setpoint; + pr_debug("pm121: %s corrected setpoint: %d RPM\n", + control->name, (int)new_setpoint); + readjust: + if (control && pm121_failure_state == 0) { + rc = control->ops->set_value(control, st->setpoint); + if (rc) { + printk(KERN_WARNING "windfarm: %s fan error %d\n", + control->name, rc); + pm121_failure_state |= FAILURE_FAN; + } + } +} + + +/* CPU LOOP */ +static void pm121_create_cpu_fans(void) +{ + struct wf_cpu_pid_param pid_param; + const struct smu_sdbp_header *hdr; + struct smu_sdbp_cpupiddata *piddata; + struct smu_sdbp_fvt *fvt; + struct wf_control *fan_cpu; + s32 tmax, tdelta, maxpow, powadj; + + fan_cpu = controls[FAN_CPU]; + + /* First, locate the PID params in SMU SBD */ + hdr = smu_get_sdb_partition(SMU_SDB_CPUPIDDATA_ID, NULL); + if (hdr == 0) { + printk(KERN_WARNING "pm121: CPU PID fan config not found.\n"); + goto fail; + } + piddata = (struct smu_sdbp_cpupiddata *)&hdr[1]; + + /* Get the FVT params for operating point 0 (the only supported one + * for now) in order to get tmax + */ + hdr = smu_get_sdb_partition(SMU_SDB_FVT_ID, NULL); + if (hdr) { + fvt = (struct smu_sdbp_fvt *)&hdr[1]; + tmax = ((s32)fvt->maxtemp) << 16; + } else + tmax = 0x5e0000; /* 94 degree default */ + + /* Alloc & initialize state */ + pm121_cpu_state = kmalloc(sizeof(struct pm121_cpu_state), + GFP_KERNEL); + if (pm121_cpu_state == NULL) + goto fail; + pm121_cpu_state->ticks = 1; + + /* Fill PID params */ + pid_param.interval = PM121_CPU_INTERVAL; + pid_param.history_len = piddata->history_len; + if (pid_param.history_len > WF_CPU_PID_MAX_HISTORY) { + printk(KERN_WARNING "pm121: History size overflow on " + "CPU control loop (%d)\n", piddata->history_len); + pid_param.history_len = WF_CPU_PID_MAX_HISTORY; + } + pid_param.gd = piddata->gd; + pid_param.gp = piddata->gp; + pid_param.gr = piddata->gr / pid_param.history_len; + + tdelta = ((s32)piddata->target_temp_delta) << 16; + maxpow = ((s32)piddata->max_power) << 16; + powadj = ((s32)piddata->power_adj) << 16; + + pid_param.tmax = tmax; + pid_param.ttarget = tmax - tdelta; + pid_param.pmaxadj = maxpow - powadj; + + pid_param.min = fan_cpu->ops->get_min(fan_cpu); + pid_param.max = fan_cpu->ops->get_max(fan_cpu); + + wf_cpu_pid_init(&pm121_cpu_state->pid, &pid_param); + + pr_debug("pm121: CPU Fan control initialized.\n"); + pr_debug(" ttarged=%d.%03d, tmax=%d.%03d, min=%d RPM, max=%d RPM,\n", + FIX32TOPRINT(pid_param.ttarget), FIX32TOPRINT(pid_param.tmax), + pid_param.min, pid_param.max); + + return; + + fail: + printk(KERN_WARNING "pm121: CPU fan config not found, max fan speed\n"); + + if (controls[CPUFREQ]) + wf_control_set_max(controls[CPUFREQ]); + if (fan_cpu) + wf_control_set_max(fan_cpu); +} + + +static void pm121_cpu_fans_tick(struct pm121_cpu_state *st) +{ + s32 new_setpoint, temp, power; + struct wf_control *fan_cpu = NULL; + int rc; + + if (--st->ticks != 0) { + if (pm121_readjust) + goto readjust; + return; + } + st->ticks = PM121_CPU_INTERVAL; + + fan_cpu = controls[FAN_CPU]; + + rc = sensor_cpu_temp->ops->get_value(sensor_cpu_temp, &temp); + if (rc) { + printk(KERN_WARNING "pm121: CPU temp sensor error %d\n", + rc); + pm121_failure_state |= FAILURE_SENSOR; + return; + } + + rc = sensor_cpu_power->ops->get_value(sensor_cpu_power, &power); + if (rc) { + printk(KERN_WARNING "pm121: CPU power sensor error %d\n", + rc); + pm121_failure_state |= FAILURE_SENSOR; + return; + } + + pr_debug("pm121: CPU Fans tick ! CPU temp: %d.%03d°C, power: %d.%03d\n", + FIX32TOPRINT(temp), FIX32TOPRINT(power)); + + if (temp > st->pid.param.tmax) + pm121_failure_state |= FAILURE_OVERTEMP; + + new_setpoint = wf_cpu_pid_run(&st->pid, power, temp); + + /* correction */ + new_setpoint = pm121_correct(new_setpoint, + FAN_CPU, + st->pid.param.min); + + /* connected correction */ + new_setpoint = pm121_connect(FAN_CPU, new_setpoint); + + if (st->setpoint == new_setpoint) + return; + st->setpoint = new_setpoint; + pr_debug("pm121: CPU corrected setpoint: %d RPM\n", (int)new_setpoint); + + readjust: + if (fan_cpu && pm121_failure_state == 0) { + rc = fan_cpu->ops->set_value(fan_cpu, st->setpoint); + if (rc) { + printk(KERN_WARNING "pm121: %s fan error %d\n", + fan_cpu->name, rc); + pm121_failure_state |= FAILURE_FAN; + } + } +} + +/* + * ****** Common ****** + * + */ + +static void pm121_tick(void) +{ + unsigned int last_failure = pm121_failure_state; + unsigned int new_failure; + s32 total_power; + int i; + + if (!pm121_started) { + pr_debug("pm121: creating control loops !\n"); + for (i = 0; i < N_LOOPS; i++) + pm121_create_sys_fans(i); + + pm121_create_cpu_fans(); + pm121_started = 1; + } + + /* skipping ticks */ + if (pm121_skipping && --pm121_skipping) + return; + + /* compute average power */ + total_power = 0; + for (i = 0; i < pm121_cpu_state->pid.param.history_len; i++) + total_power += pm121_cpu_state->pid.powers[i]; + + average_power = total_power / pm121_cpu_state->pid.param.history_len; + + + pm121_failure_state = 0; + for (i = 0 ; i < N_LOOPS; i++) { + if (pm121_sys_state[i]) + pm121_sys_fans_tick(i); + } + + if (pm121_cpu_state) + pm121_cpu_fans_tick(pm121_cpu_state); + + pm121_readjust = 0; + new_failure = pm121_failure_state & ~last_failure; + + /* If entering failure mode, clamp cpufreq and ramp all + * fans to full speed. + */ + if (pm121_failure_state && !last_failure) { + for (i = 0; i < N_CONTROLS; i++) { + if (controls[i]) + wf_control_set_max(controls[i]); + } + } + + /* If leaving failure mode, unclamp cpufreq and readjust + * all fans on next iteration + */ + if (!pm121_failure_state && last_failure) { + if (controls[CPUFREQ]) + wf_control_set_min(controls[CPUFREQ]); + pm121_readjust = 1; + } + + /* Overtemp condition detected, notify and start skipping a couple + * ticks to let the temperature go down + */ + if (new_failure & FAILURE_OVERTEMP) { + wf_set_overtemp(); + pm121_skipping = 2; + } + + /* We only clear the overtemp condition if overtemp is cleared + * _and_ no other failure is present. Since a sensor error will + * clear the overtemp condition (can't measure temperature) at + * the control loop levels, but we don't want to keep it clear + * here in this case + */ + if (new_failure == 0 && last_failure & FAILURE_OVERTEMP) + wf_clear_overtemp(); +} + + +static struct wf_control* pm121_register_control(struct wf_control *ct, + const char *match, + unsigned int id) +{ + if (controls[id] == NULL && !strcmp(ct->name, match)) { + if (wf_get_control(ct) == 0) + controls[id] = ct; + } + return controls[id]; +} + +static void pm121_new_control(struct wf_control *ct) +{ + int all = 1; + + if (pm121_all_controls_ok) + return; + + all = pm121_register_control(ct, "optical-drive-fan", FAN_OD) && all; + all = pm121_register_control(ct, "hard-drive-fan", FAN_HD) && all; + all = pm121_register_control(ct, "cpu-fan", FAN_CPU) && all; + all = pm121_register_control(ct, "cpufreq-clamp", CPUFREQ) && all; + + if (all) + pm121_all_controls_ok = 1; +} + + + + +static struct wf_sensor* pm121_register_sensor(struct wf_sensor *sensor, + const char *match, + struct wf_sensor **var) +{ + if (*var == NULL && !strcmp(sensor->name, match)) { + if (wf_get_sensor(sensor) == 0) + *var = sensor; + } + return *var; +} + +static void pm121_new_sensor(struct wf_sensor *sr) +{ + int all = 1; + + if (pm121_all_sensors_ok) + return; + + all = pm121_register_sensor(sr, "cpu-temp", + &sensor_cpu_temp) && all; + all = pm121_register_sensor(sr, "cpu-current", + &sensor_cpu_current) && all; + all = pm121_register_sensor(sr, "cpu-voltage", + &sensor_cpu_voltage) && all; + all = pm121_register_sensor(sr, "cpu-power", + &sensor_cpu_power) && all; + all = pm121_register_sensor(sr, "hard-drive-temp", + &sensor_hard_drive_temp) && all; + all = pm121_register_sensor(sr, "optical-drive-temp", + &sensor_optical_drive_temp) && all; + all = pm121_register_sensor(sr, "incoming-air-temp", + &sensor_incoming_air_temp) && all; + all = pm121_register_sensor(sr, "north-bridge-temp", + &sensor_north_bridge_temp) && all; + all = pm121_register_sensor(sr, "gpu-temp", + &sensor_gpu_temp) && all; + + if (all) + pm121_all_sensors_ok = 1; +} + + + +static int pm121_notify(struct notifier_block *self, + unsigned long event, void *data) +{ + switch (event) { + case WF_EVENT_NEW_CONTROL: + pr_debug("pm121: new control %s detected\n", + ((struct wf_control *)data)->name); + pm121_new_control(data); + break; + case WF_EVENT_NEW_SENSOR: + pr_debug("pm121: new sensor %s detected\n", + ((struct wf_sensor *)data)->name); + pm121_new_sensor(data); + break; + case WF_EVENT_TICK: + if (pm121_all_controls_ok && pm121_all_sensors_ok) + pm121_tick(); + break; + } + + return 0; +} + +static struct notifier_block pm121_events = { + .notifier_call = pm121_notify, +}; + +static int pm121_init_pm(void) +{ + const struct smu_sdbp_header *hdr; + + hdr = smu_get_sdb_partition(SMU_SDB_SENSORTREE_ID, NULL); + if (hdr != 0) { + struct smu_sdbp_sensortree *st = + (struct smu_sdbp_sensortree *)&hdr[1]; + pm121_mach_model = st->model_id; + } + + pm121_connection = &pm121_connections[pm121_mach_model - 2]; + + printk(KERN_INFO "pm121: Initializing for iMac G5 iSight model ID %d\n", + pm121_mach_model); + + return 0; +} + + +static int pm121_probe(struct platform_device *ddev) +{ + wf_register_client(&pm121_events); + + return 0; +} + +static int __devexit pm121_remove(struct platform_device *ddev) +{ + wf_unregister_client(&pm121_events); + return 0; +} + +static struct platform_driver pm121_driver = { + .probe = pm121_probe, + .remove = __devexit_p(pm121_remove), + .driver = { + .name = "windfarm", + .bus = &platform_bus_type, + }, +}; + + +static int __init pm121_init(void) +{ + int rc = -ENODEV; + + if (machine_is_compatible("PowerMac12,1")) + rc = pm121_init_pm(); + + if (rc == 0) { + request_module("windfarm_smu_controls"); + request_module("windfarm_smu_sensors"); + request_module("windfarm_smu_sat"); + request_module("windfarm_lm75_sensor"); + request_module("windfarm_max6690_sensor"); + request_module("windfarm_cpufreq_clamp"); + platform_driver_register(&pm121_driver); + } + + return rc; +} + +static void __exit pm121_exit(void) +{ + + platform_driver_unregister(&pm121_driver); +} + + +module_init(pm121_init); +module_exit(pm121_exit); + +MODULE_AUTHOR("Étienne Bersac <bersace@gmail.com>"); +MODULE_DESCRIPTION("Thermal control logic for iMac G5 (iSight)"); +MODULE_LICENSE("GPL"); + diff --git a/drivers/macintosh/windfarm_pm81.c b/drivers/macintosh/windfarm_pm81.c index f24fa734046..abbe206474f 100644 --- a/drivers/macintosh/windfarm_pm81.c +++ b/drivers/macintosh/windfarm_pm81.c @@ -770,7 +770,7 @@ static struct platform_driver wf_smu_driver = { .remove = __devexit_p(wf_smu_remove), .driver = { .name = "windfarm", - .bus = &platform_bus_type, + .owner = THIS_MODULE, }, }; @@ -810,4 +810,4 @@ module_exit(wf_smu_exit); MODULE_AUTHOR("Benjamin Herrenschmidt <benh@kernel.crashing.org>"); MODULE_DESCRIPTION("Thermal control logic for iMac G5"); MODULE_LICENSE("GPL"); - +MODULE_ALIAS("platform:windfarm"); diff --git a/drivers/macintosh/windfarm_pm91.c b/drivers/macintosh/windfarm_pm91.c index 26eee69ebe6..764c525b211 100644 --- a/drivers/macintosh/windfarm_pm91.c +++ b/drivers/macintosh/windfarm_pm91.c @@ -702,7 +702,7 @@ static struct platform_driver wf_smu_driver = { .remove = __devexit_p(wf_smu_remove), .driver = { .name = "windfarm", - .bus = &platform_bus_type, + .owner = THIS_MODULE, }, }; @@ -742,3 +742,4 @@ MODULE_AUTHOR("Benjamin Herrenschmidt <benh@kernel.crashing.org>"); MODULE_DESCRIPTION("Thermal control logic for PowerMac9,1"); MODULE_LICENSE("GPL"); +MODULE_ALIAS("platform:windfarm"); diff --git a/drivers/macintosh/windfarm_smu_controls.c b/drivers/macintosh/windfarm_smu_controls.c index 58c2590f05e..961fa0e7c2c 100644 --- a/drivers/macintosh/windfarm_smu_controls.c +++ b/drivers/macintosh/windfarm_smu_controls.c @@ -218,6 +218,10 @@ static struct smu_fan_control *smu_fan_create(struct device_node *node, fct->ctrl.name = "cpu-fan"; else if (!strcmp(l, "Hard Drive") || !strcmp(l, "Hard drive")) fct->ctrl.name = "drive-bay-fan"; + else if (!strcmp(l, "HDD Fan")) /* seen on iMac G5 iSight */ + fct->ctrl.name = "hard-drive-fan"; + else if (!strcmp(l, "ODD Fan")) /* same */ + fct->ctrl.name = "optical-drive-fan"; /* Unrecognized fan, bail out */ if (fct->ctrl.name == NULL) diff --git a/drivers/macintosh/windfarm_smu_sat.c b/drivers/macintosh/windfarm_smu_sat.c index f449d775cdf..7f2be4baaed 100644 --- a/drivers/macintosh/windfarm_smu_sat.c +++ b/drivers/macintosh/windfarm_smu_sat.c @@ -13,7 +13,7 @@ #include <linux/init.h> #include <linux/wait.h> #include <linux/i2c.h> -#include <asm/semaphore.h> +#include <linux/mutex.h> #include <asm/prom.h> #include <asm/smu.h> #include <asm/pmac_low_i2c.h> @@ -36,7 +36,7 @@ struct wf_sat { int nr; atomic_t refcnt; - struct semaphore mutex; + struct mutex mutex; unsigned long last_read; /* jiffies when cache last updated */ u8 cache[16]; struct i2c_client i2c; @@ -163,7 +163,7 @@ static int wf_sat_get(struct wf_sensor *sr, s32 *value) if (sat->i2c.adapter == NULL) return -ENODEV; - down(&sat->mutex); + mutex_lock(&sat->mutex); if (time_after(jiffies, (sat->last_read + MAX_AGE))) { err = wf_sat_read_cache(sat); if (err) @@ -182,7 +182,7 @@ static int wf_sat_get(struct wf_sensor *sr, s32 *value) err = 0; fail: - up(&sat->mutex); + mutex_unlock(&sat->mutex); return err; } @@ -233,7 +233,7 @@ static void wf_sat_create(struct i2c_adapter *adapter, struct device_node *dev) sat->nr = -1; sat->node = of_node_get(dev); atomic_set(&sat->refcnt, 0); - init_MUTEX(&sat->mutex); + mutex_init(&sat->mutex); sat->i2c.addr = (addr >> 1) & 0x7f; sat->i2c.adapter = adapter; sat->i2c.driver = &wf_sat_driver; |