aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/mfd/sm501.c
diff options
context:
space:
mode:
authorBen Dooks <ben-linux@fluff.org>2007-06-23 20:16:28 -0400
committerLinus Torvalds <torvalds@woody.linux-foundation.org>2007-06-24 11:59:11 -0400
commit331d74750e69a2202f857d3af9323335d0d6879f (patch)
tree1508b5d183c18d29a54271153e0f8c49546d9013 /drivers/mfd/sm501.c
parent1ed8a2b3c501bedd4b35130c8a52662ccf78abad (diff)
SM501: suspend support
This patch adds support for suspending the core (mfd driver) of the SM501. Signed-off-by: Ben Dooks <ben-linux@fluff.org> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'drivers/mfd/sm501.c')
-rw-r--r--drivers/mfd/sm501.c113
1 files changed, 105 insertions, 8 deletions
diff --git a/drivers/mfd/sm501.c b/drivers/mfd/sm501.c
index b0b4458ae90b..72bbecf4b451 100644
--- a/drivers/mfd/sm501.c
+++ b/drivers/mfd/sm501.c
@@ -41,6 +41,9 @@ struct sm501_devdata {
41 struct resource *regs_claim; 41 struct resource *regs_claim;
42 struct sm501_platdata *platdata; 42 struct sm501_platdata *platdata;
43 43
44 unsigned int in_suspend;
45 unsigned long pm_misc;
46
44 int unit_power[20]; 47 int unit_power[20];
45 unsigned int pdev_id; 48 unsigned int pdev_id;
46 unsigned int irq; 49 unsigned int irq;
@@ -169,10 +172,41 @@ x "M %ld.%ld (%ld), MX1 %ld.%ld (%ld)\n",
169 fmt_freq(decode_div(pll2, pm1, 8, 1<<12, 15, misc_div)), 172 fmt_freq(decode_div(pll2, pm1, 8, 1<<12, 15, misc_div)),
170 fmt_freq(decode_div(pll2, pm1, 0, 1<<4, 15, misc_div))); 173 fmt_freq(decode_div(pll2, pm1, 0, 1<<4, 15, misc_div)));
171} 174}
172#else 175
173static void sm501_dump_clk(struct sm501_devdata *sm) 176static void sm501_dump_regs(struct sm501_devdata *sm)
177{
178 void __iomem *regs = sm->regs;
179
180 dev_info(sm->dev, "System Control %08x\n",
181 readl(regs + SM501_SYSTEM_CONTROL));
182 dev_info(sm->dev, "Misc Control %08x\n",
183 readl(regs + SM501_MISC_CONTROL));
184 dev_info(sm->dev, "GPIO Control Low %08x\n",
185 readl(regs + SM501_GPIO31_0_CONTROL));
186 dev_info(sm->dev, "GPIO Control Hi %08x\n",
187 readl(regs + SM501_GPIO63_32_CONTROL));
188 dev_info(sm->dev, "DRAM Control %08x\n",
189 readl(regs + SM501_DRAM_CONTROL));
190 dev_info(sm->dev, "Arbitration Ctrl %08x\n",
191 readl(regs + SM501_ARBTRTN_CONTROL));
192 dev_info(sm->dev, "Misc Timing %08x\n",
193 readl(regs + SM501_MISC_TIMING));
194}
195
196static void sm501_dump_gate(struct sm501_devdata *sm)
174{ 197{
198 dev_info(sm->dev, "CurrentGate %08x\n",
199 readl(sm->regs + SM501_CURRENT_GATE));
200 dev_info(sm->dev, "CurrentClock %08x\n",
201 readl(sm->regs + SM501_CURRENT_CLOCK));
202 dev_info(sm->dev, "PowerModeControl %08x\n",
203 readl(sm->regs + SM501_POWER_MODE_CONTROL));
175} 204}
205
206#else
207static inline void sm501_dump_gate(struct sm501_devdata *sm) { }
208static inline void sm501_dump_regs(struct sm501_devdata *sm) { }
209static inline void sm501_dump_clk(struct sm501_devdata *sm) { }
176#endif 210#endif
177 211
178/* sm501_sync_regs 212/* sm501_sync_regs
@@ -185,9 +219,21 @@ static void sm501_sync_regs(struct sm501_devdata *sm)
185 readl(sm->regs); 219 readl(sm->regs);
186} 220}
187 221
222static inline void sm501_mdelay(struct sm501_devdata *sm, unsigned int delay)
223{
224 /* during suspend/resume, we are currently not allowed to sleep,
225 * so change to using mdelay() instead of msleep() if we
226 * are in one of these paths */
227
228 if (sm->in_suspend)
229 mdelay(delay);
230 else
231 msleep(delay);
232}
233
188/* sm501_misc_control 234/* sm501_misc_control
189 * 235 *
190 * alters the misceleneous control parameters 236 * alters the miscellaneous control parameters
191*/ 237*/
192 238
193int sm501_misc_control(struct device *dev, 239int sm501_misc_control(struct device *dev,
@@ -368,7 +414,7 @@ int sm501_unit_power(struct device *dev, unsigned int unit, unsigned int to)
368 dev_dbg(sm->dev, "gate %08lx, clock %08lx, mode %08lx\n", 414 dev_dbg(sm->dev, "gate %08lx, clock %08lx, mode %08lx\n",
369 gate, clock, mode); 415 gate, clock, mode);
370 416
371 msleep(16); 417 sm501_mdelay(sm, 16);
372 418
373 already: 419 already:
374 mutex_unlock(&sm->clock_lock); 420 mutex_unlock(&sm->clock_lock);
@@ -538,7 +584,7 @@ unsigned long sm501_set_clock(struct device *dev,
538 dev_info(sm->dev, "gate %08lx, clock %08lx, mode %08lx\n", 584 dev_info(sm->dev, "gate %08lx, clock %08lx, mode %08lx\n",
539 gate, clock, mode); 585 gate, clock, mode);
540 586
541 msleep(16); 587 sm501_mdelay(sm, 16);
542 mutex_unlock(&sm->clock_lock); 588 mutex_unlock(&sm->clock_lock);
543 589
544 sm501_dump_clk(sm); 590 sm501_dump_clk(sm);
@@ -841,9 +887,7 @@ static int sm501_init_dev(struct sm501_devdata *sm)
841 sm->regs, readl(sm->regs + SM501_DEVICEID), 887 sm->regs, readl(sm->regs + SM501_DEVICEID),
842 (unsigned long)mem_avail >> 20, sm->irq); 888 (unsigned long)mem_avail >> 20, sm->irq);
843 889
844 dev_info(sm->dev, "CurrentGate %08x\n", readl(sm->regs+0x38)); 890 sm501_dump_gate(sm);
845 dev_info(sm->dev, "CurrentClock %08x\n", readl(sm->regs+0x3c));
846 dev_info(sm->dev, "PowerModeControl %08x\n", readl(sm->regs+0x54));
847 891
848 ret = device_create_file(sm->dev, &dev_attr_dbg_regs); 892 ret = device_create_file(sm->dev, &dev_attr_dbg_regs);
849 if (ret) 893 if (ret)
@@ -933,6 +977,57 @@ static int sm501_plat_probe(struct platform_device *dev)
933 977
934} 978}
935 979
980#ifdef CONFIG_PM
981/* power management support */
982
983static int sm501_plat_suspend(struct platform_device *pdev, pm_message_t state)
984{
985 struct sm501_devdata *sm = platform_get_drvdata(pdev);
986
987 sm->in_suspend = 1;
988 sm->pm_misc = readl(sm->regs + SM501_MISC_CONTROL);
989
990 sm501_dump_regs(sm);
991 return 0;
992}
993
994static int sm501_plat_resume(struct platform_device *pdev)
995{
996 struct sm501_devdata *sm = platform_get_drvdata(pdev);
997
998 sm501_dump_regs(sm);
999 sm501_dump_gate(sm);
1000 sm501_dump_clk(sm);
1001
1002 /* check to see if we are in the same state as when suspended */
1003
1004 if (readl(sm->regs + SM501_MISC_CONTROL) != sm->pm_misc) {
1005 dev_info(sm->dev, "SM501_MISC_CONTROL changed over sleep\n");
1006 writel(sm->pm_misc, sm->regs + SM501_MISC_CONTROL);
1007
1008 /* our suspend causes the controller state to change,
1009 * either by something attempting setup, power loss,
1010 * or an external reset event on power change */
1011
1012 if (sm->platdata && sm->platdata->init) {
1013 sm501_init_regs(sm, sm->platdata->init);
1014 }
1015 }
1016
1017 /* dump our state from resume */
1018
1019 sm501_dump_regs(sm);
1020 sm501_dump_clk(sm);
1021
1022 sm->in_suspend = 0;
1023
1024 return 0;
1025}
1026#else
1027#define sm501_plat_suspend NULL
1028#define sm501_plat_resume NULL
1029#endif
1030
936/* Initialisation data for PCI devices */ 1031/* Initialisation data for PCI devices */
937 1032
938static struct sm501_initdata sm501_pci_initdata = { 1033static struct sm501_initdata sm501_pci_initdata = {
@@ -1126,6 +1221,8 @@ static struct platform_driver sm501_plat_drv = {
1126 }, 1221 },
1127 .probe = sm501_plat_probe, 1222 .probe = sm501_plat_probe,
1128 .remove = sm501_plat_remove, 1223 .remove = sm501_plat_remove,
1224 .suspend = sm501_plat_suspend,
1225 .resume = sm501_plat_resume,
1129}; 1226};
1130 1227
1131static int __init sm501_base_init(void) 1228static int __init sm501_base_init(void)