1 /* 2 * arch/arm/mach-kirkwood/cpuidle.c 3 * 4 * CPU idle Marvell Kirkwood SoCs 5 * 6 * This file is licensed under the terms of the GNU General Public 7 * License version 2. This program is licensed "as is" without any 8 * warranty of any kind, whether express or implied. 9 * 10 * The cpu idle uses wait-for-interrupt and DDR self refresh in order 11 * to implement two idle states - 12 * #1 wait-for-interrupt 13 * #2 wait-for-interrupt and DDR self refresh 14 */ 15 16 #include <linux/kernel.h> 17 #include <linux/module.h> 18 #include <linux/init.h> 19 #include <linux/platform_device.h> 20 #include <linux/cpuidle.h> 21 #include <linux/io.h> 22 #include <linux/export.h> 23 #include <asm/proc-fns.h> 24 #include <asm/cpuidle.h> 25 26 #define KIRKWOOD_MAX_STATES 2 27 28 static void __iomem *ddr_operation_base; 29 30 /* Actual code that puts the SoC in different idle states */ 31 static int kirkwood_enter_idle(struct cpuidle_device *dev, 32 struct cpuidle_driver *drv, 33 int index) 34 { 35 writel(0x7, ddr_operation_base); 36 cpu_do_idle(); 37 38 return index; 39 } 40 41 static struct cpuidle_driver kirkwood_idle_driver = { 42 .name = "kirkwood_idle", 43 .owner = THIS_MODULE, 44 .en_core_tk_irqen = 1, 45 .states[0] = ARM_CPUIDLE_WFI_STATE, 46 .states[1] = { 47 .enter = kirkwood_enter_idle, 48 .exit_latency = 10, 49 .target_residency = 100000, 50 .flags = CPUIDLE_FLAG_TIME_VALID, 51 .name = "DDR SR", 52 .desc = "WFI and DDR Self Refresh", 53 }, 54 .state_count = KIRKWOOD_MAX_STATES, 55 }; 56 static struct cpuidle_device *device; 57 58 static DEFINE_PER_CPU(struct cpuidle_device, kirkwood_cpuidle_device); 59 60 /* Initialize CPU idle by registering the idle states */ 61 static int kirkwood_cpuidle_probe(struct platform_device *pdev) 62 { 63 struct resource *res; 64 65 res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 66 if (res == NULL) 67 return -EINVAL; 68 69 ddr_operation_base = devm_request_and_ioremap(&pdev->dev, res); 70 if (!ddr_operation_base) 71 return -EADDRNOTAVAIL; 72 73 device = &per_cpu(kirkwood_cpuidle_device, smp_processor_id()); 74 device->state_count = KIRKWOOD_MAX_STATES; 75 76 cpuidle_register_driver(&kirkwood_idle_driver); 77 if (cpuidle_register_device(device)) { 78 pr_err("kirkwood_init_cpuidle: Failed registering\n"); 79 return -EIO; 80 } 81 return 0; 82 } 83 84 int kirkwood_cpuidle_remove(struct platform_device *pdev) 85 { 86 cpuidle_unregister_device(device); 87 cpuidle_unregister_driver(&kirkwood_idle_driver); 88 89 return 0; 90 } 91 92 static struct platform_driver kirkwood_cpuidle_driver = { 93 .probe = kirkwood_cpuidle_probe, 94 .remove = kirkwood_cpuidle_remove, 95 .driver = { 96 .name = "kirkwood_cpuidle", 97 .owner = THIS_MODULE, 98 }, 99 }; 100 101 module_platform_driver(kirkwood_cpuidle_driver); 102 103 MODULE_AUTHOR("Andrew Lunn <andrew@lunn.ch>"); 104 MODULE_DESCRIPTION("Kirkwood cpu idle driver"); 105 MODULE_LICENSE("GPL v2"); 106 MODULE_ALIAS("platform:kirkwood-cpuidle"); 107