Linux Kernel  3.7.1
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
mach-osiris-dvs.c
Go to the documentation of this file.
1 /* linux/arch/arm/mach-s3c2440/mach-osiris-dvs.c
2  *
3  * Copyright (c) 2009 Simtec Electronics
4  * http://armlinux.simtec.co.uk/
5  * Ben Dooks <[email protected]>
6  *
7  * Simtec Osiris Dynamic Voltage Scaling support.
8  *
9  * This program is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License version 2 as
11  * published by the Free Software Foundation.
12 */
13 
14 #include <linux/kernel.h>
15 #include <linux/module.h>
16 #include <linux/platform_device.h>
17 #include <linux/cpufreq.h>
18 #include <linux/gpio.h>
19 
20 #include <linux/i2c/tps65010.h>
21 
22 #include <plat/cpu-freq.h>
23 
24 #define OSIRIS_GPIO_DVS S3C2410_GPB(5)
25 
26 static bool dvs_en;
27 
28 static void osiris_dvs_tps_setdvs(bool on)
29 {
30  unsigned vregs1 = 0, vdcdc2 = 0;
31 
32  if (!on) {
34  vregs1 = TPS_LDO1_OFF; /* turn off in low-power mode */
35  }
36 
37  dvs_en = on;
39  vregs1 |= TPS_LDO2_ENABLE | TPS_LDO1_ENABLE;
40 
41  tps65010_config_vregs1(vregs1);
42  tps65010_config_vdcdc2(vdcdc2);
43 }
44 
45 static bool is_dvs(struct s3c_freq *f)
46 {
47  /* at the moment, we assume ARMCLK = HCLK => DVS */
48  return f->armclk == f->hclk;
49 }
50 
51 /* keep track of current state */
52 static bool cur_dvs = false;
53 
54 static int osiris_dvs_notify(struct notifier_block *nb,
55  unsigned long val, void *data)
56 {
57  struct cpufreq_freqs *cf = data;
59  bool old_dvs = is_dvs(&freqs->old);
60  bool new_dvs = is_dvs(&freqs->new);
61  int ret = 0;
62 
63  if (!dvs_en)
64  return 0;
65 
66  printk(KERN_DEBUG "%s: old %ld,%ld new %ld,%ld\n", __func__,
67  freqs->old.armclk, freqs->old.hclk,
68  freqs->new.armclk, freqs->new.hclk);
69 
70  switch (val) {
71  case CPUFREQ_PRECHANGE:
72  if (old_dvs & !new_dvs ||
73  cur_dvs & !new_dvs) {
74  pr_debug("%s: exiting dvs\n", __func__);
75  cur_dvs = false;
77  }
78  break;
79  case CPUFREQ_POSTCHANGE:
80  if (!old_dvs & new_dvs ||
81  !cur_dvs & new_dvs) {
82  pr_debug("entering dvs\n");
83  cur_dvs = true;
85  }
86  break;
87  }
88 
89  return ret;
90 }
91 
92 static struct notifier_block osiris_dvs_nb = {
93  .notifier_call = osiris_dvs_notify,
94 };
95 
96 static int __devinit osiris_dvs_probe(struct platform_device *pdev)
97 {
98  int ret;
99 
100  dev_info(&pdev->dev, "initialising\n");
101 
102  ret = gpio_request(OSIRIS_GPIO_DVS, "osiris-dvs");
103  if (ret) {
104  dev_err(&pdev->dev, "cannot claim gpio\n");
105  goto err_nogpio;
106  }
107 
108  /* start with dvs disabled */
110 
111  ret = cpufreq_register_notifier(&osiris_dvs_nb,
113  if (ret) {
114  dev_err(&pdev->dev, "failed to register with cpufreq\n");
115  goto err_nofreq;
116  }
117 
118  osiris_dvs_tps_setdvs(true);
119 
120  return 0;
121 
122 err_nofreq:
124 
125 err_nogpio:
126  return ret;
127 }
128 
129 static int __devexit osiris_dvs_remove(struct platform_device *pdev)
130 {
131  dev_info(&pdev->dev, "exiting\n");
132 
133  /* disable any current dvs */
135  osiris_dvs_tps_setdvs(false);
136 
137  cpufreq_unregister_notifier(&osiris_dvs_nb,
139 
141 
142  return 0;
143 }
144 
145 /* the CONFIG_PM block is so small, it isn't worth actaully compiling it
146  * out if the configuration isn't set. */
147 
148 static int osiris_dvs_suspend(struct device *dev)
149 {
151  osiris_dvs_tps_setdvs(false);
152  cur_dvs = false;
153 
154  return 0;
155 }
156 
157 static int osiris_dvs_resume(struct device *dev)
158 {
159  osiris_dvs_tps_setdvs(true);
160  return 0;
161 }
162 
163 static const struct dev_pm_ops osiris_dvs_pm = {
164  .suspend = osiris_dvs_suspend,
165  .resume = osiris_dvs_resume,
166 };
167 
168 static struct platform_driver osiris_dvs_driver = {
169  .probe = osiris_dvs_probe,
170  .remove = __devexit_p(osiris_dvs_remove),
171  .driver = {
172  .name = "osiris-dvs",
173  .owner = THIS_MODULE,
174  .pm = &osiris_dvs_pm,
175  },
176 };
177 
178 module_platform_driver(osiris_dvs_driver);
179 
180 MODULE_DESCRIPTION("Simtec OSIRIS DVS support");
181 MODULE_AUTHOR("Ben Dooks <[email protected]>");
182 MODULE_LICENSE("GPL");
183 MODULE_ALIAS("platform:osiris-dvs");