therm_pm72.c

来自「Linux Kernel 2.6.9 for OMAP1710」· C语言 代码 · 共 1,340 行 · 第 1/3 页

C
1,340
字号
		return;	state->ticks = DRIVES_PID_INTERVAL;	DBG("drives:\n");	/* Check fan status */	rc = get_rpm_fan(DRIVES_FAN_RPM_ID, !RPM_PID_USE_ACTUAL_SPEED);	if (rc < 0) {		printk(KERN_WARNING "Error %d reading drives fan !\n", rc);		/* XXX What do we do now ? */	} else		state->rpm = rc;	DBG("  current rpm: %d\n", state->rpm);	/* Get some sensor readings */	temp = le16_to_cpu(i2c_smbus_read_word_data(state->monitor, DS1775_TEMP)) << 8;	state->last_temp = temp;	DBG("  temp: %d.%03d, target: %d.%03d\n", FIX32TOPRINT(temp),	    FIX32TOPRINT(DRIVES_PID_INPUT_TARGET));	/* Store temperature and error in history array */	state->cur_sample = (state->cur_sample + 1) % DRIVES_PID_HISTORY_SIZE;	state->sample_history[state->cur_sample] = temp;	state->error_history[state->cur_sample] = temp - DRIVES_PID_INPUT_TARGET;		/* If first loop, fill the history table */	if (state->first) {		for (i = 0; i < (DRIVES_PID_HISTORY_SIZE - 1); i++) {			state->cur_sample = (state->cur_sample + 1) %				DRIVES_PID_HISTORY_SIZE;			state->sample_history[state->cur_sample] = temp;			state->error_history[state->cur_sample] =				temp - DRIVES_PID_INPUT_TARGET;		}		state->first = 0;	}	/* Calculate the integral term */	sum = 0;	integral = 0;	for (i = 0; i < DRIVES_PID_HISTORY_SIZE; i++)		integral += state->error_history[i];	integral *= DRIVES_PID_INTERVAL;	DBG("  integral: %08x\n", integral);	integ_p = ((s64)DRIVES_PID_G_r) * (s64)integral;	DBG("   integ_p: %d\n", (int)(integ_p >> 36));	sum += integ_p;	/* Calculate the derivative term */	derivative = state->error_history[state->cur_sample] -		state->error_history[(state->cur_sample + DRIVES_PID_HISTORY_SIZE - 1)				    % DRIVES_PID_HISTORY_SIZE];	derivative /= DRIVES_PID_INTERVAL;	deriv_p = ((s64)DRIVES_PID_G_d) * (s64)derivative;	DBG("   deriv_p: %d\n", (int)(deriv_p >> 36));	sum += deriv_p;	/* Calculate the proportional term */	prop_p = ((s64)DRIVES_PID_G_p) * (s64)(state->error_history[state->cur_sample]);	DBG("   prop_p: %d\n", (int)(prop_p >> 36));	sum += prop_p;	/* Scale sum */	sum >>= 36;	DBG("   sum: %d\n", (int)sum);	state->rpm += (s32)sum;	if (state->rpm < DRIVES_PID_OUTPUT_MIN)		state->rpm = DRIVES_PID_OUTPUT_MIN;	if (state->rpm > DRIVES_PID_OUTPUT_MAX)		state->rpm = DRIVES_PID_OUTPUT_MAX;	DBG("** DRIVES RPM: %d\n", (int)state->rpm);	set_rpm_fan(DRIVES_FAN_RPM_ID, state->rpm);}/* * Initialize the state structure for the drives bay fan control loop */static int init_drives_state(struct drives_pid_state *state){	state->ticks = 1;	state->first = 1;	state->rpm = 1000;	state->monitor = attach_i2c_chip(DRIVES_DALLAS_ID, "drives_temp");	if (state->monitor == NULL)		return -ENODEV;	device_create_file(&of_dev->dev, &dev_attr_drives_temperature);	device_create_file(&of_dev->dev, &dev_attr_drives_fan_rpm);	return 0;}/* * Dispose of the state data for the drives control loop */static void dispose_drives_state(struct drives_pid_state *state){	if (state->monitor == NULL)		return;	device_remove_file(&of_dev->dev, &dev_attr_drives_temperature);	device_remove_file(&of_dev->dev, &dev_attr_drives_fan_rpm);	detach_i2c_chip(state->monitor);	state->monitor = NULL;}static int call_critical_overtemp(void){	char *argv[] = { critical_overtemp_path, NULL };	static char *envp[] = { "HOME=/",				"TERM=linux",				"PATH=/sbin:/usr/sbin:/bin:/usr/bin",				NULL };	return call_usermodehelper(critical_overtemp_path, argv, envp, 0);}/* * Here's the kernel thread that calls the various control loops */static int main_control_loop(void *x){	daemonize("kfand");	DBG("main_control_loop started\n");	down(&driver_lock);	if (start_fcu() < 0) {		printk(KERN_ERR "kfand: failed to start FCU\n");		up(&driver_lock);		goto out;	}	/* Set the PCI fan once for now */	set_pwm_fan(SLOTS_FAN_PWM_ID, SLOTS_FAN_DEFAULT_PWM);	/* Initialize ADCs */	initialize_adc(&cpu_state[0]);	if (cpu_state[1].monitor != NULL)		initialize_adc(&cpu_state[1]);	up(&driver_lock);	while (state == state_attached) {		unsigned long elapsed, start;		start = jiffies;		down(&driver_lock);		do_monitor_cpu(&cpu_state[0]);		if (cpu_state[1].monitor != NULL)			do_monitor_cpu(&cpu_state[1]);		do_monitor_backside(&backside_state);		do_monitor_drives(&drives_state);		up(&driver_lock);		if (critical_state == 1) {			printk(KERN_WARNING "Temperature control detected a critical condition\n");			printk(KERN_WARNING "Attempting to shut down...\n");			if (call_critical_overtemp()) {				printk(KERN_WARNING "Can't call %s, power off now!\n",				       critical_overtemp_path);				machine_power_off();			}		}		if (critical_state > 0)			critical_state++;		if (critical_state > MAX_CRITICAL_STATE) {			printk(KERN_WARNING "Shutdown timed out, power off now !\n");			machine_power_off();		}		// FIXME: Deal with signals		set_current_state(TASK_INTERRUPTIBLE);		elapsed = jiffies - start;		if (elapsed < HZ)			schedule_timeout(HZ - elapsed);	} out:	DBG("main_control_loop ended\n");	ctrl_task = 0;	complete_and_exit(&ctrl_complete, 0);}/* * Dispose the control loops when tearing down */static void dispose_control_loops(void){	dispose_cpu_state(&cpu_state[0]);	dispose_cpu_state(&cpu_state[1]);	dispose_backside_state(&backside_state);	dispose_drives_state(&drives_state);}/* * Create the control loops. U3-0 i2c bus is up, so we can now * get to the various sensors */static int create_control_loops(void){	struct device_node *np;	/* Count CPUs from the device-tree, we don't care how many are	 * actually used by Linux	 */	cpu_count = 0;	for (np = NULL; NULL != (np = of_find_node_by_type(np, "cpu"));)		cpu_count++;	DBG("counted %d CPUs in the device-tree\n", cpu_count);	/* Create control loops for everything. If any fail, everything	 * fails	 */	if (init_cpu_state(&cpu_state[0], 0))		goto fail;	if (cpu_count > 1 && init_cpu_state(&cpu_state[1], 1))		goto fail;	if (init_backside_state(&backside_state))		goto fail;	if (init_drives_state(&drives_state))		goto fail;	DBG("all control loops up !\n");	return 0;	 fail:	DBG("failure creating control loops, disposing\n");	dispose_control_loops();	return -ENODEV;}/* * Start the control loops after everything is up, that is create * the thread that will make them run */static void start_control_loops(void){	init_completion(&ctrl_complete);	ctrl_task = kernel_thread(main_control_loop, NULL, SIGCHLD | CLONE_KERNEL);}/* * Stop the control loops when tearing down */static void stop_control_loops(void){	if (ctrl_task != 0)		wait_for_completion(&ctrl_complete);}/* * Attach to the i2c FCU after detecting U3-1 bus */static int attach_fcu(void){	fcu = attach_i2c_chip(FAN_CTRLER_ID, "fcu");	if (fcu == NULL)		return -ENODEV;	DBG("FCU attached\n");	return 0;}/* * Detach from the i2c FCU when tearing down */static void detach_fcu(void){	if (fcu)		detach_i2c_chip(fcu);	fcu = NULL;}/* * Attach to the i2c controller. We probe the various chips based * on the device-tree nodes and build everything for the driver to * run, we then kick the driver monitoring thread */static int therm_pm72_attach(struct i2c_adapter *adapter){	down(&driver_lock);	/* Check state */	if (state == state_detached)		state = state_attaching;	if (state != state_attaching) {		up(&driver_lock);		return 0;	}	/* Check if we are looking for one of these */	if (u3_0 == NULL && !strcmp(adapter->name, "u3 0")) {		u3_0 = adapter;		DBG("found U3-0, creating control loops\n");		if (create_control_loops())			u3_0 = NULL;	} else if (u3_1 == NULL && !strcmp(adapter->name, "u3 1")) {		u3_1 = adapter;		DBG("found U3-1, attaching FCU\n");		if (attach_fcu())			u3_1 = NULL;	}	/* We got all we need, start control loops */	if (u3_0 != NULL && u3_1 != NULL) {		DBG("everything up, starting control loops\n");		state = state_attached;		start_control_loops();	}	up(&driver_lock);	return 0;}/* * Called on every adapter when the driver or the i2c controller * is going away. */static int therm_pm72_detach(struct i2c_adapter *adapter){	down(&driver_lock);	if (state != state_detached)		state = state_detaching;	/* Stop control loops if any */	DBG("stopping control loops\n");	up(&driver_lock);	stop_control_loops();	down(&driver_lock);	if (u3_0 != NULL && !strcmp(adapter->name, "u3 0")) {		DBG("lost U3-0, disposing control loops\n");		dispose_control_loops();		u3_0 = NULL;	}		if (u3_1 != NULL && !strcmp(adapter->name, "u3 1")) {		DBG("lost U3-1, detaching FCU\n");		detach_fcu();		u3_1 = NULL;	}	if (u3_0 == NULL && u3_1 == NULL)		state = state_detached;	up(&driver_lock);	return 0;}static int fcu_of_probe(struct of_device* dev, const struct of_match *match){	int rc;	state = state_detached;	rc = i2c_add_driver(&therm_pm72_driver);	if (rc < 0)		return rc;	return 0;}static int fcu_of_remove(struct of_device* dev){	i2c_del_driver(&therm_pm72_driver);	return 0;}static struct of_match fcu_of_match[] = {	{	.name 		= OF_ANY_MATCH,	.type		= "fcu",	.compatible	= OF_ANY_MATCH	},	{},};static struct of_platform_driver fcu_of_platform_driver = {	.name 		= "temperature",	.match_table	= fcu_of_match,	.probe		= fcu_of_probe,	.remove		= fcu_of_remove};/* * Check machine type, attach to i2c controller */static int __init therm_pm72_init(void){	struct device_node *np;	if (!machine_is_compatible("PowerMac7,2"))	    	return -ENODEV;	printk(KERN_INFO "PowerMac G5 Thermal control driver %s\n", VERSION);	np = of_find_node_by_type(NULL, "fcu");	if (np == NULL) {		printk(KERN_ERR "Can't find FCU in device-tree !\n");		return -ENODEV;	}	of_dev = of_platform_device_create(np, "temperature");	if (of_dev == NULL) {		printk(KERN_ERR "Can't register FCU platform device !\n");		return -ENODEV;	}	of_register_driver(&fcu_of_platform_driver);		return 0;}static void __exit therm_pm72_exit(void){	of_unregister_driver(&fcu_of_platform_driver);	if (of_dev)		of_device_unregister(of_dev);}module_init(therm_pm72_init);module_exit(therm_pm72_exit);MODULE_AUTHOR("Benjamin Herrenschmidt <benh@kernel.crashing.org>");MODULE_DESCRIPTION("Driver for Apple's PowerMac7,2 G5 thermal control");MODULE_LICENSE("GPL");

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?