aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorLinus Walleij <linus.walleij@linaro.org>2011-05-15 16:53:56 -0400
committerLinus Walleij <linus.walleij@linaro.org>2011-05-24 16:14:31 -0400
commit650c2a2145981696c414be1d540a32447d0e353e (patch)
treef05aadb054bffb88fee3056b78310b148ceed9bf /drivers
parent118718905de6e32c11e09a8f41c7abff6155ba19 (diff)
mach-ux500: move the DB8500 PRCMU driver to MFD
We have decided that this function arbiter fits better in the MFD subsystem. Since we need to concatenate the split header files we move it basically like this: mv mach-ux500/prcmu-db8500.c drivers/mfd/db8500-prcmu.c mv mach-ux500/include/mach/prcmu-defs.h include/linux/mfd/db8500-prcmu.h mv mach-ux500/include/mach/prcmu-regs.h drivers/mfd/db8500-prcmu-regs.h mach-ux500/include/mach/prcmu.h >> include/linux/mfd/db8500-prcmu.h rm arch/arm/mach-ux500/include/mach/prcmu.h Then we update different #include statements and Makefile orders etc to make the PRCMU driver compile, link and boot in the new place without really changing any code. Acked-by: Samuel Ortiz <sameo@linux.intel.com> Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/mfd/Kconfig12
-rw-r--r--drivers/mfd/Makefile4
-rw-r--r--drivers/mfd/ab8500-i2c.c3
-rw-r--r--drivers/mfd/db8500-prcmu-regs.h94
-rw-r--r--drivers/mfd/db8500-prcmu.c395
5 files changed, 504 insertions, 4 deletions
diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig
index 3ed3ff06be5d..7eaeb9750793 100644
--- a/drivers/mfd/Kconfig
+++ b/drivers/mfd/Kconfig
@@ -538,7 +538,7 @@ config AB8500_CORE
538 538
539config AB8500_I2C_CORE 539config AB8500_I2C_CORE
540 bool "AB8500 register access via PRCMU I2C" 540 bool "AB8500 register access via PRCMU I2C"
541 depends on AB8500_CORE && UX500_SOC_DB8500 541 depends on AB8500_CORE && MFD_DB8500_PRCMU
542 default y 542 default y
543 help 543 help
544 This enables register access to the AB8500 chip via PRCMU I2C. 544 This enables register access to the AB8500 chip via PRCMU I2C.
@@ -575,6 +575,16 @@ config AB3550_CORE
575 LEDs, vibrator, system power and temperature, power management 575 LEDs, vibrator, system power and temperature, power management
576 and ALSA sound. 576 and ALSA sound.
577 577
578config MFD_DB8500_PRCMU
579 bool "ST-Ericsson DB8500 Power Reset Control Management Unit"
580 depends on UX500_SOC_DB8500
581 select MFD_CORE
582 help
583 Select this option to enable support for the DB8500 Power Reset
584 and Control Management Unit. This is basically an autonomous
585 system controller running an XP70 microprocessor, which is accessed
586 through a register map.
587
578config MFD_CS5535 588config MFD_CS5535
579 tristate "Support for CS5535 and CS5536 southbridge core functions" 589 tristate "Support for CS5535 and CS5536 southbridge core functions"
580 select MFD_CORE 590 select MFD_CORE
diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile
index 419caa9d7dcf..814c57a692a9 100644
--- a/drivers/mfd/Makefile
+++ b/drivers/mfd/Makefile
@@ -74,9 +74,11 @@ obj-$(CONFIG_AB3100_CORE) += ab3100-core.o
74obj-$(CONFIG_AB3100_OTP) += ab3100-otp.o 74obj-$(CONFIG_AB3100_OTP) += ab3100-otp.o
75obj-$(CONFIG_AB3550_CORE) += ab3550-core.o 75obj-$(CONFIG_AB3550_CORE) += ab3550-core.o
76obj-$(CONFIG_AB8500_CORE) += ab8500-core.o ab8500-sysctrl.o 76obj-$(CONFIG_AB8500_CORE) += ab8500-core.o ab8500-sysctrl.o
77obj-$(CONFIG_AB8500_I2C_CORE) += ab8500-i2c.o
78obj-$(CONFIG_AB8500_DEBUG) += ab8500-debugfs.o 77obj-$(CONFIG_AB8500_DEBUG) += ab8500-debugfs.o
79obj-$(CONFIG_AB8500_GPADC) += ab8500-gpadc.o 78obj-$(CONFIG_AB8500_GPADC) += ab8500-gpadc.o
79obj-$(CONFIG_MFD_DB8500_PRCMU) += db8500-prcmu.o
80# ab8500-i2c need to come after db8500-prcmu (which provides the channel)
81obj-$(CONFIG_AB8500_I2C_CORE) += ab8500-i2c.o
80obj-$(CONFIG_MFD_TIMBERDALE) += timberdale.o 82obj-$(CONFIG_MFD_TIMBERDALE) += timberdale.o
81obj-$(CONFIG_PMIC_ADP5520) += adp5520.o 83obj-$(CONFIG_PMIC_ADP5520) += adp5520.o
82obj-$(CONFIG_LPC_SCH) += lpc_sch.o 84obj-$(CONFIG_LPC_SCH) += lpc_sch.o
diff --git a/drivers/mfd/ab8500-i2c.c b/drivers/mfd/ab8500-i2c.c
index 821e6b86afd2..9be541c6b004 100644
--- a/drivers/mfd/ab8500-i2c.c
+++ b/drivers/mfd/ab8500-i2c.c
@@ -11,8 +11,7 @@
11#include <linux/module.h> 11#include <linux/module.h>
12#include <linux/platform_device.h> 12#include <linux/platform_device.h>
13#include <linux/mfd/ab8500.h> 13#include <linux/mfd/ab8500.h>
14 14#include <linux/mfd/db8500-prcmu.h>
15#include <mach/prcmu.h>
16 15
17static int ab8500_i2c_write(struct ab8500 *ab8500, u16 addr, u8 data) 16static int ab8500_i2c_write(struct ab8500 *ab8500, u16 addr, u8 data)
18{ 17{
diff --git a/drivers/mfd/db8500-prcmu-regs.h b/drivers/mfd/db8500-prcmu-regs.h
new file mode 100644
index 000000000000..c1226da19bfb
--- /dev/null
+++ b/drivers/mfd/db8500-prcmu-regs.h
@@ -0,0 +1,94 @@
1/*
2 * Copyright (C) STMicroelectronics 2009
3 * Copyright (C) ST-Ericsson SA 2010
4 *
5 * Author: Kumar Sanghvi <kumar.sanghvi@stericsson.com>
6 * Author: Sundar Iyer <sundar.iyer@stericsson.com>
7 *
8 * License Terms: GNU General Public License v2
9 *
10 * PRCM Unit registers
11 */
12
13#ifndef __MACH_PRCMU_REGS_H
14#define __MACH_PRCMU_REGS_H
15
16#include <mach/hardware.h>
17
18#define PRCM_ARM_PLLDIVPS (_PRCMU_BASE + 0x118)
19#define PRCM_ARM_CHGCLKREQ (_PRCMU_BASE + 0x114)
20#define PRCM_PLLARM_ENABLE (_PRCMU_BASE + 0x98)
21#define PRCM_ARMCLKFIX_MGT (_PRCMU_BASE + 0x0)
22#define PRCM_A9_RESETN_CLR (_PRCMU_BASE + 0x1f4)
23#define PRCM_A9_RESETN_SET (_PRCMU_BASE + 0x1f0)
24#define PRCM_ARM_LS_CLAMP (_PRCMU_BASE + 0x30c)
25#define PRCM_SRAM_A9 (_PRCMU_BASE + 0x308)
26
27/* ARM WFI Standby signal register */
28#define PRCM_ARM_WFI_STANDBY (_PRCMU_BASE + 0x130)
29#define PRCMU_IOCR (_PRCMU_BASE + 0x310)
30
31/* CPU mailbox registers */
32#define PRCM_MBOX_CPU_VAL (_PRCMU_BASE + 0x0fc)
33#define PRCM_MBOX_CPU_SET (_PRCMU_BASE + 0x100)
34#define PRCM_MBOX_CPU_CLR (_PRCMU_BASE + 0x104)
35
36/* Dual A9 core interrupt management unit registers */
37#define PRCM_A9_MASK_REQ (_PRCMU_BASE + 0x328)
38#define PRCM_A9_MASK_ACK (_PRCMU_BASE + 0x32c)
39#define PRCM_ARMITMSK31TO0 (_PRCMU_BASE + 0x11c)
40#define PRCM_ARMITMSK63TO32 (_PRCMU_BASE + 0x120)
41#define PRCM_ARMITMSK95TO64 (_PRCMU_BASE + 0x124)
42#define PRCM_ARMITMSK127TO96 (_PRCMU_BASE + 0x128)
43#define PRCM_POWER_STATE_VAL (_PRCMU_BASE + 0x25C)
44#define PRCM_ARMITVAL31TO0 (_PRCMU_BASE + 0x260)
45#define PRCM_ARMITVAL63TO32 (_PRCMU_BASE + 0x264)
46#define PRCM_ARMITVAL95TO64 (_PRCMU_BASE + 0x268)
47#define PRCM_ARMITVAL127TO96 (_PRCMU_BASE + 0x26C)
48
49#define PRCM_HOSTACCESS_REQ (_PRCMU_BASE + 0x334)
50#define ARM_WAKEUP_MODEM 0x1
51
52#define PRCM_ARM_IT1_CLEAR (_PRCMU_BASE + 0x48C)
53#define PRCM_ARM_IT1_VAL (_PRCMU_BASE + 0x494)
54#define PRCM_HOLD_EVT (_PRCMU_BASE + 0x174)
55
56#define PRCM_ITSTATUS0 (_PRCMU_BASE + 0x148)
57#define PRCM_ITSTATUS1 (_PRCMU_BASE + 0x150)
58#define PRCM_ITSTATUS2 (_PRCMU_BASE + 0x158)
59#define PRCM_ITSTATUS3 (_PRCMU_BASE + 0x160)
60#define PRCM_ITSTATUS4 (_PRCMU_BASE + 0x168)
61#define PRCM_ITSTATUS5 (_PRCMU_BASE + 0x484)
62#define PRCM_ITCLEAR5 (_PRCMU_BASE + 0x488)
63#define PRCM_ARMIT_MASKXP70_IT (_PRCMU_BASE + 0x1018)
64
65/* System reset register */
66#define PRCM_APE_SOFTRST (_PRCMU_BASE + 0x228)
67
68/* Level shifter and clamp control registers */
69#define PRCM_MMIP_LS_CLAMP_SET (_PRCMU_BASE + 0x420)
70#define PRCM_MMIP_LS_CLAMP_CLR (_PRCMU_BASE + 0x424)
71
72/* PRCMU clock/PLL/reset registers */
73#define PRCM_PLLDSI_FREQ (_PRCMU_BASE + 0x500)
74#define PRCM_PLLDSI_ENABLE (_PRCMU_BASE + 0x504)
75#define PRCM_LCDCLK_MGT (_PRCMU_BASE + 0x044)
76#define PRCM_MCDECLK_MGT (_PRCMU_BASE + 0x064)
77#define PRCM_HDMICLK_MGT (_PRCMU_BASE + 0x058)
78#define PRCM_TVCLK_MGT (_PRCMU_BASE + 0x07c)
79#define PRCM_DSI_PLLOUT_SEL (_PRCMU_BASE + 0x530)
80#define PRCM_DSITVCLK_DIV (_PRCMU_BASE + 0x52C)
81#define PRCM_APE_RESETN_SET (_PRCMU_BASE + 0x1E4)
82#define PRCM_APE_RESETN_CLR (_PRCMU_BASE + 0x1E8)
83
84/* ePOD and memory power signal control registers */
85#define PRCM_EPOD_C_SET (_PRCMU_BASE + 0x410)
86#define PRCM_SRAM_LS_SLEEP (_PRCMU_BASE + 0x304)
87
88/* Debug power control unit registers */
89#define PRCM_POWER_STATE_SET (_PRCMU_BASE + 0x254)
90
91/* Miscellaneous unit registers */
92#define PRCM_DSI_SW_RESET (_PRCMU_BASE + 0x324)
93
94#endif /* __MACH_PRCMU_REGS_H */
diff --git a/drivers/mfd/db8500-prcmu.c b/drivers/mfd/db8500-prcmu.c
new file mode 100644
index 000000000000..31f18c8c6bf8
--- /dev/null
+++ b/drivers/mfd/db8500-prcmu.c
@@ -0,0 +1,395 @@
1/*
2 * Copyright (C) STMicroelectronics 2009
3 * Copyright (C) ST-Ericsson SA 2010
4 *
5 * License Terms: GNU General Public License v2
6 * Author: Kumar Sanghvi <kumar.sanghvi@stericsson.com>
7 * Author: Sundar Iyer <sundar.iyer@stericsson.com>
8 * Author: Mattias Nilsson <mattias.i.nilsson@stericsson.com>
9 *
10 * U8500 PRCM Unit interface driver
11 *
12 */
13#include <linux/kernel.h>
14#include <linux/module.h>
15#include <linux/errno.h>
16#include <linux/err.h>
17#include <linux/io.h>
18#include <linux/mutex.h>
19#include <linux/completion.h>
20#include <linux/jiffies.h>
21#include <linux/bitops.h>
22#include <linux/interrupt.h>
23#include <linux/mfd/db8500-prcmu.h>
24
25#include <mach/hardware.h>
26
27#include "db8500-prcmu-regs.h"
28
29/* Global var to runtime determine TCDM base for v2 or v1 */
30static __iomem void *tcdm_base;
31
32#define _MBOX_HEADER (tcdm_base + 0xFE8)
33#define MBOX_HEADER_REQ_MB0 (_MBOX_HEADER + 0x0)
34
35#define REQ_MB1 (tcdm_base + 0xFD0)
36#define REQ_MB5 (tcdm_base + 0xE44)
37
38#define REQ_MB1_ARMOPP (REQ_MB1 + 0x0)
39#define REQ_MB1_APEOPP (REQ_MB1 + 0x1)
40#define REQ_MB1_BOOSTOPP (REQ_MB1 + 0x2)
41
42#define ACK_MB1 (tcdm_base + 0xE04)
43#define ACK_MB5 (tcdm_base + 0xDF4)
44
45#define ACK_MB1_CURR_ARMOPP (ACK_MB1 + 0x0)
46#define ACK_MB1_CURR_APEOPP (ACK_MB1 + 0x1)
47
48#define REQ_MB5_I2C_SLAVE_OP (REQ_MB5)
49#define REQ_MB5_I2C_HW_BITS (REQ_MB5 + 1)
50#define REQ_MB5_I2C_REG (REQ_MB5 + 2)
51#define REQ_MB5_I2C_VAL (REQ_MB5 + 3)
52
53#define ACK_MB5_I2C_STATUS (ACK_MB5 + 1)
54#define ACK_MB5_I2C_VAL (ACK_MB5 + 3)
55
56#define PRCM_AVS_VARM_MAX_OPP (tcdm_base + 0x2E4)
57#define PRCM_AVS_ISMODEENABLE 7
58#define PRCM_AVS_ISMODEENABLE_MASK (1 << PRCM_AVS_ISMODEENABLE)
59
60#define I2C_WRITE(slave) \
61 (((slave) << 1) | (cpu_is_u8500v2() ? BIT(6) : 0))
62#define I2C_READ(slave) \
63 (((slave) << 1) | (cpu_is_u8500v2() ? BIT(6) : 0) | BIT(0))
64#define I2C_STOP_EN BIT(3)
65
66enum mb1_h {
67 MB1H_ARM_OPP = 1,
68 MB1H_APE_OPP,
69 MB1H_ARM_APE_OPP,
70};
71
72static struct {
73 struct mutex lock;
74 struct completion work;
75 struct {
76 u8 arm_opp;
77 u8 ape_opp;
78 u8 arm_status;
79 u8 ape_status;
80 } ack;
81} mb1_transfer;
82
83enum ack_mb5_status {
84 I2C_WR_OK = 0x01,
85 I2C_RD_OK = 0x02,
86};
87
88#define MBOX_BIT BIT
89#define NUM_MBOX 8
90
91static struct {
92 struct mutex lock;
93 struct completion work;
94 bool failed;
95 struct {
96 u8 status;
97 u8 value;
98 } ack;
99} mb5_transfer;
100
101/**
102 * prcmu_abb_read() - Read register value(s) from the ABB.
103 * @slave: The I2C slave address.
104 * @reg: The (start) register address.
105 * @value: The read out value(s).
106 * @size: The number of registers to read.
107 *
108 * Reads register value(s) from the ABB.
109 * @size has to be 1 for the current firmware version.
110 */
111int prcmu_abb_read(u8 slave, u8 reg, u8 *value, u8 size)
112{
113 int r;
114
115 if (size != 1)
116 return -EINVAL;
117
118 r = mutex_lock_interruptible(&mb5_transfer.lock);
119 if (r)
120 return r;
121
122 while (readl(PRCM_MBOX_CPU_VAL) & MBOX_BIT(5))
123 cpu_relax();
124
125 writeb(I2C_READ(slave), REQ_MB5_I2C_SLAVE_OP);
126 writeb(I2C_STOP_EN, REQ_MB5_I2C_HW_BITS);
127 writeb(reg, REQ_MB5_I2C_REG);
128
129 writel(MBOX_BIT(5), PRCM_MBOX_CPU_SET);
130 if (!wait_for_completion_timeout(&mb5_transfer.work,
131 msecs_to_jiffies(500))) {
132 pr_err("prcmu: prcmu_abb_read timed out.\n");
133 r = -EIO;
134 goto unlock_and_return;
135 }
136 r = ((mb5_transfer.ack.status == I2C_RD_OK) ? 0 : -EIO);
137 if (!r)
138 *value = mb5_transfer.ack.value;
139
140unlock_and_return:
141 mutex_unlock(&mb5_transfer.lock);
142 return r;
143}
144EXPORT_SYMBOL(prcmu_abb_read);
145
146/**
147 * prcmu_abb_write() - Write register value(s) to the ABB.
148 * @slave: The I2C slave address.
149 * @reg: The (start) register address.
150 * @value: The value(s) to write.
151 * @size: The number of registers to write.
152 *
153 * Reads register value(s) from the ABB.
154 * @size has to be 1 for the current firmware version.
155 */
156int prcmu_abb_write(u8 slave, u8 reg, u8 *value, u8 size)
157{
158 int r;
159
160 if (size != 1)
161 return -EINVAL;
162
163 r = mutex_lock_interruptible(&mb5_transfer.lock);
164 if (r)
165 return r;
166
167
168 while (readl(PRCM_MBOX_CPU_VAL) & MBOX_BIT(5))
169 cpu_relax();
170
171 writeb(I2C_WRITE(slave), REQ_MB5_I2C_SLAVE_OP);
172 writeb(I2C_STOP_EN, REQ_MB5_I2C_HW_BITS);
173 writeb(reg, REQ_MB5_I2C_REG);
174 writeb(*value, REQ_MB5_I2C_VAL);
175
176 writel(MBOX_BIT(5), PRCM_MBOX_CPU_SET);
177 if (!wait_for_completion_timeout(&mb5_transfer.work,
178 msecs_to_jiffies(500))) {
179 pr_err("prcmu: prcmu_abb_write timed out.\n");
180 r = -EIO;
181 goto unlock_and_return;
182 }
183 r = ((mb5_transfer.ack.status == I2C_WR_OK) ? 0 : -EIO);
184
185unlock_and_return:
186 mutex_unlock(&mb5_transfer.lock);
187 return r;
188}
189EXPORT_SYMBOL(prcmu_abb_write);
190
191static int set_ape_cpu_opps(u8 header, enum prcmu_ape_opp ape_opp,
192 enum prcmu_cpu_opp cpu_opp)
193{
194 bool do_ape;
195 bool do_arm;
196 int err = 0;
197
198 do_ape = ((header == MB1H_APE_OPP) || (header == MB1H_ARM_APE_OPP));
199 do_arm = ((header == MB1H_ARM_OPP) || (header == MB1H_ARM_APE_OPP));
200
201 mutex_lock(&mb1_transfer.lock);
202
203 while (readl(PRCM_MBOX_CPU_VAL) & MBOX_BIT(1))
204 cpu_relax();
205
206 writeb(0, MBOX_HEADER_REQ_MB0);
207 writeb(cpu_opp, REQ_MB1_ARMOPP);
208 writeb(ape_opp, REQ_MB1_APEOPP);
209 writeb(0, REQ_MB1_BOOSTOPP);
210 writel(MBOX_BIT(1), PRCM_MBOX_CPU_SET);
211 wait_for_completion(&mb1_transfer.work);
212 if ((do_ape) && (mb1_transfer.ack.ape_status != 0))
213 err = -EIO;
214 if ((do_arm) && (mb1_transfer.ack.arm_status != 0))
215 err = -EIO;
216
217 mutex_unlock(&mb1_transfer.lock);
218
219 return err;
220}
221
222/**
223 * prcmu_set_ape_opp() - Set the OPP of the APE.
224 * @opp: The OPP to set.
225 *
226 * This function sets the OPP of the APE.
227 */
228int prcmu_set_ape_opp(enum prcmu_ape_opp opp)
229{
230 return set_ape_cpu_opps(MB1H_APE_OPP, opp, APE_OPP_NO_CHANGE);
231}
232EXPORT_SYMBOL(prcmu_set_ape_opp);
233
234/**
235 * prcmu_set_cpu_opp() - Set the OPP of the CPU.
236 * @opp: The OPP to set.
237 *
238 * This function sets the OPP of the CPU.
239 */
240int prcmu_set_cpu_opp(enum prcmu_cpu_opp opp)
241{
242 return set_ape_cpu_opps(MB1H_ARM_OPP, CPU_OPP_NO_CHANGE, opp);
243}
244EXPORT_SYMBOL(prcmu_set_cpu_opp);
245
246/**
247 * prcmu_set_ape_cpu_opps() - Set the OPPs of the APE and the CPU.
248 * @ape_opp: The APE OPP to set.
249 * @cpu_opp: The CPU OPP to set.
250 *
251 * This function sets the OPPs of the APE and the CPU.
252 */
253int prcmu_set_ape_cpu_opps(enum prcmu_ape_opp ape_opp,
254 enum prcmu_cpu_opp cpu_opp)
255{
256 return set_ape_cpu_opps(MB1H_ARM_APE_OPP, ape_opp, cpu_opp);
257}
258EXPORT_SYMBOL(prcmu_set_ape_cpu_opps);
259
260/**
261 * prcmu_get_ape_opp() - Get the OPP of the APE.
262 *
263 * This function gets the OPP of the APE.
264 */
265enum prcmu_ape_opp prcmu_get_ape_opp(void)
266{
267 return readb(ACK_MB1_CURR_APEOPP);
268}
269EXPORT_SYMBOL(prcmu_get_ape_opp);
270
271/**
272 * prcmu_get_cpu_opp() - Get the OPP of the CPU.
273 *
274 * This function gets the OPP of the CPU. The OPP is specified in %%.
275 * PRCMU_OPP_EXT is a special OPP value, not specified in %%.
276 */
277int prcmu_get_cpu_opp(void)
278{
279 return readb(ACK_MB1_CURR_ARMOPP);
280}
281EXPORT_SYMBOL(prcmu_get_cpu_opp);
282
283bool prcmu_has_arm_maxopp(void)
284{
285 return (readb(PRCM_AVS_VARM_MAX_OPP) & PRCM_AVS_ISMODEENABLE_MASK)
286 == PRCM_AVS_ISMODEENABLE_MASK;
287}
288
289static void read_mailbox_0(void)
290{
291 writel(MBOX_BIT(0), PRCM_ARM_IT1_CLEAR);
292}
293
294static void read_mailbox_1(void)
295{
296 mb1_transfer.ack.arm_opp = readb(ACK_MB1_CURR_ARMOPP);
297 mb1_transfer.ack.ape_opp = readb(ACK_MB1_CURR_APEOPP);
298 complete(&mb1_transfer.work);
299 writel(MBOX_BIT(1), PRCM_ARM_IT1_CLEAR);
300}
301
302static void read_mailbox_2(void)
303{
304 writel(MBOX_BIT(2), PRCM_ARM_IT1_CLEAR);
305}
306
307static void read_mailbox_3(void)
308{
309 writel(MBOX_BIT(3), PRCM_ARM_IT1_CLEAR);
310}
311
312static void read_mailbox_4(void)
313{
314 writel(MBOX_BIT(4), PRCM_ARM_IT1_CLEAR);
315}
316
317static void read_mailbox_5(void)
318{
319 mb5_transfer.ack.status = readb(ACK_MB5_I2C_STATUS);
320 mb5_transfer.ack.value = readb(ACK_MB5_I2C_VAL);
321 complete(&mb5_transfer.work);
322 writel(MBOX_BIT(5), PRCM_ARM_IT1_CLEAR);
323}
324
325static void read_mailbox_6(void)
326{
327 writel(MBOX_BIT(6), PRCM_ARM_IT1_CLEAR);
328}
329
330static void read_mailbox_7(void)
331{
332 writel(MBOX_BIT(7), PRCM_ARM_IT1_CLEAR);
333}
334
335static void (* const read_mailbox[NUM_MBOX])(void) = {
336 read_mailbox_0,
337 read_mailbox_1,
338 read_mailbox_2,
339 read_mailbox_3,
340 read_mailbox_4,
341 read_mailbox_5,
342 read_mailbox_6,
343 read_mailbox_7
344};
345
346static irqreturn_t prcmu_irq_handler(int irq, void *data)
347{
348 u32 bits;
349 u8 n;
350
351 bits = (readl(PRCM_ARM_IT1_VAL) & (MBOX_BIT(NUM_MBOX) - 1));
352 if (unlikely(!bits))
353 return IRQ_NONE;
354
355 for (n = 0; bits; n++) {
356 if (bits & MBOX_BIT(n)) {
357 bits -= MBOX_BIT(n);
358 read_mailbox[n]();
359 }
360 }
361 return IRQ_HANDLED;
362}
363
364void __init prcmu_early_init(void)
365{
366 if (cpu_is_u8500v11() || cpu_is_u8500ed()) {
367 tcdm_base = __io_address(U8500_PRCMU_TCDM_BASE_V1);
368 } else if (cpu_is_u8500v2()) {
369 tcdm_base = __io_address(U8500_PRCMU_TCDM_BASE);
370 } else {
371 pr_err("prcmu: Unsupported chip version\n");
372 BUG();
373 }
374}
375
376static int __init prcmu_init(void)
377{
378 if (cpu_is_u8500ed()) {
379 pr_err("prcmu: Unsupported chip version\n");
380 return 0;
381 }
382
383 mutex_init(&mb1_transfer.lock);
384 init_completion(&mb1_transfer.work);
385 mutex_init(&mb5_transfer.lock);
386 init_completion(&mb5_transfer.work);
387
388 /* Clean up the mailbox interrupts after pre-kernel code. */
389 writel((MBOX_BIT(NUM_MBOX) - 1), PRCM_ARM_IT1_CLEAR);
390
391 return request_irq(IRQ_DB8500_PRCMU1, prcmu_irq_handler, 0,
392 "prcmu", NULL);
393}
394
395arch_initcall(prcmu_init);