| 
									
										
										
										
											2009-07-03 10:28:00 +00:00
										 |  |  | /*
 | 
					
						
							|  |  |  |  * arch/sh/kernel/cpu/shmobile/cpuidle.c | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * Cpuidle support code for SuperH Mobile | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  *  Copyright (C) 2009 Magnus Damm | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * This file is subject to the terms and conditions of the GNU General Public | 
					
						
							|  |  |  |  * License.  See the file "COPYING" in the main directory of this archive | 
					
						
							|  |  |  |  * for more details. | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | #include <linux/init.h>
 | 
					
						
							|  |  |  | #include <linux/kernel.h>
 | 
					
						
							|  |  |  | #include <linux/io.h>
 | 
					
						
							|  |  |  | #include <linux/suspend.h>
 | 
					
						
							|  |  |  | #include <linux/cpuidle.h>
 | 
					
						
							| 
									
										
										
										
											2011-07-31 19:20:02 -04:00
										 |  |  | #include <linux/export.h>
 | 
					
						
							| 
									
										
										
										
											2009-07-03 10:28:00 +00:00
										 |  |  | #include <asm/suspend.h>
 | 
					
						
							|  |  |  | #include <asm/uaccess.h>
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static unsigned long cpuidle_mode[] = { | 
					
						
							|  |  |  | 	SUSP_SH_SLEEP, /* regular sleep mode */ | 
					
						
							|  |  |  | 	SUSP_SH_SLEEP | SUSP_SH_SF, /* sleep mode + self refresh */ | 
					
						
							| 
									
										
										
										
											2009-08-17 09:41:40 +00:00
										 |  |  | 	SUSP_SH_STANDBY | SUSP_SH_SF, /* software standby mode + self refresh */ | 
					
						
							| 
									
										
										
										
											2009-07-03 10:28:00 +00:00
										 |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static int cpuidle_sleep_enter(struct cpuidle_device *dev, | 
					
						
							| 
									
										
										
										
											2011-10-28 16:20:42 +05:30
										 |  |  | 				struct cpuidle_driver *drv, | 
					
						
							| 
									
										
										
										
											2011-10-28 16:20:09 +05:30
										 |  |  | 				int index) | 
					
						
							| 
									
										
										
										
											2009-07-03 10:28:00 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2011-11-18 16:13:09 +09:00
										 |  |  | 	unsigned long allowed_mode = SUSP_SH_SLEEP; | 
					
						
							| 
									
										
										
										
											2011-10-28 16:20:09 +05:30
										 |  |  | 	int requested_state = index; | 
					
						
							| 
									
										
										
										
											2009-07-03 10:28:00 +00:00
										 |  |  | 	int allowed_state; | 
					
						
							|  |  |  | 	int k; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/* convert allowed mode to allowed state */ | 
					
						
							|  |  |  | 	for (k = ARRAY_SIZE(cpuidle_mode) - 1; k > 0; k--) | 
					
						
							|  |  |  | 		if (cpuidle_mode[k] == allowed_mode) | 
					
						
							|  |  |  | 			break; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	allowed_state = k; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/* take the following into account for sleep mode selection:
 | 
					
						
							|  |  |  | 	 * - allowed_state: best mode allowed by hardware (clock deps) | 
					
						
							|  |  |  | 	 * - requested_state: best mode allowed by software (latencies) | 
					
						
							|  |  |  | 	 */ | 
					
						
							|  |  |  | 	k = min_t(int, allowed_state, requested_state); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	sh_mobile_call_standby(cpuidle_mode[k]); | 
					
						
							| 
									
										
										
										
											2011-10-28 16:20:09 +05:30
										 |  |  | 
 | 
					
						
							|  |  |  | 	return k; | 
					
						
							| 
									
										
										
										
											2009-07-03 10:28:00 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static struct cpuidle_driver cpuidle_driver = { | 
					
						
							| 
									
										
										
										
											2013-04-17 13:32:56 +00:00
										 |  |  | 	.name   = "sh_idle", | 
					
						
							|  |  |  | 	.owner  = THIS_MODULE, | 
					
						
							|  |  |  | 	.states = { | 
					
						
							|  |  |  | 		{ | 
					
						
							|  |  |  | 			.exit_latency = 1, | 
					
						
							|  |  |  | 			.target_residency = 1 * 2, | 
					
						
							|  |  |  | 			.power_usage = 3, | 
					
						
							|  |  |  | 			.enter = cpuidle_sleep_enter, | 
					
						
							|  |  |  | 			.name = "C1", | 
					
						
							|  |  |  | 			.desc = "SuperH Sleep Mode", | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 		{ | 
					
						
							|  |  |  | 			.exit_latency = 100, | 
					
						
							|  |  |  | 			.target_residency = 1 * 2, | 
					
						
							|  |  |  | 			.power_usage = 1, | 
					
						
							|  |  |  | 			.enter = cpuidle_sleep_enter, | 
					
						
							|  |  |  | 			.name = "C2", | 
					
						
							|  |  |  | 			.desc = "SuperH Sleep Mode [SF]", | 
					
						
							|  |  |  | 			.disabled = true, | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 		{ | 
					
						
							|  |  |  | 			.exit_latency = 2300, | 
					
						
							|  |  |  | 			.target_residency = 1 * 2, | 
					
						
							|  |  |  | 			.power_usage = 1, | 
					
						
							|  |  |  | 			.enter = cpuidle_sleep_enter, | 
					
						
							|  |  |  | 			.name = "C3", | 
					
						
							|  |  |  | 			.desc = "SuperH Mobile Standby Mode [SF]", | 
					
						
							|  |  |  | 			.disabled = true, | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 	}, | 
					
						
							|  |  |  | 	.safe_state_index = 0, | 
					
						
							|  |  |  | 	.state_count = 3, | 
					
						
							| 
									
										
										
										
											2009-07-03 10:28:00 +00:00
										 |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-04-17 13:32:57 +00:00
										 |  |  | int __init sh_mobile_setup_cpuidle(void) | 
					
						
							| 
									
										
										
										
											2009-07-03 10:28:00 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2013-04-17 13:32:56 +00:00
										 |  |  | 	if (sh_mobile_sleep_supported & SUSP_SH_SF) | 
					
						
							|  |  |  | 		cpuidle_driver.states[1].disabled = false; | 
					
						
							| 
									
										
										
										
											2009-07-03 10:28:00 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-04-17 13:32:56 +00:00
										 |  |  | 	if (sh_mobile_sleep_supported & SUSP_SH_STANDBY) | 
					
						
							|  |  |  | 		cpuidle_driver.states[2].disabled = false; | 
					
						
							| 
									
										
										
										
											2009-07-03 10:28:00 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-07-26 00:14:04 +02:00
										 |  |  | 	return cpuidle_register(&cpuidle_driver, NULL); | 
					
						
							| 
									
										
										
										
											2009-07-03 10:28:00 +00:00
										 |  |  | } |