Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

mfd: add DB5500 PRCMU driver

This adds the DB5500 PRCMU driver. Right now this one is pretty
restricted in functionality, exposing a simple interface to send
I2C messages.

Acked-by: Samuel Ortiz <sameo@linux.intel.com>
Signed-off-by: Linus Walleij <linus.walleij@linaro.org>

+623
+1
arch/arm/mach-ux500/Kconfig
··· 12 12 13 13 config UX500_SOC_DB5500 14 14 bool "DB5500" 15 + select MFD_DB5500_PRCMU 15 16 16 17 config UX500_SOC_DB8500 17 18 bool "DB8500"
+3
arch/arm/mach-ux500/cpu.c
··· 9 9 #include <linux/io.h> 10 10 #include <linux/clk.h> 11 11 #include <linux/mfd/db8500-prcmu.h> 12 + #include <linux/mfd/db5500-prcmu.h> 12 13 13 14 #include <asm/cacheflush.h> 14 15 #include <asm/hardware/cache-l2x0.h> ··· 50 49 * Init clocks here so that they are available for system timer 51 50 * initialization. 52 51 */ 52 + if (cpu_is_u5500()) 53 + db5500_prcmu_early_init(); 53 54 if (cpu_is_u8500()) 54 55 prcmu_early_init(); 55 56 clk_init();
+10
drivers/mfd/Kconfig
··· 585 585 system controller running an XP70 microprocessor, which is accessed 586 586 through a register map. 587 587 588 + config MFD_DB5500_PRCMU 589 + bool "ST-Ericsson DB5500 Power Reset Control Management Unit" 590 + depends on UX500_SOC_DB5500 591 + select MFD_CORE 592 + help 593 + Select this option to enable support for the DB5500 Power Reset 594 + and Control Management Unit. This is basically an autonomous 595 + system controller running an XP70 microprocessor, which is accessed 596 + through a register map. 597 + 588 598 config MFD_CS5535 589 599 tristate "Support for CS5535 and CS5536 southbridge core functions" 590 600 select MFD_CORE
+1
drivers/mfd/Makefile
··· 79 79 obj-$(CONFIG_MFD_DB8500_PRCMU) += db8500-prcmu.o 80 80 # ab8500-i2c need to come after db8500-prcmu (which provides the channel) 81 81 obj-$(CONFIG_AB8500_I2C_CORE) += ab8500-i2c.o 82 + obj-$(CONFIG_MFD_DB5500_PRCMU) += db5500-prcmu.o 82 83 obj-$(CONFIG_MFD_TIMBERDALE) += timberdale.o 83 84 obj-$(CONFIG_PMIC_ADP5520) += adp5520.o 84 85 obj-$(CONFIG_LPC_SCH) += lpc_sch.o
+115
drivers/mfd/db5500-prcmu-regs.h
··· 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_PLLDIVPS_ARM_BRM_RATE 0x3f 20 + #define PRCM_ARM_PLLDIVPS_MAX_MASK 0xf 21 + 22 + #define PRCM_PLLARM_LOCKP (_PRCMU_BASE + 0x0a8) 23 + #define PRCM_PLLARM_LOCKP_PRCM_PLLARM_LOCKP3 0x2 24 + 25 + #define PRCM_ARM_CHGCLKREQ (_PRCMU_BASE + 0x114) 26 + #define PRCM_ARM_CHGCLKREQ_PRCM_ARM_CHGCLKREQ 0x1 27 + 28 + #define PRCM_PLLARM_ENABLE (_PRCMU_BASE + 0x98) 29 + #define PRCM_PLLARM_ENABLE_PRCM_PLLARM_ENABLE 0x1 30 + #define PRCM_PLLARM_ENABLE_PRCM_PLLARM_COUNTON 0x100 31 + 32 + #define PRCM_ARMCLKFIX_MGT (_PRCMU_BASE + 0x0) 33 + #define PRCM_A9_RESETN_CLR (_PRCMU_BASE + 0x1f4) 34 + #define PRCM_A9_RESETN_SET (_PRCMU_BASE + 0x1f0) 35 + #define PRCM_ARM_LS_CLAMP (_PRCMU_BASE + 0x30c) 36 + #define PRCM_SRAM_A9 (_PRCMU_BASE + 0x308) 37 + 38 + /* ARM WFI Standby signal register */ 39 + #define PRCM_ARM_WFI_STANDBY (_PRCMU_BASE + 0x130) 40 + #define PRCM_IOCR (_PRCMU_BASE + 0x310) 41 + #define PRCM_IOCR_IOFORCE 0x1 42 + 43 + /* CPU mailbox registers */ 44 + #define PRCM_MBOX_CPU_VAL (_PRCMU_BASE + 0x0fc) 45 + #define PRCM_MBOX_CPU_SET (_PRCMU_BASE + 0x100) 46 + #define PRCM_MBOX_CPU_CLR (_PRCMU_BASE + 0x104) 47 + 48 + /* Dual A9 core interrupt management unit registers */ 49 + #define PRCM_A9_MASK_REQ (_PRCMU_BASE + 0x328) 50 + #define PRCM_A9_MASK_REQ_PRCM_A9_MASK_REQ 0x1 51 + 52 + #define PRCM_A9_MASK_ACK (_PRCMU_BASE + 0x32c) 53 + #define PRCM_ARMITMSK31TO0 (_PRCMU_BASE + 0x11c) 54 + #define PRCM_ARMITMSK63TO32 (_PRCMU_BASE + 0x120) 55 + #define PRCM_ARMITMSK95TO64 (_PRCMU_BASE + 0x124) 56 + #define PRCM_ARMITMSK127TO96 (_PRCMU_BASE + 0x128) 57 + #define PRCM_POWER_STATE_VAL (_PRCMU_BASE + 0x25C) 58 + #define PRCM_ARMITVAL31TO0 (_PRCMU_BASE + 0x260) 59 + #define PRCM_ARMITVAL63TO32 (_PRCMU_BASE + 0x264) 60 + #define PRCM_ARMITVAL95TO64 (_PRCMU_BASE + 0x268) 61 + #define PRCM_ARMITVAL127TO96 (_PRCMU_BASE + 0x26C) 62 + 63 + #define PRCM_HOSTACCESS_REQ (_PRCMU_BASE + 0x334) 64 + #define ARM_WAKEUP_MODEM 0x1 65 + 66 + #define PRCM_ARM_IT1_CLEAR (_PRCMU_BASE + 0x48C) 67 + #define PRCM_ARM_IT1_VAL (_PRCMU_BASE + 0x494) 68 + #define PRCM_HOLD_EVT (_PRCMU_BASE + 0x174) 69 + 70 + #define PRCM_ITSTATUS0 (_PRCMU_BASE + 0x148) 71 + #define PRCM_ITSTATUS1 (_PRCMU_BASE + 0x150) 72 + #define PRCM_ITSTATUS2 (_PRCMU_BASE + 0x158) 73 + #define PRCM_ITSTATUS3 (_PRCMU_BASE + 0x160) 74 + #define PRCM_ITSTATUS4 (_PRCMU_BASE + 0x168) 75 + #define PRCM_ITSTATUS5 (_PRCMU_BASE + 0x484) 76 + #define PRCM_ITCLEAR5 (_PRCMU_BASE + 0x488) 77 + #define PRCM_ARMIT_MASKXP70_IT (_PRCMU_BASE + 0x1018) 78 + 79 + /* System reset register */ 80 + #define PRCM_APE_SOFTRST (_PRCMU_BASE + 0x228) 81 + 82 + /* Level shifter and clamp control registers */ 83 + #define PRCM_MMIP_LS_CLAMP_SET (_PRCMU_BASE + 0x420) 84 + #define PRCM_MMIP_LS_CLAMP_CLR (_PRCMU_BASE + 0x424) 85 + 86 + /* PRCMU clock/PLL/reset registers */ 87 + #define PRCM_PLLDSI_FREQ (_PRCMU_BASE + 0x500) 88 + #define PRCM_PLLDSI_ENABLE (_PRCMU_BASE + 0x504) 89 + #define PRCM_PLLDSI_LOCKP (_PRCMU_BASE + 0x508) 90 + #define PRCM_LCDCLK_MGT (_PRCMU_BASE + 0x044) 91 + #define PRCM_MCDECLK_MGT (_PRCMU_BASE + 0x064) 92 + #define PRCM_HDMICLK_MGT (_PRCMU_BASE + 0x058) 93 + #define PRCM_TVCLK_MGT (_PRCMU_BASE + 0x07c) 94 + #define PRCM_DSI_PLLOUT_SEL (_PRCMU_BASE + 0x530) 95 + #define PRCM_DSITVCLK_DIV (_PRCMU_BASE + 0x52C) 96 + #define PRCM_PLLDSI_LOCKP (_PRCMU_BASE + 0x508) 97 + #define PRCM_APE_RESETN_SET (_PRCMU_BASE + 0x1E4) 98 + #define PRCM_APE_RESETN_CLR (_PRCMU_BASE + 0x1E8) 99 + #define PRCM_CLKOCR (_PRCMU_BASE + 0x1CC) 100 + 101 + /* ePOD and memory power signal control registers */ 102 + #define PRCM_EPOD_C_SET (_PRCMU_BASE + 0x410) 103 + #define PRCM_SRAM_LS_SLEEP (_PRCMU_BASE + 0x304) 104 + 105 + /* Debug power control unit registers */ 106 + #define PRCM_POWER_STATE_SET (_PRCMU_BASE + 0x254) 107 + 108 + /* Miscellaneous unit registers */ 109 + #define PRCM_DSI_SW_RESET (_PRCMU_BASE + 0x324) 110 + #define PRCM_GPIOCR (_PRCMU_BASE + 0x138) 111 + #define PRCM_GPIOCR_DBG_STM_MOD_CMD1 0x800 112 + #define PRCM_GPIOCR_DBG_UARTMOD_CMD0 0x1 113 + 114 + 115 + #endif /* __MACH_PRCMU__REGS_H */
+448
drivers/mfd/db5500-prcmu.c
··· 1 + /* 2 + * Copyright (C) ST-Ericsson SA 2010 3 + * 4 + * License Terms: GNU General Public License v2 5 + * Author: Mattias Nilsson <mattias.i.nilsson@stericsson.com> 6 + * 7 + * U5500 PRCM Unit interface driver 8 + */ 9 + #include <linux/module.h> 10 + #include <linux/kernel.h> 11 + #include <linux/delay.h> 12 + #include <linux/errno.h> 13 + #include <linux/err.h> 14 + #include <linux/spinlock.h> 15 + #include <linux/io.h> 16 + #include <linux/slab.h> 17 + #include <linux/mutex.h> 18 + #include <linux/completion.h> 19 + #include <linux/irq.h> 20 + #include <linux/jiffies.h> 21 + #include <linux/bitops.h> 22 + #include <linux/interrupt.h> 23 + #include <linux/mfd/db5500-prcmu.h> 24 + #include <mach/hardware.h> 25 + #include <mach/irqs.h> 26 + #include <mach/db5500-regs.h> 27 + #include "db5500-prcmu-regs.h" 28 + 29 + #define _PRCM_MB_HEADER (tcdm_base + 0xFE8) 30 + #define PRCM_REQ_MB0_HEADER (_PRCM_MB_HEADER + 0x0) 31 + #define PRCM_REQ_MB1_HEADER (_PRCM_MB_HEADER + 0x1) 32 + #define PRCM_REQ_MB2_HEADER (_PRCM_MB_HEADER + 0x2) 33 + #define PRCM_REQ_MB3_HEADER (_PRCM_MB_HEADER + 0x3) 34 + #define PRCM_REQ_MB4_HEADER (_PRCM_MB_HEADER + 0x4) 35 + #define PRCM_REQ_MB5_HEADER (_PRCM_MB_HEADER + 0x5) 36 + #define PRCM_REQ_MB6_HEADER (_PRCM_MB_HEADER + 0x6) 37 + #define PRCM_REQ_MB7_HEADER (_PRCM_MB_HEADER + 0x7) 38 + #define PRCM_ACK_MB0_HEADER (_PRCM_MB_HEADER + 0x8) 39 + #define PRCM_ACK_MB1_HEADER (_PRCM_MB_HEADER + 0x9) 40 + #define PRCM_ACK_MB2_HEADER (_PRCM_MB_HEADER + 0xa) 41 + #define PRCM_ACK_MB3_HEADER (_PRCM_MB_HEADER + 0xb) 42 + #define PRCM_ACK_MB4_HEADER (_PRCM_MB_HEADER + 0xc) 43 + #define PRCM_ACK_MB5_HEADER (_PRCM_MB_HEADER + 0xd) 44 + #define PRCM_ACK_MB6_HEADER (_PRCM_MB_HEADER + 0xe) 45 + #define PRCM_ACK_MB7_HEADER (_PRCM_MB_HEADER + 0xf) 46 + 47 + /* Req Mailboxes */ 48 + #define PRCM_REQ_MB0 (tcdm_base + 0xFD8) 49 + #define PRCM_REQ_MB1 (tcdm_base + 0xFCC) 50 + #define PRCM_REQ_MB2 (tcdm_base + 0xFC4) 51 + #define PRCM_REQ_MB3 (tcdm_base + 0xFC0) 52 + #define PRCM_REQ_MB4 (tcdm_base + 0xF98) 53 + #define PRCM_REQ_MB5 (tcdm_base + 0xF90) 54 + #define PRCM_REQ_MB6 (tcdm_base + 0xF8C) 55 + #define PRCM_REQ_MB7 (tcdm_base + 0xF84) 56 + 57 + /* Ack Mailboxes */ 58 + #define PRCM_ACK_MB0 (tcdm_base + 0xF38) 59 + #define PRCM_ACK_MB1 (tcdm_base + 0xF30) 60 + #define PRCM_ACK_MB2 (tcdm_base + 0xF24) 61 + #define PRCM_ACK_MB3 (tcdm_base + 0xF20) 62 + #define PRCM_ACK_MB4 (tcdm_base + 0xF1C) 63 + #define PRCM_ACK_MB5 (tcdm_base + 0xF14) 64 + #define PRCM_ACK_MB6 (tcdm_base + 0xF0C) 65 + #define PRCM_ACK_MB7 (tcdm_base + 0xF08) 66 + 67 + enum mb_return_code { 68 + RC_SUCCESS, 69 + RC_FAIL, 70 + }; 71 + 72 + /* Mailbox 0 headers. */ 73 + enum mb0_header { 74 + /* request */ 75 + RMB0H_PWR_STATE_TRANS = 1, 76 + RMB0H_WAKE_UP_CFG, 77 + RMB0H_RD_WAKE_UP_ACK, 78 + /* acknowledge */ 79 + AMB0H_WAKE_UP = 1, 80 + }; 81 + 82 + /* Mailbox 5 headers. */ 83 + enum mb5_header { 84 + MB5H_I2C_WRITE = 1, 85 + MB5H_I2C_READ, 86 + }; 87 + 88 + /* Request mailbox 5 fields. */ 89 + #define PRCM_REQ_MB5_I2C_SLAVE (PRCM_REQ_MB5 + 0) 90 + #define PRCM_REQ_MB5_I2C_REG (PRCM_REQ_MB5 + 1) 91 + #define PRCM_REQ_MB5_I2C_SIZE (PRCM_REQ_MB5 + 2) 92 + #define PRCM_REQ_MB5_I2C_DATA (PRCM_REQ_MB5 + 4) 93 + 94 + /* Acknowledge mailbox 5 fields. */ 95 + #define PRCM_ACK_MB5_RETURN_CODE (PRCM_ACK_MB5 + 0) 96 + #define PRCM_ACK_MB5_I2C_DATA (PRCM_ACK_MB5 + 4) 97 + 98 + #define NUM_MB 8 99 + #define MBOX_BIT BIT 100 + #define ALL_MBOX_BITS (MBOX_BIT(NUM_MB) - 1) 101 + 102 + /* 103 + * Used by MCDE to setup all necessary PRCMU registers 104 + */ 105 + #define PRCMU_RESET_DSIPLL 0x00004000 106 + #define PRCMU_UNCLAMP_DSIPLL 0x00400800 107 + 108 + /* HDMI CLK MGT PLLSW=001 (PLLSOC0), PLLDIV=0x8, = 50 Mhz*/ 109 + #define PRCMU_DSI_CLOCK_SETTING 0x00000128 110 + /* TVCLK_MGT PLLSW=001 (PLLSOC0) PLLDIV=0x13, = 19.05 MHZ */ 111 + #define PRCMU_DSI_LP_CLOCK_SETTING 0x00000135 112 + #define PRCMU_PLLDSI_FREQ_SETTING 0x0004013C 113 + #define PRCMU_DSI_PLLOUT_SEL_SETTING 0x00000002 114 + #define PRCMU_ENABLE_ESCAPE_CLOCK_DIV 0x03000101 115 + #define PRCMU_DISABLE_ESCAPE_CLOCK_DIV 0x00000101 116 + 117 + #define PRCMU_ENABLE_PLLDSI 0x00000001 118 + #define PRCMU_DISABLE_PLLDSI 0x00000000 119 + 120 + #define PRCMU_DSI_RESET_SW 0x00000003 121 + 122 + #define PRCMU_PLLDSI_LOCKP_LOCKED 0x3 123 + 124 + /* 125 + * mb0_transfer - state needed for mailbox 0 communication. 126 + * @lock: The transaction lock. 127 + */ 128 + static struct { 129 + spinlock_t lock; 130 + } mb0_transfer; 131 + 132 + /* 133 + * mb5_transfer - state needed for mailbox 5 communication. 134 + * @lock: The transaction lock. 135 + * @work: The transaction completion structure. 136 + * @ack: Reply ("acknowledge") data. 137 + */ 138 + static struct { 139 + struct mutex lock; 140 + struct completion work; 141 + struct { 142 + u8 header; 143 + u8 status; 144 + u8 value[4]; 145 + } ack; 146 + } mb5_transfer; 147 + 148 + /* PRCMU TCDM base IO address. */ 149 + static __iomem void *tcdm_base; 150 + 151 + /** 152 + * db5500_prcmu_abb_read() - Read register value(s) from the ABB. 153 + * @slave: The I2C slave address. 154 + * @reg: The (start) register address. 155 + * @value: The read out value(s). 156 + * @size: The number of registers to read. 157 + * 158 + * Reads register value(s) from the ABB. 159 + * @size has to be <= 4. 160 + */ 161 + int db5500_prcmu_abb_read(u8 slave, u8 reg, u8 *value, u8 size) 162 + { 163 + int r; 164 + 165 + if ((size < 1) || (4 < size)) 166 + return -EINVAL; 167 + 168 + mutex_lock(&mb5_transfer.lock); 169 + 170 + while (readl(PRCM_MBOX_CPU_VAL) & MBOX_BIT(5)) 171 + cpu_relax(); 172 + writeb(slave, PRCM_REQ_MB5_I2C_SLAVE); 173 + writeb(reg, PRCM_REQ_MB5_I2C_REG); 174 + writeb(size, PRCM_REQ_MB5_I2C_SIZE); 175 + writeb(MB5H_I2C_READ, PRCM_REQ_MB5_HEADER); 176 + 177 + writel(MBOX_BIT(5), PRCM_MBOX_CPU_SET); 178 + wait_for_completion(&mb5_transfer.work); 179 + 180 + r = 0; 181 + if ((mb5_transfer.ack.header == MB5H_I2C_READ) && 182 + (mb5_transfer.ack.status == RC_SUCCESS)) 183 + memcpy(value, mb5_transfer.ack.value, (size_t)size); 184 + else 185 + r = -EIO; 186 + 187 + mutex_unlock(&mb5_transfer.lock); 188 + 189 + return r; 190 + } 191 + 192 + /** 193 + * db5500_prcmu_abb_write() - Write register value(s) to the ABB. 194 + * @slave: The I2C slave address. 195 + * @reg: The (start) register address. 196 + * @value: The value(s) to write. 197 + * @size: The number of registers to write. 198 + * 199 + * Writes register value(s) to the ABB. 200 + * @size has to be <= 4. 201 + */ 202 + int db5500_prcmu_abb_write(u8 slave, u8 reg, u8 *value, u8 size) 203 + { 204 + int r; 205 + 206 + if ((size < 1) || (4 < size)) 207 + return -EINVAL; 208 + 209 + mutex_lock(&mb5_transfer.lock); 210 + 211 + while (readl(PRCM_MBOX_CPU_VAL) & MBOX_BIT(5)) 212 + cpu_relax(); 213 + writeb(slave, PRCM_REQ_MB5_I2C_SLAVE); 214 + writeb(reg, PRCM_REQ_MB5_I2C_REG); 215 + writeb(size, PRCM_REQ_MB5_I2C_SIZE); 216 + memcpy_toio(PRCM_REQ_MB5_I2C_DATA, value, size); 217 + writeb(MB5H_I2C_WRITE, PRCM_REQ_MB5_HEADER); 218 + 219 + writel(MBOX_BIT(5), PRCM_MBOX_CPU_SET); 220 + wait_for_completion(&mb5_transfer.work); 221 + 222 + if ((mb5_transfer.ack.header == MB5H_I2C_WRITE) && 223 + (mb5_transfer.ack.status == RC_SUCCESS)) 224 + r = 0; 225 + else 226 + r = -EIO; 227 + 228 + mutex_unlock(&mb5_transfer.lock); 229 + 230 + return r; 231 + } 232 + 233 + int db5500_prcmu_enable_dsipll(void) 234 + { 235 + int i; 236 + 237 + /* Enable DSIPLL_RESETN resets */ 238 + writel(PRCMU_RESET_DSIPLL, PRCM_APE_RESETN_CLR); 239 + /* Unclamp DSIPLL in/out */ 240 + writel(PRCMU_UNCLAMP_DSIPLL, PRCM_MMIP_LS_CLAMP_CLR); 241 + /* Set DSI PLL FREQ */ 242 + writel(PRCMU_PLLDSI_FREQ_SETTING, PRCM_PLLDSI_FREQ); 243 + writel(PRCMU_DSI_PLLOUT_SEL_SETTING, 244 + PRCM_DSI_PLLOUT_SEL); 245 + /* Enable Escape clocks */ 246 + writel(PRCMU_ENABLE_ESCAPE_CLOCK_DIV, PRCM_DSITVCLK_DIV); 247 + 248 + /* Start DSI PLL */ 249 + writel(PRCMU_ENABLE_PLLDSI, PRCM_PLLDSI_ENABLE); 250 + /* Reset DSI PLL */ 251 + writel(PRCMU_DSI_RESET_SW, PRCM_DSI_SW_RESET); 252 + for (i = 0; i < 10; i++) { 253 + if ((readl(PRCM_PLLDSI_LOCKP) & 254 + PRCMU_PLLDSI_LOCKP_LOCKED) == PRCMU_PLLDSI_LOCKP_LOCKED) 255 + break; 256 + udelay(100); 257 + } 258 + /* Release DSIPLL_RESETN */ 259 + writel(PRCMU_RESET_DSIPLL, PRCM_APE_RESETN_SET); 260 + return 0; 261 + } 262 + 263 + int db5500_prcmu_disable_dsipll(void) 264 + { 265 + /* Disable dsi pll */ 266 + writel(PRCMU_DISABLE_PLLDSI, PRCM_PLLDSI_ENABLE); 267 + /* Disable escapeclock */ 268 + writel(PRCMU_DISABLE_ESCAPE_CLOCK_DIV, PRCM_DSITVCLK_DIV); 269 + return 0; 270 + } 271 + 272 + int db5500_prcmu_set_display_clocks(void) 273 + { 274 + /* HDMI and TVCLK Should be handled somewhere else */ 275 + /* PLLDIV=8, PLLSW=2, CLKEN=1 */ 276 + writel(PRCMU_DSI_CLOCK_SETTING, PRCM_HDMICLK_MGT); 277 + /* PLLDIV=14, PLLSW=2, CLKEN=1 */ 278 + writel(PRCMU_DSI_LP_CLOCK_SETTING, PRCM_TVCLK_MGT); 279 + return 0; 280 + } 281 + 282 + static void ack_dbb_wakeup(void) 283 + { 284 + unsigned long flags; 285 + 286 + spin_lock_irqsave(&mb0_transfer.lock, flags); 287 + 288 + while (readl(PRCM_MBOX_CPU_VAL) & MBOX_BIT(0)) 289 + cpu_relax(); 290 + 291 + writeb(RMB0H_RD_WAKE_UP_ACK, PRCM_REQ_MB0_HEADER); 292 + writel(MBOX_BIT(0), PRCM_MBOX_CPU_SET); 293 + 294 + spin_unlock_irqrestore(&mb0_transfer.lock, flags); 295 + } 296 + 297 + static inline void print_unknown_header_warning(u8 n, u8 header) 298 + { 299 + pr_warning("prcmu: Unknown message header (%d) in mailbox %d.\n", 300 + header, n); 301 + } 302 + 303 + static bool read_mailbox_0(void) 304 + { 305 + bool r; 306 + u8 header; 307 + 308 + header = readb(PRCM_ACK_MB0_HEADER); 309 + switch (header) { 310 + case AMB0H_WAKE_UP: 311 + r = true; 312 + break; 313 + default: 314 + print_unknown_header_warning(0, header); 315 + r = false; 316 + break; 317 + } 318 + writel(MBOX_BIT(0), PRCM_ARM_IT1_CLEAR); 319 + return r; 320 + } 321 + 322 + static bool read_mailbox_1(void) 323 + { 324 + writel(MBOX_BIT(1), PRCM_ARM_IT1_CLEAR); 325 + return false; 326 + } 327 + 328 + static bool read_mailbox_2(void) 329 + { 330 + writel(MBOX_BIT(2), PRCM_ARM_IT1_CLEAR); 331 + return false; 332 + } 333 + 334 + static bool read_mailbox_3(void) 335 + { 336 + writel(MBOX_BIT(3), PRCM_ARM_IT1_CLEAR); 337 + return false; 338 + } 339 + 340 + static bool read_mailbox_4(void) 341 + { 342 + writel(MBOX_BIT(4), PRCM_ARM_IT1_CLEAR); 343 + return false; 344 + } 345 + 346 + static bool read_mailbox_5(void) 347 + { 348 + u8 header; 349 + 350 + header = readb(PRCM_ACK_MB5_HEADER); 351 + switch (header) { 352 + case MB5H_I2C_READ: 353 + memcpy_fromio(mb5_transfer.ack.value, PRCM_ACK_MB5_I2C_DATA, 4); 354 + case MB5H_I2C_WRITE: 355 + mb5_transfer.ack.header = header; 356 + mb5_transfer.ack.status = readb(PRCM_ACK_MB5_RETURN_CODE); 357 + complete(&mb5_transfer.work); 358 + break; 359 + default: 360 + print_unknown_header_warning(5, header); 361 + break; 362 + } 363 + writel(MBOX_BIT(5), PRCM_ARM_IT1_CLEAR); 364 + return false; 365 + } 366 + 367 + static bool read_mailbox_6(void) 368 + { 369 + writel(MBOX_BIT(6), PRCM_ARM_IT1_CLEAR); 370 + return false; 371 + } 372 + 373 + static bool read_mailbox_7(void) 374 + { 375 + writel(MBOX_BIT(7), PRCM_ARM_IT1_CLEAR); 376 + return false; 377 + } 378 + 379 + static bool (* const read_mailbox[NUM_MB])(void) = { 380 + read_mailbox_0, 381 + read_mailbox_1, 382 + read_mailbox_2, 383 + read_mailbox_3, 384 + read_mailbox_4, 385 + read_mailbox_5, 386 + read_mailbox_6, 387 + read_mailbox_7 388 + }; 389 + 390 + static irqreturn_t prcmu_irq_handler(int irq, void *data) 391 + { 392 + u32 bits; 393 + u8 n; 394 + irqreturn_t r; 395 + 396 + bits = (readl(PRCM_ARM_IT1_VAL) & ALL_MBOX_BITS); 397 + if (unlikely(!bits)) 398 + return IRQ_NONE; 399 + 400 + r = IRQ_HANDLED; 401 + for (n = 0; bits; n++) { 402 + if (bits & MBOX_BIT(n)) { 403 + bits -= MBOX_BIT(n); 404 + if (read_mailbox[n]()) 405 + r = IRQ_WAKE_THREAD; 406 + } 407 + } 408 + return r; 409 + } 410 + 411 + static irqreturn_t prcmu_irq_thread_fn(int irq, void *data) 412 + { 413 + ack_dbb_wakeup(); 414 + return IRQ_HANDLED; 415 + } 416 + 417 + void __init db5500_prcmu_early_init(void) 418 + { 419 + tcdm_base = __io_address(U5500_PRCMU_TCDM_BASE); 420 + spin_lock_init(&mb0_transfer.lock); 421 + mutex_init(&mb5_transfer.lock); 422 + init_completion(&mb5_transfer.work); 423 + } 424 + 425 + /** 426 + * prcmu_fw_init - arch init call for the Linux PRCMU fw init logic 427 + * 428 + */ 429 + int __init db5500_prcmu_init(void) 430 + { 431 + int r = 0; 432 + 433 + if (ux500_is_svp() || !cpu_is_u5500()) 434 + return -ENODEV; 435 + 436 + /* Clean up the mailbox interrupts after pre-kernel code. */ 437 + writel(ALL_MBOX_BITS, PRCM_ARM_IT1_CLEAR); 438 + 439 + r = request_threaded_irq(IRQ_DB5500_PRCMU1, prcmu_irq_handler, 440 + prcmu_irq_thread_fn, 0, "prcmu", NULL); 441 + if (r < 0) { 442 + pr_err("prcmu: Failed to allocate IRQ_DB5500_PRCMU1.\n"); 443 + return -EBUSY; 444 + } 445 + return 0; 446 + } 447 + 448 + arch_initcall(db5500_prcmu_init);
+45
include/linux/mfd/db5500-prcmu.h
··· 1 + /* 2 + * Copyright (C) ST-Ericsson SA 2010 3 + * 4 + * License Terms: GNU General Public License v2 5 + * 6 + * U5500 PRCMU API. 7 + */ 8 + #ifndef __MACH_PRCMU_U5500_H 9 + #define __MACH_PRCMU_U5500_H 10 + 11 + #ifdef CONFIG_UX500_SOC_DB5500 12 + 13 + void db5500_prcmu_early_init(void); 14 + 15 + int db5500_prcmu_abb_read(u8 slave, u8 reg, u8 *value, u8 size); 16 + int db5500_prcmu_abb_write(u8 slave, u8 reg, u8 *value, u8 size); 17 + 18 + #else /* !CONFIG_UX500_SOC_DB5500 */ 19 + 20 + static inline void db5500_prcmu_early_init(void) 21 + { 22 + } 23 + 24 + static inline int db5500_prcmu_abb_read(u8 slave, u8 reg, u8 *value, u8 size) 25 + { 26 + return -ENOSYS; 27 + } 28 + 29 + static inline int db5500_prcmu_abb_write(u8 slave, u8 reg, u8 *value, u8 size) 30 + { 31 + return -ENOSYS; 32 + } 33 + 34 + #endif /* CONFIG_UX500_SOC_DB5500 */ 35 + 36 + static inline int db5500_prcmu_config_abb_event_readout(u32 abb_events) 37 + { 38 + #ifdef CONFIG_MACH_U5500_SIMULATOR 39 + return 0; 40 + #else 41 + return -1; 42 + #endif 43 + } 44 + 45 + #endif /* __MACH_PRCMU_U5500_H */