aboutsummaryrefslogtreecommitdiffstats
path: root/target/linux/s3c24xx/patches-2.6.24/1090-fix-s3c2410_timer_setup-resume-BUG.patch.patch
blob: 6457bbffc88cba60d1e93cd13c6262fa59613279 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
From 6ce7c9b239314f4ee9f86164da8aaf5f78c0d1f1 Mon Sep 17 00:00:00 2001
From: warmcat <andy@warmcat.com>
Date: Sun, 13 Apr 2008 07:25:49 +0100
Subject: [PATCH] fix-s3c2410_timer_setup-resume-BUG.patch

---
 arch/arm/plat-s3c24xx/time.c |   33 +++++++++++++++++++++++++++++++++
 drivers/i2c/chips/pcf50633.c |    9 +++++++--
 2 files changed, 40 insertions(+), 2 deletions(-)

diff --git a/arch/arm/plat-s3c24xx/time.c b/arch/arm/plat-s3c24xx/time.c
index c11d0dd..6989eea 100644
--- a/arch/arm/plat-s3c24xx/time.c
+++ b/arch/arm/plat-s3c24xx/time.c
@@ -42,6 +42,7 @@
 
 static unsigned long timer_startval;
 static unsigned long timer_usec_ticks;
+static struct work_struct resume_work;
 
 #define TIMER_USEC_SHIFT 16
 
@@ -201,9 +202,12 @@ static void s3c2410_timer_setup (void)
 
 		pclk = clk_get_rate(clk);
 
+		printk("pclk = %d\n", pclk);
+
 		/* configure clock tick */
 
 		timer_usec_ticks = timer_mask_usec_ticks(6, pclk);
+		printk("timer_usec_ticks = %d\n", timer_usec_ticks);
 
 		tcfg1 &= ~S3C2410_TCFG1_MUX4_MASK;
 		tcfg1 |= S3C2410_TCFG1_MUX4_DIV2;
@@ -212,6 +216,11 @@ static void s3c2410_timer_setup (void)
 		tcfg0 |= ((6 - 1) / 2) << S3C2410_TCFG_PRESCALER1_SHIFT;
 
 		tcnt = (pclk / 6) / HZ;
+
+		/* start the timer running */
+		tcon |= S3C2410_TCON_T4START | S3C2410_TCON_T4RELOAD;
+		tcon &= ~S3C2410_TCON_T4MANUALUPD;
+		__raw_writel(tcon, S3C2410_TCON);
 	}
 
 	/* timers reload after counting zero, so reduce the count by 1 */
@@ -247,10 +256,34 @@ static void s3c2410_timer_setup (void)
 	tcon |= S3C2410_TCON_T4START;
 	tcon &= ~S3C2410_TCON_T4MANUALUPD;
 	__raw_writel(tcon, S3C2410_TCON);
+
+	__raw_writel(__raw_readl(S3C2410_INTMSK) & (~(1UL << 14)),
+		     S3C2410_INTMSK);
+
+}
+
+static void timer_resume_work(struct work_struct *work)
+{
+	s3c2410_timer_setup();
+}
+
+/* ooh a nasty situation arises if we try to call s3c2410_timer_setup() from
+ * the resume handler.  It is called in atomic context but the clock APIs
+ * try to lock a mutex which may sleep.  We are in a bit of an unusual
+ * situation because we don't have a tick source right now, but it should be
+ * okay to try to schedule a work item... hopefully
+ */
+
+static void s3c2410_timer_resume_atomic(void)
+{
+	int ret = schedule_work(&resume_work);
+	if (!ret)
+		printk(KERN_INFO"Failed to schedule_work tick ctr (%d)\n", ret);
 }
 
 static void __init s3c2410_timer_init (void)
 {
+	INIT_WORK(&resume_work, timer_resume_work);
 	s3c2410_timer_setup();
 	setup_irq(IRQ_TIMER4, &s3c2410_timer_irq);
 }
diff --git a/drivers/i2c/chips/pcf50633.c b/drivers/i2c/chips/pcf50633.c
index e23c540..91b9ac3 100644
--- a/drivers/i2c/chips/pcf50633.c
+++ b/drivers/i2c/chips/pcf50633.c
@@ -1926,9 +1926,11 @@ static int pcf50633_resume(struct device *dev)
 	struct pcf50633_data *pcf = i2c_get_clientdata(client);
 	int i;
 
-	mutex_lock(&pcf->lock);
+	printk(KERN_INFO"a\n");
+	/* mutex_lock(&pcf->lock); */  /* resume in atomic context */
 
 	__reg_write(pcf, PCF50633_REG_LEDENA, 0x01);
+	printk(KERN_INFO"b\n");
 
 	/* Resume all saved registers that don't "survive" standby state */
 	__reg_write(pcf, PCF50633_REG_INT1M, pcf->standby_regs.int1m);
@@ -1936,6 +1938,7 @@ static int pcf50633_resume(struct device *dev)
 	__reg_write(pcf, PCF50633_REG_INT3M, pcf->standby_regs.int3m);
 	__reg_write(pcf, PCF50633_REG_INT4M, pcf->standby_regs.int4m);
 	__reg_write(pcf, PCF50633_REG_INT5M, pcf->standby_regs.int5m);
+	printk(KERN_INFO"c\n");
 
 	__reg_write(pcf, PCF50633_REG_OOCTIM2, pcf->standby_regs.ooctim2);
 	__reg_write(pcf, PCF50633_REG_AUTOOUT, pcf->standby_regs.autoout);
@@ -1949,14 +1952,16 @@ static int pcf50633_resume(struct device *dev)
 	__reg_write(pcf, PCF50633_REG_LEDOUT, pcf->standby_regs.ledout);
 	__reg_write(pcf, PCF50633_REG_LEDENA, pcf->standby_regs.ledena);
 	__reg_write(pcf, PCF50633_REG_LEDDIM, pcf->standby_regs.leddim);
+	printk(KERN_INFO"d\n");
 	/* FIXME: one big read? */
 	for (i = 0; i < 7; i++) {
 		u_int8_t reg_out = PCF50633_REG_LDO1OUT + 2*i;
 		__reg_write(pcf, reg_out, pcf->standby_regs.ldo[i].out);
 		__reg_write(pcf, reg_out+1, pcf->standby_regs.ldo[i].ena);
 	}
+	printk(KERN_INFO"e\n");
 
-	mutex_unlock(&pcf->lock);
+	/* mutex_unlock(&pcf->lock); */ /* resume in atomic context */
 
 	pcf50633_irq(pcf->irq, pcf);
 
-- 
1.5.6.5