162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * DB8500 PRCM Unit driver
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * Copyright (C) STMicroelectronics 2009
662306a36Sopenharmony_ci * Copyright (C) ST-Ericsson SA 2010
762306a36Sopenharmony_ci *
862306a36Sopenharmony_ci * Author: Kumar Sanghvi <kumar.sanghvi@stericsson.com>
962306a36Sopenharmony_ci * Author: Sundar Iyer <sundar.iyer@stericsson.com>
1062306a36Sopenharmony_ci * Author: Mattias Nilsson <mattias.i.nilsson@stericsson.com>
1162306a36Sopenharmony_ci *
1262306a36Sopenharmony_ci * U8500 PRCM Unit interface driver
1362306a36Sopenharmony_ci */
1462306a36Sopenharmony_ci#include <linux/init.h>
1562306a36Sopenharmony_ci#include <linux/export.h>
1662306a36Sopenharmony_ci#include <linux/kernel.h>
1762306a36Sopenharmony_ci#include <linux/delay.h>
1862306a36Sopenharmony_ci#include <linux/errno.h>
1962306a36Sopenharmony_ci#include <linux/err.h>
2062306a36Sopenharmony_ci#include <linux/spinlock.h>
2162306a36Sopenharmony_ci#include <linux/io.h>
2262306a36Sopenharmony_ci#include <linux/slab.h>
2362306a36Sopenharmony_ci#include <linux/mutex.h>
2462306a36Sopenharmony_ci#include <linux/completion.h>
2562306a36Sopenharmony_ci#include <linux/irq.h>
2662306a36Sopenharmony_ci#include <linux/jiffies.h>
2762306a36Sopenharmony_ci#include <linux/bitops.h>
2862306a36Sopenharmony_ci#include <linux/fs.h>
2962306a36Sopenharmony_ci#include <linux/of.h>
3062306a36Sopenharmony_ci#include <linux/of_address.h>
3162306a36Sopenharmony_ci#include <linux/of_irq.h>
3262306a36Sopenharmony_ci#include <linux/platform_device.h>
3362306a36Sopenharmony_ci#include <linux/uaccess.h>
3462306a36Sopenharmony_ci#include <linux/mfd/core.h>
3562306a36Sopenharmony_ci#include <linux/mfd/dbx500-prcmu.h>
3662306a36Sopenharmony_ci#include <linux/mfd/abx500/ab8500.h>
3762306a36Sopenharmony_ci#include <linux/regulator/db8500-prcmu.h>
3862306a36Sopenharmony_ci#include <linux/regulator/machine.h>
3962306a36Sopenharmony_ci#include "db8500-prcmu-regs.h"
4062306a36Sopenharmony_ci
4162306a36Sopenharmony_ci/* Index of different voltages to be used when accessing AVSData */
4262306a36Sopenharmony_ci#define PRCM_AVS_BASE		0x2FC
4362306a36Sopenharmony_ci#define PRCM_AVS_VBB_RET	(PRCM_AVS_BASE + 0x0)
4462306a36Sopenharmony_ci#define PRCM_AVS_VBB_MAX_OPP	(PRCM_AVS_BASE + 0x1)
4562306a36Sopenharmony_ci#define PRCM_AVS_VBB_100_OPP	(PRCM_AVS_BASE + 0x2)
4662306a36Sopenharmony_ci#define PRCM_AVS_VBB_50_OPP	(PRCM_AVS_BASE + 0x3)
4762306a36Sopenharmony_ci#define PRCM_AVS_VARM_MAX_OPP	(PRCM_AVS_BASE + 0x4)
4862306a36Sopenharmony_ci#define PRCM_AVS_VARM_100_OPP	(PRCM_AVS_BASE + 0x5)
4962306a36Sopenharmony_ci#define PRCM_AVS_VARM_50_OPP	(PRCM_AVS_BASE + 0x6)
5062306a36Sopenharmony_ci#define PRCM_AVS_VARM_RET	(PRCM_AVS_BASE + 0x7)
5162306a36Sopenharmony_ci#define PRCM_AVS_VAPE_100_OPP	(PRCM_AVS_BASE + 0x8)
5262306a36Sopenharmony_ci#define PRCM_AVS_VAPE_50_OPP	(PRCM_AVS_BASE + 0x9)
5362306a36Sopenharmony_ci#define PRCM_AVS_VMOD_100_OPP	(PRCM_AVS_BASE + 0xA)
5462306a36Sopenharmony_ci#define PRCM_AVS_VMOD_50_OPP	(PRCM_AVS_BASE + 0xB)
5562306a36Sopenharmony_ci#define PRCM_AVS_VSAFE		(PRCM_AVS_BASE + 0xC)
5662306a36Sopenharmony_ci
5762306a36Sopenharmony_ci#define PRCM_AVS_VOLTAGE		0
5862306a36Sopenharmony_ci#define PRCM_AVS_VOLTAGE_MASK		0x3f
5962306a36Sopenharmony_ci#define PRCM_AVS_ISSLOWSTARTUP		6
6062306a36Sopenharmony_ci#define PRCM_AVS_ISSLOWSTARTUP_MASK	(1 << PRCM_AVS_ISSLOWSTARTUP)
6162306a36Sopenharmony_ci#define PRCM_AVS_ISMODEENABLE		7
6262306a36Sopenharmony_ci#define PRCM_AVS_ISMODEENABLE_MASK	(1 << PRCM_AVS_ISMODEENABLE)
6362306a36Sopenharmony_ci
6462306a36Sopenharmony_ci#define PRCM_BOOT_STATUS	0xFFF
6562306a36Sopenharmony_ci#define PRCM_ROMCODE_A2P	0xFFE
6662306a36Sopenharmony_ci#define PRCM_ROMCODE_P2A	0xFFD
6762306a36Sopenharmony_ci#define PRCM_XP70_CUR_PWR_STATE 0xFFC      /* 4 BYTES */
6862306a36Sopenharmony_ci
6962306a36Sopenharmony_ci#define PRCM_SW_RST_REASON 0xFF8 /* 2 bytes */
7062306a36Sopenharmony_ci
7162306a36Sopenharmony_ci#define _PRCM_MBOX_HEADER		0xFE8 /* 16 bytes */
7262306a36Sopenharmony_ci#define PRCM_MBOX_HEADER_REQ_MB0	(_PRCM_MBOX_HEADER + 0x0)
7362306a36Sopenharmony_ci#define PRCM_MBOX_HEADER_REQ_MB1	(_PRCM_MBOX_HEADER + 0x1)
7462306a36Sopenharmony_ci#define PRCM_MBOX_HEADER_REQ_MB2	(_PRCM_MBOX_HEADER + 0x2)
7562306a36Sopenharmony_ci#define PRCM_MBOX_HEADER_REQ_MB3	(_PRCM_MBOX_HEADER + 0x3)
7662306a36Sopenharmony_ci#define PRCM_MBOX_HEADER_REQ_MB4	(_PRCM_MBOX_HEADER + 0x4)
7762306a36Sopenharmony_ci#define PRCM_MBOX_HEADER_REQ_MB5	(_PRCM_MBOX_HEADER + 0x5)
7862306a36Sopenharmony_ci#define PRCM_MBOX_HEADER_ACK_MB0	(_PRCM_MBOX_HEADER + 0x8)
7962306a36Sopenharmony_ci
8062306a36Sopenharmony_ci/* Req Mailboxes */
8162306a36Sopenharmony_ci#define PRCM_REQ_MB0 0xFDC /* 12 bytes  */
8262306a36Sopenharmony_ci#define PRCM_REQ_MB1 0xFD0 /* 12 bytes  */
8362306a36Sopenharmony_ci#define PRCM_REQ_MB2 0xFC0 /* 16 bytes  */
8462306a36Sopenharmony_ci#define PRCM_REQ_MB3 0xE4C /* 372 bytes  */
8562306a36Sopenharmony_ci#define PRCM_REQ_MB4 0xE48 /* 4 bytes  */
8662306a36Sopenharmony_ci#define PRCM_REQ_MB5 0xE44 /* 4 bytes  */
8762306a36Sopenharmony_ci
8862306a36Sopenharmony_ci/* Ack Mailboxes */
8962306a36Sopenharmony_ci#define PRCM_ACK_MB0 0xE08 /* 52 bytes  */
9062306a36Sopenharmony_ci#define PRCM_ACK_MB1 0xE04 /* 4 bytes */
9162306a36Sopenharmony_ci#define PRCM_ACK_MB2 0xE00 /* 4 bytes */
9262306a36Sopenharmony_ci#define PRCM_ACK_MB3 0xDFC /* 4 bytes */
9362306a36Sopenharmony_ci#define PRCM_ACK_MB4 0xDF8 /* 4 bytes */
9462306a36Sopenharmony_ci#define PRCM_ACK_MB5 0xDF4 /* 4 bytes */
9562306a36Sopenharmony_ci
9662306a36Sopenharmony_ci/* Mailbox 0 headers */
9762306a36Sopenharmony_ci#define MB0H_POWER_STATE_TRANS		0
9862306a36Sopenharmony_ci#define MB0H_CONFIG_WAKEUPS_EXE		1
9962306a36Sopenharmony_ci#define MB0H_READ_WAKEUP_ACK		3
10062306a36Sopenharmony_ci#define MB0H_CONFIG_WAKEUPS_SLEEP	4
10162306a36Sopenharmony_ci
10262306a36Sopenharmony_ci#define MB0H_WAKEUP_EXE 2
10362306a36Sopenharmony_ci#define MB0H_WAKEUP_SLEEP 5
10462306a36Sopenharmony_ci
10562306a36Sopenharmony_ci/* Mailbox 0 REQs */
10662306a36Sopenharmony_ci#define PRCM_REQ_MB0_AP_POWER_STATE	(PRCM_REQ_MB0 + 0x0)
10762306a36Sopenharmony_ci#define PRCM_REQ_MB0_AP_PLL_STATE	(PRCM_REQ_MB0 + 0x1)
10862306a36Sopenharmony_ci#define PRCM_REQ_MB0_ULP_CLOCK_STATE	(PRCM_REQ_MB0 + 0x2)
10962306a36Sopenharmony_ci#define PRCM_REQ_MB0_DO_NOT_WFI		(PRCM_REQ_MB0 + 0x3)
11062306a36Sopenharmony_ci#define PRCM_REQ_MB0_WAKEUP_8500	(PRCM_REQ_MB0 + 0x4)
11162306a36Sopenharmony_ci#define PRCM_REQ_MB0_WAKEUP_4500	(PRCM_REQ_MB0 + 0x8)
11262306a36Sopenharmony_ci
11362306a36Sopenharmony_ci/* Mailbox 0 ACKs */
11462306a36Sopenharmony_ci#define PRCM_ACK_MB0_AP_PWRSTTR_STATUS	(PRCM_ACK_MB0 + 0x0)
11562306a36Sopenharmony_ci#define PRCM_ACK_MB0_READ_POINTER	(PRCM_ACK_MB0 + 0x1)
11662306a36Sopenharmony_ci#define PRCM_ACK_MB0_WAKEUP_0_8500	(PRCM_ACK_MB0 + 0x4)
11762306a36Sopenharmony_ci#define PRCM_ACK_MB0_WAKEUP_0_4500	(PRCM_ACK_MB0 + 0x8)
11862306a36Sopenharmony_ci#define PRCM_ACK_MB0_WAKEUP_1_8500	(PRCM_ACK_MB0 + 0x1C)
11962306a36Sopenharmony_ci#define PRCM_ACK_MB0_WAKEUP_1_4500	(PRCM_ACK_MB0 + 0x20)
12062306a36Sopenharmony_ci#define PRCM_ACK_MB0_EVENT_4500_NUMBERS	20
12162306a36Sopenharmony_ci
12262306a36Sopenharmony_ci/* Mailbox 1 headers */
12362306a36Sopenharmony_ci#define MB1H_ARM_APE_OPP 0x0
12462306a36Sopenharmony_ci#define MB1H_RESET_MODEM 0x2
12562306a36Sopenharmony_ci#define MB1H_REQUEST_APE_OPP_100_VOLT 0x3
12662306a36Sopenharmony_ci#define MB1H_RELEASE_APE_OPP_100_VOLT 0x4
12762306a36Sopenharmony_ci#define MB1H_RELEASE_USB_WAKEUP 0x5
12862306a36Sopenharmony_ci#define MB1H_PLL_ON_OFF 0x6
12962306a36Sopenharmony_ci
13062306a36Sopenharmony_ci/* Mailbox 1 Requests */
13162306a36Sopenharmony_ci#define PRCM_REQ_MB1_ARM_OPP			(PRCM_REQ_MB1 + 0x0)
13262306a36Sopenharmony_ci#define PRCM_REQ_MB1_APE_OPP			(PRCM_REQ_MB1 + 0x1)
13362306a36Sopenharmony_ci#define PRCM_REQ_MB1_PLL_ON_OFF			(PRCM_REQ_MB1 + 0x4)
13462306a36Sopenharmony_ci#define PLL_SOC0_OFF	0x1
13562306a36Sopenharmony_ci#define PLL_SOC0_ON	0x2
13662306a36Sopenharmony_ci#define PLL_SOC1_OFF	0x4
13762306a36Sopenharmony_ci#define PLL_SOC1_ON	0x8
13862306a36Sopenharmony_ci
13962306a36Sopenharmony_ci/* Mailbox 1 ACKs */
14062306a36Sopenharmony_ci#define PRCM_ACK_MB1_CURRENT_ARM_OPP	(PRCM_ACK_MB1 + 0x0)
14162306a36Sopenharmony_ci#define PRCM_ACK_MB1_CURRENT_APE_OPP	(PRCM_ACK_MB1 + 0x1)
14262306a36Sopenharmony_ci#define PRCM_ACK_MB1_APE_VOLTAGE_STATUS	(PRCM_ACK_MB1 + 0x2)
14362306a36Sopenharmony_ci#define PRCM_ACK_MB1_DVFS_STATUS	(PRCM_ACK_MB1 + 0x3)
14462306a36Sopenharmony_ci
14562306a36Sopenharmony_ci/* Mailbox 2 headers */
14662306a36Sopenharmony_ci#define MB2H_DPS	0x0
14762306a36Sopenharmony_ci#define MB2H_AUTO_PWR	0x1
14862306a36Sopenharmony_ci
14962306a36Sopenharmony_ci/* Mailbox 2 REQs */
15062306a36Sopenharmony_ci#define PRCM_REQ_MB2_SVA_MMDSP		(PRCM_REQ_MB2 + 0x0)
15162306a36Sopenharmony_ci#define PRCM_REQ_MB2_SVA_PIPE		(PRCM_REQ_MB2 + 0x1)
15262306a36Sopenharmony_ci#define PRCM_REQ_MB2_SIA_MMDSP		(PRCM_REQ_MB2 + 0x2)
15362306a36Sopenharmony_ci#define PRCM_REQ_MB2_SIA_PIPE		(PRCM_REQ_MB2 + 0x3)
15462306a36Sopenharmony_ci#define PRCM_REQ_MB2_SGA		(PRCM_REQ_MB2 + 0x4)
15562306a36Sopenharmony_ci#define PRCM_REQ_MB2_B2R2_MCDE		(PRCM_REQ_MB2 + 0x5)
15662306a36Sopenharmony_ci#define PRCM_REQ_MB2_ESRAM12		(PRCM_REQ_MB2 + 0x6)
15762306a36Sopenharmony_ci#define PRCM_REQ_MB2_ESRAM34		(PRCM_REQ_MB2 + 0x7)
15862306a36Sopenharmony_ci#define PRCM_REQ_MB2_AUTO_PM_SLEEP	(PRCM_REQ_MB2 + 0x8)
15962306a36Sopenharmony_ci#define PRCM_REQ_MB2_AUTO_PM_IDLE	(PRCM_REQ_MB2 + 0xC)
16062306a36Sopenharmony_ci
16162306a36Sopenharmony_ci/* Mailbox 2 ACKs */
16262306a36Sopenharmony_ci#define PRCM_ACK_MB2_DPS_STATUS (PRCM_ACK_MB2 + 0x0)
16362306a36Sopenharmony_ci#define HWACC_PWR_ST_OK 0xFE
16462306a36Sopenharmony_ci
16562306a36Sopenharmony_ci/* Mailbox 3 headers */
16662306a36Sopenharmony_ci#define MB3H_ANC	0x0
16762306a36Sopenharmony_ci#define MB3H_SIDETONE	0x1
16862306a36Sopenharmony_ci#define MB3H_SYSCLK	0xE
16962306a36Sopenharmony_ci
17062306a36Sopenharmony_ci/* Mailbox 3 Requests */
17162306a36Sopenharmony_ci#define PRCM_REQ_MB3_ANC_FIR_COEFF	(PRCM_REQ_MB3 + 0x0)
17262306a36Sopenharmony_ci#define PRCM_REQ_MB3_ANC_IIR_COEFF	(PRCM_REQ_MB3 + 0x20)
17362306a36Sopenharmony_ci#define PRCM_REQ_MB3_ANC_SHIFTER	(PRCM_REQ_MB3 + 0x60)
17462306a36Sopenharmony_ci#define PRCM_REQ_MB3_ANC_WARP		(PRCM_REQ_MB3 + 0x64)
17562306a36Sopenharmony_ci#define PRCM_REQ_MB3_SIDETONE_FIR_GAIN	(PRCM_REQ_MB3 + 0x68)
17662306a36Sopenharmony_ci#define PRCM_REQ_MB3_SIDETONE_FIR_COEFF	(PRCM_REQ_MB3 + 0x6C)
17762306a36Sopenharmony_ci#define PRCM_REQ_MB3_SYSCLK_MGT		(PRCM_REQ_MB3 + 0x16C)
17862306a36Sopenharmony_ci
17962306a36Sopenharmony_ci/* Mailbox 4 headers */
18062306a36Sopenharmony_ci#define MB4H_DDR_INIT	0x0
18162306a36Sopenharmony_ci#define MB4H_MEM_ST	0x1
18262306a36Sopenharmony_ci#define MB4H_HOTDOG	0x12
18362306a36Sopenharmony_ci#define MB4H_HOTMON	0x13
18462306a36Sopenharmony_ci#define MB4H_HOT_PERIOD	0x14
18562306a36Sopenharmony_ci#define MB4H_A9WDOG_CONF 0x16
18662306a36Sopenharmony_ci#define MB4H_A9WDOG_EN   0x17
18762306a36Sopenharmony_ci#define MB4H_A9WDOG_DIS  0x18
18862306a36Sopenharmony_ci#define MB4H_A9WDOG_LOAD 0x19
18962306a36Sopenharmony_ci#define MB4H_A9WDOG_KICK 0x20
19062306a36Sopenharmony_ci
19162306a36Sopenharmony_ci/* Mailbox 4 Requests */
19262306a36Sopenharmony_ci#define PRCM_REQ_MB4_DDR_ST_AP_SLEEP_IDLE	(PRCM_REQ_MB4 + 0x0)
19362306a36Sopenharmony_ci#define PRCM_REQ_MB4_DDR_ST_AP_DEEP_IDLE	(PRCM_REQ_MB4 + 0x1)
19462306a36Sopenharmony_ci#define PRCM_REQ_MB4_ESRAM0_ST			(PRCM_REQ_MB4 + 0x3)
19562306a36Sopenharmony_ci#define PRCM_REQ_MB4_HOTDOG_THRESHOLD		(PRCM_REQ_MB4 + 0x0)
19662306a36Sopenharmony_ci#define PRCM_REQ_MB4_HOTMON_LOW			(PRCM_REQ_MB4 + 0x0)
19762306a36Sopenharmony_ci#define PRCM_REQ_MB4_HOTMON_HIGH		(PRCM_REQ_MB4 + 0x1)
19862306a36Sopenharmony_ci#define PRCM_REQ_MB4_HOTMON_CONFIG		(PRCM_REQ_MB4 + 0x2)
19962306a36Sopenharmony_ci#define PRCM_REQ_MB4_HOT_PERIOD			(PRCM_REQ_MB4 + 0x0)
20062306a36Sopenharmony_ci#define HOTMON_CONFIG_LOW			BIT(0)
20162306a36Sopenharmony_ci#define HOTMON_CONFIG_HIGH			BIT(1)
20262306a36Sopenharmony_ci#define PRCM_REQ_MB4_A9WDOG_0			(PRCM_REQ_MB4 + 0x0)
20362306a36Sopenharmony_ci#define PRCM_REQ_MB4_A9WDOG_1			(PRCM_REQ_MB4 + 0x1)
20462306a36Sopenharmony_ci#define PRCM_REQ_MB4_A9WDOG_2			(PRCM_REQ_MB4 + 0x2)
20562306a36Sopenharmony_ci#define PRCM_REQ_MB4_A9WDOG_3			(PRCM_REQ_MB4 + 0x3)
20662306a36Sopenharmony_ci#define A9WDOG_AUTO_OFF_EN			BIT(7)
20762306a36Sopenharmony_ci#define A9WDOG_AUTO_OFF_DIS			0
20862306a36Sopenharmony_ci#define A9WDOG_ID_MASK				0xf
20962306a36Sopenharmony_ci
21062306a36Sopenharmony_ci/* Mailbox 5 Requests */
21162306a36Sopenharmony_ci#define PRCM_REQ_MB5_I2C_SLAVE_OP	(PRCM_REQ_MB5 + 0x0)
21262306a36Sopenharmony_ci#define PRCM_REQ_MB5_I2C_HW_BITS	(PRCM_REQ_MB5 + 0x1)
21362306a36Sopenharmony_ci#define PRCM_REQ_MB5_I2C_REG		(PRCM_REQ_MB5 + 0x2)
21462306a36Sopenharmony_ci#define PRCM_REQ_MB5_I2C_VAL		(PRCM_REQ_MB5 + 0x3)
21562306a36Sopenharmony_ci#define PRCMU_I2C_WRITE(slave) (((slave) << 1) | BIT(6))
21662306a36Sopenharmony_ci#define PRCMU_I2C_READ(slave) (((slave) << 1) | BIT(0) | BIT(6))
21762306a36Sopenharmony_ci#define PRCMU_I2C_STOP_EN		BIT(3)
21862306a36Sopenharmony_ci
21962306a36Sopenharmony_ci/* Mailbox 5 ACKs */
22062306a36Sopenharmony_ci#define PRCM_ACK_MB5_I2C_STATUS	(PRCM_ACK_MB5 + 0x1)
22162306a36Sopenharmony_ci#define PRCM_ACK_MB5_I2C_VAL	(PRCM_ACK_MB5 + 0x3)
22262306a36Sopenharmony_ci#define I2C_WR_OK 0x1
22362306a36Sopenharmony_ci#define I2C_RD_OK 0x2
22462306a36Sopenharmony_ci
22562306a36Sopenharmony_ci#define NUM_MB 8
22662306a36Sopenharmony_ci#define MBOX_BIT BIT
22762306a36Sopenharmony_ci#define ALL_MBOX_BITS (MBOX_BIT(NUM_MB) - 1)
22862306a36Sopenharmony_ci
22962306a36Sopenharmony_ci/*
23062306a36Sopenharmony_ci * Wakeups/IRQs
23162306a36Sopenharmony_ci */
23262306a36Sopenharmony_ci
23362306a36Sopenharmony_ci#define WAKEUP_BIT_RTC BIT(0)
23462306a36Sopenharmony_ci#define WAKEUP_BIT_RTT0 BIT(1)
23562306a36Sopenharmony_ci#define WAKEUP_BIT_RTT1 BIT(2)
23662306a36Sopenharmony_ci#define WAKEUP_BIT_HSI0 BIT(3)
23762306a36Sopenharmony_ci#define WAKEUP_BIT_HSI1 BIT(4)
23862306a36Sopenharmony_ci#define WAKEUP_BIT_CA_WAKE BIT(5)
23962306a36Sopenharmony_ci#define WAKEUP_BIT_USB BIT(6)
24062306a36Sopenharmony_ci#define WAKEUP_BIT_ABB BIT(7)
24162306a36Sopenharmony_ci#define WAKEUP_BIT_ABB_FIFO BIT(8)
24262306a36Sopenharmony_ci#define WAKEUP_BIT_SYSCLK_OK BIT(9)
24362306a36Sopenharmony_ci#define WAKEUP_BIT_CA_SLEEP BIT(10)
24462306a36Sopenharmony_ci#define WAKEUP_BIT_AC_WAKE_ACK BIT(11)
24562306a36Sopenharmony_ci#define WAKEUP_BIT_SIDE_TONE_OK BIT(12)
24662306a36Sopenharmony_ci#define WAKEUP_BIT_ANC_OK BIT(13)
24762306a36Sopenharmony_ci#define WAKEUP_BIT_SW_ERROR BIT(14)
24862306a36Sopenharmony_ci#define WAKEUP_BIT_AC_SLEEP_ACK BIT(15)
24962306a36Sopenharmony_ci#define WAKEUP_BIT_ARM BIT(17)
25062306a36Sopenharmony_ci#define WAKEUP_BIT_HOTMON_LOW BIT(18)
25162306a36Sopenharmony_ci#define WAKEUP_BIT_HOTMON_HIGH BIT(19)
25262306a36Sopenharmony_ci#define WAKEUP_BIT_MODEM_SW_RESET_REQ BIT(20)
25362306a36Sopenharmony_ci#define WAKEUP_BIT_GPIO0 BIT(23)
25462306a36Sopenharmony_ci#define WAKEUP_BIT_GPIO1 BIT(24)
25562306a36Sopenharmony_ci#define WAKEUP_BIT_GPIO2 BIT(25)
25662306a36Sopenharmony_ci#define WAKEUP_BIT_GPIO3 BIT(26)
25762306a36Sopenharmony_ci#define WAKEUP_BIT_GPIO4 BIT(27)
25862306a36Sopenharmony_ci#define WAKEUP_BIT_GPIO5 BIT(28)
25962306a36Sopenharmony_ci#define WAKEUP_BIT_GPIO6 BIT(29)
26062306a36Sopenharmony_ci#define WAKEUP_BIT_GPIO7 BIT(30)
26162306a36Sopenharmony_ci#define WAKEUP_BIT_GPIO8 BIT(31)
26262306a36Sopenharmony_ci
26362306a36Sopenharmony_cistatic struct {
26462306a36Sopenharmony_ci	bool valid;
26562306a36Sopenharmony_ci	struct prcmu_fw_version version;
26662306a36Sopenharmony_ci} fw_info;
26762306a36Sopenharmony_ci
26862306a36Sopenharmony_cistatic struct irq_domain *db8500_irq_domain;
26962306a36Sopenharmony_ci
27062306a36Sopenharmony_ci/*
27162306a36Sopenharmony_ci * This vector maps irq numbers to the bits in the bit field used in
27262306a36Sopenharmony_ci * communication with the PRCMU firmware.
27362306a36Sopenharmony_ci *
27462306a36Sopenharmony_ci * The reason for having this is to keep the irq numbers contiguous even though
27562306a36Sopenharmony_ci * the bits in the bit field are not. (The bits also have a tendency to move
27662306a36Sopenharmony_ci * around, to further complicate matters.)
27762306a36Sopenharmony_ci */
27862306a36Sopenharmony_ci#define IRQ_INDEX(_name) ((IRQ_PRCMU_##_name))
27962306a36Sopenharmony_ci#define IRQ_ENTRY(_name)[IRQ_INDEX(_name)] = (WAKEUP_BIT_##_name)
28062306a36Sopenharmony_ci
28162306a36Sopenharmony_ci#define IRQ_PRCMU_RTC 0
28262306a36Sopenharmony_ci#define IRQ_PRCMU_RTT0 1
28362306a36Sopenharmony_ci#define IRQ_PRCMU_RTT1 2
28462306a36Sopenharmony_ci#define IRQ_PRCMU_HSI0 3
28562306a36Sopenharmony_ci#define IRQ_PRCMU_HSI1 4
28662306a36Sopenharmony_ci#define IRQ_PRCMU_CA_WAKE 5
28762306a36Sopenharmony_ci#define IRQ_PRCMU_USB 6
28862306a36Sopenharmony_ci#define IRQ_PRCMU_ABB 7
28962306a36Sopenharmony_ci#define IRQ_PRCMU_ABB_FIFO 8
29062306a36Sopenharmony_ci#define IRQ_PRCMU_ARM 9
29162306a36Sopenharmony_ci#define IRQ_PRCMU_MODEM_SW_RESET_REQ 10
29262306a36Sopenharmony_ci#define IRQ_PRCMU_GPIO0 11
29362306a36Sopenharmony_ci#define IRQ_PRCMU_GPIO1 12
29462306a36Sopenharmony_ci#define IRQ_PRCMU_GPIO2 13
29562306a36Sopenharmony_ci#define IRQ_PRCMU_GPIO3 14
29662306a36Sopenharmony_ci#define IRQ_PRCMU_GPIO4 15
29762306a36Sopenharmony_ci#define IRQ_PRCMU_GPIO5 16
29862306a36Sopenharmony_ci#define IRQ_PRCMU_GPIO6 17
29962306a36Sopenharmony_ci#define IRQ_PRCMU_GPIO7 18
30062306a36Sopenharmony_ci#define IRQ_PRCMU_GPIO8 19
30162306a36Sopenharmony_ci#define IRQ_PRCMU_CA_SLEEP 20
30262306a36Sopenharmony_ci#define IRQ_PRCMU_HOTMON_LOW 21
30362306a36Sopenharmony_ci#define IRQ_PRCMU_HOTMON_HIGH 22
30462306a36Sopenharmony_ci#define NUM_PRCMU_WAKEUPS 23
30562306a36Sopenharmony_ci
30662306a36Sopenharmony_cistatic u32 prcmu_irq_bit[NUM_PRCMU_WAKEUPS] = {
30762306a36Sopenharmony_ci	IRQ_ENTRY(RTC),
30862306a36Sopenharmony_ci	IRQ_ENTRY(RTT0),
30962306a36Sopenharmony_ci	IRQ_ENTRY(RTT1),
31062306a36Sopenharmony_ci	IRQ_ENTRY(HSI0),
31162306a36Sopenharmony_ci	IRQ_ENTRY(HSI1),
31262306a36Sopenharmony_ci	IRQ_ENTRY(CA_WAKE),
31362306a36Sopenharmony_ci	IRQ_ENTRY(USB),
31462306a36Sopenharmony_ci	IRQ_ENTRY(ABB),
31562306a36Sopenharmony_ci	IRQ_ENTRY(ABB_FIFO),
31662306a36Sopenharmony_ci	IRQ_ENTRY(CA_SLEEP),
31762306a36Sopenharmony_ci	IRQ_ENTRY(ARM),
31862306a36Sopenharmony_ci	IRQ_ENTRY(HOTMON_LOW),
31962306a36Sopenharmony_ci	IRQ_ENTRY(HOTMON_HIGH),
32062306a36Sopenharmony_ci	IRQ_ENTRY(MODEM_SW_RESET_REQ),
32162306a36Sopenharmony_ci	IRQ_ENTRY(GPIO0),
32262306a36Sopenharmony_ci	IRQ_ENTRY(GPIO1),
32362306a36Sopenharmony_ci	IRQ_ENTRY(GPIO2),
32462306a36Sopenharmony_ci	IRQ_ENTRY(GPIO3),
32562306a36Sopenharmony_ci	IRQ_ENTRY(GPIO4),
32662306a36Sopenharmony_ci	IRQ_ENTRY(GPIO5),
32762306a36Sopenharmony_ci	IRQ_ENTRY(GPIO6),
32862306a36Sopenharmony_ci	IRQ_ENTRY(GPIO7),
32962306a36Sopenharmony_ci	IRQ_ENTRY(GPIO8)
33062306a36Sopenharmony_ci};
33162306a36Sopenharmony_ci
33262306a36Sopenharmony_ci#define VALID_WAKEUPS (BIT(NUM_PRCMU_WAKEUP_INDICES) - 1)
33362306a36Sopenharmony_ci#define WAKEUP_ENTRY(_name)[PRCMU_WAKEUP_INDEX_##_name] = (WAKEUP_BIT_##_name)
33462306a36Sopenharmony_cistatic u32 prcmu_wakeup_bit[NUM_PRCMU_WAKEUP_INDICES] = {
33562306a36Sopenharmony_ci	WAKEUP_ENTRY(RTC),
33662306a36Sopenharmony_ci	WAKEUP_ENTRY(RTT0),
33762306a36Sopenharmony_ci	WAKEUP_ENTRY(RTT1),
33862306a36Sopenharmony_ci	WAKEUP_ENTRY(HSI0),
33962306a36Sopenharmony_ci	WAKEUP_ENTRY(HSI1),
34062306a36Sopenharmony_ci	WAKEUP_ENTRY(USB),
34162306a36Sopenharmony_ci	WAKEUP_ENTRY(ABB),
34262306a36Sopenharmony_ci	WAKEUP_ENTRY(ABB_FIFO),
34362306a36Sopenharmony_ci	WAKEUP_ENTRY(ARM)
34462306a36Sopenharmony_ci};
34562306a36Sopenharmony_ci
34662306a36Sopenharmony_ci/*
34762306a36Sopenharmony_ci * mb0_transfer - state needed for mailbox 0 communication.
34862306a36Sopenharmony_ci * @lock:		The transaction lock.
34962306a36Sopenharmony_ci * @dbb_events_lock:	A lock used to handle concurrent access to (parts of)
35062306a36Sopenharmony_ci *			the request data.
35162306a36Sopenharmony_ci * @mask_work:		Work structure used for (un)masking wakeup interrupts.
35262306a36Sopenharmony_ci * @req:		Request data that need to persist between requests.
35362306a36Sopenharmony_ci */
35462306a36Sopenharmony_cistatic struct {
35562306a36Sopenharmony_ci	spinlock_t lock;
35662306a36Sopenharmony_ci	spinlock_t dbb_irqs_lock;
35762306a36Sopenharmony_ci	struct work_struct mask_work;
35862306a36Sopenharmony_ci	struct mutex ac_wake_lock;
35962306a36Sopenharmony_ci	struct completion ac_wake_work;
36062306a36Sopenharmony_ci	struct {
36162306a36Sopenharmony_ci		u32 dbb_irqs;
36262306a36Sopenharmony_ci		u32 dbb_wakeups;
36362306a36Sopenharmony_ci		u32 abb_events;
36462306a36Sopenharmony_ci	} req;
36562306a36Sopenharmony_ci} mb0_transfer;
36662306a36Sopenharmony_ci
36762306a36Sopenharmony_ci/*
36862306a36Sopenharmony_ci * mb1_transfer - state needed for mailbox 1 communication.
36962306a36Sopenharmony_ci * @lock:	The transaction lock.
37062306a36Sopenharmony_ci * @work:	The transaction completion structure.
37162306a36Sopenharmony_ci * @ape_opp:	The current APE OPP.
37262306a36Sopenharmony_ci * @ack:	Reply ("acknowledge") data.
37362306a36Sopenharmony_ci */
37462306a36Sopenharmony_cistatic struct {
37562306a36Sopenharmony_ci	struct mutex lock;
37662306a36Sopenharmony_ci	struct completion work;
37762306a36Sopenharmony_ci	u8 ape_opp;
37862306a36Sopenharmony_ci	struct {
37962306a36Sopenharmony_ci		u8 header;
38062306a36Sopenharmony_ci		u8 arm_opp;
38162306a36Sopenharmony_ci		u8 ape_opp;
38262306a36Sopenharmony_ci		u8 ape_voltage_status;
38362306a36Sopenharmony_ci	} ack;
38462306a36Sopenharmony_ci} mb1_transfer;
38562306a36Sopenharmony_ci
38662306a36Sopenharmony_ci/*
38762306a36Sopenharmony_ci * mb2_transfer - state needed for mailbox 2 communication.
38862306a36Sopenharmony_ci * @lock:            The transaction lock.
38962306a36Sopenharmony_ci * @work:            The transaction completion structure.
39062306a36Sopenharmony_ci * @auto_pm_lock:    The autonomous power management configuration lock.
39162306a36Sopenharmony_ci * @auto_pm_enabled: A flag indicating whether autonomous PM is enabled.
39262306a36Sopenharmony_ci * @req:             Request data that need to persist between requests.
39362306a36Sopenharmony_ci * @ack:             Reply ("acknowledge") data.
39462306a36Sopenharmony_ci */
39562306a36Sopenharmony_cistatic struct {
39662306a36Sopenharmony_ci	struct mutex lock;
39762306a36Sopenharmony_ci	struct completion work;
39862306a36Sopenharmony_ci	spinlock_t auto_pm_lock;
39962306a36Sopenharmony_ci	bool auto_pm_enabled;
40062306a36Sopenharmony_ci	struct {
40162306a36Sopenharmony_ci		u8 status;
40262306a36Sopenharmony_ci	} ack;
40362306a36Sopenharmony_ci} mb2_transfer;
40462306a36Sopenharmony_ci
40562306a36Sopenharmony_ci/*
40662306a36Sopenharmony_ci * mb3_transfer - state needed for mailbox 3 communication.
40762306a36Sopenharmony_ci * @lock:		The request lock.
40862306a36Sopenharmony_ci * @sysclk_lock:	A lock used to handle concurrent sysclk requests.
40962306a36Sopenharmony_ci * @sysclk_work:	Work structure used for sysclk requests.
41062306a36Sopenharmony_ci */
41162306a36Sopenharmony_cistatic struct {
41262306a36Sopenharmony_ci	spinlock_t lock;
41362306a36Sopenharmony_ci	struct mutex sysclk_lock;
41462306a36Sopenharmony_ci	struct completion sysclk_work;
41562306a36Sopenharmony_ci} mb3_transfer;
41662306a36Sopenharmony_ci
41762306a36Sopenharmony_ci/*
41862306a36Sopenharmony_ci * mb4_transfer - state needed for mailbox 4 communication.
41962306a36Sopenharmony_ci * @lock:	The transaction lock.
42062306a36Sopenharmony_ci * @work:	The transaction completion structure.
42162306a36Sopenharmony_ci */
42262306a36Sopenharmony_cistatic struct {
42362306a36Sopenharmony_ci	struct mutex lock;
42462306a36Sopenharmony_ci	struct completion work;
42562306a36Sopenharmony_ci} mb4_transfer;
42662306a36Sopenharmony_ci
42762306a36Sopenharmony_ci/*
42862306a36Sopenharmony_ci * mb5_transfer - state needed for mailbox 5 communication.
42962306a36Sopenharmony_ci * @lock:	The transaction lock.
43062306a36Sopenharmony_ci * @work:	The transaction completion structure.
43162306a36Sopenharmony_ci * @ack:	Reply ("acknowledge") data.
43262306a36Sopenharmony_ci */
43362306a36Sopenharmony_cistatic struct {
43462306a36Sopenharmony_ci	struct mutex lock;
43562306a36Sopenharmony_ci	struct completion work;
43662306a36Sopenharmony_ci	struct {
43762306a36Sopenharmony_ci		u8 status;
43862306a36Sopenharmony_ci		u8 value;
43962306a36Sopenharmony_ci	} ack;
44062306a36Sopenharmony_ci} mb5_transfer;
44162306a36Sopenharmony_ci
44262306a36Sopenharmony_cistatic atomic_t ac_wake_req_state = ATOMIC_INIT(0);
44362306a36Sopenharmony_ci
44462306a36Sopenharmony_ci/* Spinlocks */
44562306a36Sopenharmony_cistatic DEFINE_SPINLOCK(prcmu_lock);
44662306a36Sopenharmony_cistatic DEFINE_SPINLOCK(clkout_lock);
44762306a36Sopenharmony_ci
44862306a36Sopenharmony_ci/* Global var to runtime determine TCDM base for v2 or v1 */
44962306a36Sopenharmony_cistatic __iomem void *tcdm_base;
45062306a36Sopenharmony_cistatic __iomem void *prcmu_base;
45162306a36Sopenharmony_ci
45262306a36Sopenharmony_cistruct clk_mgt {
45362306a36Sopenharmony_ci	u32 offset;
45462306a36Sopenharmony_ci	u32 pllsw;
45562306a36Sopenharmony_ci	int branch;
45662306a36Sopenharmony_ci	bool clk38div;
45762306a36Sopenharmony_ci};
45862306a36Sopenharmony_ci
45962306a36Sopenharmony_cienum {
46062306a36Sopenharmony_ci	PLL_RAW,
46162306a36Sopenharmony_ci	PLL_FIX,
46262306a36Sopenharmony_ci	PLL_DIV
46362306a36Sopenharmony_ci};
46462306a36Sopenharmony_ci
46562306a36Sopenharmony_cistatic DEFINE_SPINLOCK(clk_mgt_lock);
46662306a36Sopenharmony_ci
46762306a36Sopenharmony_ci#define CLK_MGT_ENTRY(_name, _branch, _clk38div)[PRCMU_##_name] = \
46862306a36Sopenharmony_ci	{ (PRCM_##_name##_MGT), 0 , _branch, _clk38div}
46962306a36Sopenharmony_cistatic struct clk_mgt clk_mgt[PRCMU_NUM_REG_CLOCKS] = {
47062306a36Sopenharmony_ci	CLK_MGT_ENTRY(SGACLK, PLL_DIV, false),
47162306a36Sopenharmony_ci	CLK_MGT_ENTRY(UARTCLK, PLL_FIX, true),
47262306a36Sopenharmony_ci	CLK_MGT_ENTRY(MSP02CLK, PLL_FIX, true),
47362306a36Sopenharmony_ci	CLK_MGT_ENTRY(MSP1CLK, PLL_FIX, true),
47462306a36Sopenharmony_ci	CLK_MGT_ENTRY(I2CCLK, PLL_FIX, true),
47562306a36Sopenharmony_ci	CLK_MGT_ENTRY(SDMMCCLK, PLL_DIV, true),
47662306a36Sopenharmony_ci	CLK_MGT_ENTRY(SLIMCLK, PLL_FIX, true),
47762306a36Sopenharmony_ci	CLK_MGT_ENTRY(PER1CLK, PLL_DIV, true),
47862306a36Sopenharmony_ci	CLK_MGT_ENTRY(PER2CLK, PLL_DIV, true),
47962306a36Sopenharmony_ci	CLK_MGT_ENTRY(PER3CLK, PLL_DIV, true),
48062306a36Sopenharmony_ci	CLK_MGT_ENTRY(PER5CLK, PLL_DIV, true),
48162306a36Sopenharmony_ci	CLK_MGT_ENTRY(PER6CLK, PLL_DIV, true),
48262306a36Sopenharmony_ci	CLK_MGT_ENTRY(PER7CLK, PLL_DIV, true),
48362306a36Sopenharmony_ci	CLK_MGT_ENTRY(LCDCLK, PLL_FIX, true),
48462306a36Sopenharmony_ci	CLK_MGT_ENTRY(BMLCLK, PLL_DIV, true),
48562306a36Sopenharmony_ci	CLK_MGT_ENTRY(HSITXCLK, PLL_DIV, true),
48662306a36Sopenharmony_ci	CLK_MGT_ENTRY(HSIRXCLK, PLL_DIV, true),
48762306a36Sopenharmony_ci	CLK_MGT_ENTRY(HDMICLK, PLL_FIX, false),
48862306a36Sopenharmony_ci	CLK_MGT_ENTRY(APEATCLK, PLL_DIV, true),
48962306a36Sopenharmony_ci	CLK_MGT_ENTRY(APETRACECLK, PLL_DIV, true),
49062306a36Sopenharmony_ci	CLK_MGT_ENTRY(MCDECLK, PLL_DIV, true),
49162306a36Sopenharmony_ci	CLK_MGT_ENTRY(IPI2CCLK, PLL_FIX, true),
49262306a36Sopenharmony_ci	CLK_MGT_ENTRY(DSIALTCLK, PLL_FIX, false),
49362306a36Sopenharmony_ci	CLK_MGT_ENTRY(DMACLK, PLL_DIV, true),
49462306a36Sopenharmony_ci	CLK_MGT_ENTRY(B2R2CLK, PLL_DIV, true),
49562306a36Sopenharmony_ci	CLK_MGT_ENTRY(TVCLK, PLL_FIX, true),
49662306a36Sopenharmony_ci	CLK_MGT_ENTRY(SSPCLK, PLL_FIX, true),
49762306a36Sopenharmony_ci	CLK_MGT_ENTRY(RNGCLK, PLL_FIX, true),
49862306a36Sopenharmony_ci	CLK_MGT_ENTRY(UICCCLK, PLL_FIX, false),
49962306a36Sopenharmony_ci};
50062306a36Sopenharmony_ci
50162306a36Sopenharmony_cistruct dsiclk {
50262306a36Sopenharmony_ci	u32 divsel_mask;
50362306a36Sopenharmony_ci	u32 divsel_shift;
50462306a36Sopenharmony_ci	u32 divsel;
50562306a36Sopenharmony_ci};
50662306a36Sopenharmony_ci
50762306a36Sopenharmony_cistatic struct dsiclk dsiclk[2] = {
50862306a36Sopenharmony_ci	{
50962306a36Sopenharmony_ci		.divsel_mask = PRCM_DSI_PLLOUT_SEL_DSI0_PLLOUT_DIVSEL_MASK,
51062306a36Sopenharmony_ci		.divsel_shift = PRCM_DSI_PLLOUT_SEL_DSI0_PLLOUT_DIVSEL_SHIFT,
51162306a36Sopenharmony_ci		.divsel = PRCM_DSI_PLLOUT_SEL_PHI,
51262306a36Sopenharmony_ci	},
51362306a36Sopenharmony_ci	{
51462306a36Sopenharmony_ci		.divsel_mask = PRCM_DSI_PLLOUT_SEL_DSI1_PLLOUT_DIVSEL_MASK,
51562306a36Sopenharmony_ci		.divsel_shift = PRCM_DSI_PLLOUT_SEL_DSI1_PLLOUT_DIVSEL_SHIFT,
51662306a36Sopenharmony_ci		.divsel = PRCM_DSI_PLLOUT_SEL_PHI,
51762306a36Sopenharmony_ci	}
51862306a36Sopenharmony_ci};
51962306a36Sopenharmony_ci
52062306a36Sopenharmony_cistruct dsiescclk {
52162306a36Sopenharmony_ci	u32 en;
52262306a36Sopenharmony_ci	u32 div_mask;
52362306a36Sopenharmony_ci	u32 div_shift;
52462306a36Sopenharmony_ci};
52562306a36Sopenharmony_ci
52662306a36Sopenharmony_cistatic struct dsiescclk dsiescclk[3] = {
52762306a36Sopenharmony_ci	{
52862306a36Sopenharmony_ci		.en = PRCM_DSITVCLK_DIV_DSI0_ESC_CLK_EN,
52962306a36Sopenharmony_ci		.div_mask = PRCM_DSITVCLK_DIV_DSI0_ESC_CLK_DIV_MASK,
53062306a36Sopenharmony_ci		.div_shift = PRCM_DSITVCLK_DIV_DSI0_ESC_CLK_DIV_SHIFT,
53162306a36Sopenharmony_ci	},
53262306a36Sopenharmony_ci	{
53362306a36Sopenharmony_ci		.en = PRCM_DSITVCLK_DIV_DSI1_ESC_CLK_EN,
53462306a36Sopenharmony_ci		.div_mask = PRCM_DSITVCLK_DIV_DSI1_ESC_CLK_DIV_MASK,
53562306a36Sopenharmony_ci		.div_shift = PRCM_DSITVCLK_DIV_DSI1_ESC_CLK_DIV_SHIFT,
53662306a36Sopenharmony_ci	},
53762306a36Sopenharmony_ci	{
53862306a36Sopenharmony_ci		.en = PRCM_DSITVCLK_DIV_DSI2_ESC_CLK_EN,
53962306a36Sopenharmony_ci		.div_mask = PRCM_DSITVCLK_DIV_DSI2_ESC_CLK_DIV_MASK,
54062306a36Sopenharmony_ci		.div_shift = PRCM_DSITVCLK_DIV_DSI2_ESC_CLK_DIV_SHIFT,
54162306a36Sopenharmony_ci	}
54262306a36Sopenharmony_ci};
54362306a36Sopenharmony_ci
54462306a36Sopenharmony_ciu32 db8500_prcmu_read(unsigned int reg)
54562306a36Sopenharmony_ci{
54662306a36Sopenharmony_ci	return readl(prcmu_base + reg);
54762306a36Sopenharmony_ci}
54862306a36Sopenharmony_ci
54962306a36Sopenharmony_civoid db8500_prcmu_write(unsigned int reg, u32 value)
55062306a36Sopenharmony_ci{
55162306a36Sopenharmony_ci	unsigned long flags;
55262306a36Sopenharmony_ci
55362306a36Sopenharmony_ci	spin_lock_irqsave(&prcmu_lock, flags);
55462306a36Sopenharmony_ci	writel(value, (prcmu_base + reg));
55562306a36Sopenharmony_ci	spin_unlock_irqrestore(&prcmu_lock, flags);
55662306a36Sopenharmony_ci}
55762306a36Sopenharmony_ci
55862306a36Sopenharmony_civoid db8500_prcmu_write_masked(unsigned int reg, u32 mask, u32 value)
55962306a36Sopenharmony_ci{
56062306a36Sopenharmony_ci	u32 val;
56162306a36Sopenharmony_ci	unsigned long flags;
56262306a36Sopenharmony_ci
56362306a36Sopenharmony_ci	spin_lock_irqsave(&prcmu_lock, flags);
56462306a36Sopenharmony_ci	val = readl(prcmu_base + reg);
56562306a36Sopenharmony_ci	val = ((val & ~mask) | (value & mask));
56662306a36Sopenharmony_ci	writel(val, (prcmu_base + reg));
56762306a36Sopenharmony_ci	spin_unlock_irqrestore(&prcmu_lock, flags);
56862306a36Sopenharmony_ci}
56962306a36Sopenharmony_ci
57062306a36Sopenharmony_cistruct prcmu_fw_version *prcmu_get_fw_version(void)
57162306a36Sopenharmony_ci{
57262306a36Sopenharmony_ci	return fw_info.valid ? &fw_info.version : NULL;
57362306a36Sopenharmony_ci}
57462306a36Sopenharmony_ci
57562306a36Sopenharmony_cistatic bool prcmu_is_ulppll_disabled(void)
57662306a36Sopenharmony_ci{
57762306a36Sopenharmony_ci	struct prcmu_fw_version *ver;
57862306a36Sopenharmony_ci
57962306a36Sopenharmony_ci	ver = prcmu_get_fw_version();
58062306a36Sopenharmony_ci	return ver && ver->project == PRCMU_FW_PROJECT_U8420_SYSCLK;
58162306a36Sopenharmony_ci}
58262306a36Sopenharmony_ci
58362306a36Sopenharmony_cibool prcmu_has_arm_maxopp(void)
58462306a36Sopenharmony_ci{
58562306a36Sopenharmony_ci	return (readb(tcdm_base + PRCM_AVS_VARM_MAX_OPP) &
58662306a36Sopenharmony_ci		PRCM_AVS_ISMODEENABLE_MASK) == PRCM_AVS_ISMODEENABLE_MASK;
58762306a36Sopenharmony_ci}
58862306a36Sopenharmony_ci
58962306a36Sopenharmony_ci/**
59062306a36Sopenharmony_ci * prcmu_set_rc_a2p - This function is used to run few power state sequences
59162306a36Sopenharmony_ci * @val: Value to be set, i.e. transition requested
59262306a36Sopenharmony_ci * Returns: 0 on success, -EINVAL on invalid argument
59362306a36Sopenharmony_ci *
59462306a36Sopenharmony_ci * This function is used to run the following power state sequences -
59562306a36Sopenharmony_ci * any state to ApReset,  ApDeepSleep to ApExecute, ApExecute to ApDeepSleep
59662306a36Sopenharmony_ci */
59762306a36Sopenharmony_ciint prcmu_set_rc_a2p(enum romcode_write val)
59862306a36Sopenharmony_ci{
59962306a36Sopenharmony_ci	if (val < RDY_2_DS || val > RDY_2_XP70_RST)
60062306a36Sopenharmony_ci		return -EINVAL;
60162306a36Sopenharmony_ci	writeb(val, (tcdm_base + PRCM_ROMCODE_A2P));
60262306a36Sopenharmony_ci	return 0;
60362306a36Sopenharmony_ci}
60462306a36Sopenharmony_ci
60562306a36Sopenharmony_ci/**
60662306a36Sopenharmony_ci * prcmu_get_rc_p2a - This function is used to get power state sequences
60762306a36Sopenharmony_ci * Returns: the power transition that has last happened
60862306a36Sopenharmony_ci *
60962306a36Sopenharmony_ci * This function can return the following transitions-
61062306a36Sopenharmony_ci * any state to ApReset,  ApDeepSleep to ApExecute, ApExecute to ApDeepSleep
61162306a36Sopenharmony_ci */
61262306a36Sopenharmony_cienum romcode_read prcmu_get_rc_p2a(void)
61362306a36Sopenharmony_ci{
61462306a36Sopenharmony_ci	return readb(tcdm_base + PRCM_ROMCODE_P2A);
61562306a36Sopenharmony_ci}
61662306a36Sopenharmony_ci
61762306a36Sopenharmony_ci/**
61862306a36Sopenharmony_ci * prcmu_get_xp70_current_state - Return the current XP70 power mode
61962306a36Sopenharmony_ci * Returns: Returns the current AP(ARM) power mode: init,
62062306a36Sopenharmony_ci * apBoot, apExecute, apDeepSleep, apSleep, apIdle, apReset
62162306a36Sopenharmony_ci */
62262306a36Sopenharmony_cienum ap_pwrst prcmu_get_xp70_current_state(void)
62362306a36Sopenharmony_ci{
62462306a36Sopenharmony_ci	return readb(tcdm_base + PRCM_XP70_CUR_PWR_STATE);
62562306a36Sopenharmony_ci}
62662306a36Sopenharmony_ci
62762306a36Sopenharmony_ci/**
62862306a36Sopenharmony_ci * prcmu_config_clkout - Configure one of the programmable clock outputs.
62962306a36Sopenharmony_ci * @clkout:	The CLKOUT number (0 or 1).
63062306a36Sopenharmony_ci * @source:	The clock to be used (one of the PRCMU_CLKSRC_*).
63162306a36Sopenharmony_ci * @div:	The divider to be applied.
63262306a36Sopenharmony_ci *
63362306a36Sopenharmony_ci * Configures one of the programmable clock outputs (CLKOUTs).
63462306a36Sopenharmony_ci * @div should be in the range [1,63] to request a configuration, or 0 to
63562306a36Sopenharmony_ci * inform that the configuration is no longer requested.
63662306a36Sopenharmony_ci */
63762306a36Sopenharmony_ciint prcmu_config_clkout(u8 clkout, u8 source, u8 div)
63862306a36Sopenharmony_ci{
63962306a36Sopenharmony_ci	static int requests[2];
64062306a36Sopenharmony_ci	int r = 0;
64162306a36Sopenharmony_ci	unsigned long flags;
64262306a36Sopenharmony_ci	u32 val;
64362306a36Sopenharmony_ci	u32 bits;
64462306a36Sopenharmony_ci	u32 mask;
64562306a36Sopenharmony_ci	u32 div_mask;
64662306a36Sopenharmony_ci
64762306a36Sopenharmony_ci	BUG_ON(clkout > 1);
64862306a36Sopenharmony_ci	BUG_ON(div > 63);
64962306a36Sopenharmony_ci	BUG_ON((clkout == 0) && (source > PRCMU_CLKSRC_CLK009));
65062306a36Sopenharmony_ci
65162306a36Sopenharmony_ci	if (!div && !requests[clkout])
65262306a36Sopenharmony_ci		return -EINVAL;
65362306a36Sopenharmony_ci
65462306a36Sopenharmony_ci	if (clkout == 0) {
65562306a36Sopenharmony_ci		div_mask = PRCM_CLKOCR_CLKODIV0_MASK;
65662306a36Sopenharmony_ci		mask = (PRCM_CLKOCR_CLKODIV0_MASK | PRCM_CLKOCR_CLKOSEL0_MASK);
65762306a36Sopenharmony_ci		bits = ((source << PRCM_CLKOCR_CLKOSEL0_SHIFT) |
65862306a36Sopenharmony_ci			(div << PRCM_CLKOCR_CLKODIV0_SHIFT));
65962306a36Sopenharmony_ci	} else {
66062306a36Sopenharmony_ci		div_mask = PRCM_CLKOCR_CLKODIV1_MASK;
66162306a36Sopenharmony_ci		mask = (PRCM_CLKOCR_CLKODIV1_MASK | PRCM_CLKOCR_CLKOSEL1_MASK |
66262306a36Sopenharmony_ci			PRCM_CLKOCR_CLK1TYPE);
66362306a36Sopenharmony_ci		bits = ((source << PRCM_CLKOCR_CLKOSEL1_SHIFT) |
66462306a36Sopenharmony_ci			(div << PRCM_CLKOCR_CLKODIV1_SHIFT));
66562306a36Sopenharmony_ci	}
66662306a36Sopenharmony_ci	bits &= mask;
66762306a36Sopenharmony_ci
66862306a36Sopenharmony_ci	spin_lock_irqsave(&clkout_lock, flags);
66962306a36Sopenharmony_ci
67062306a36Sopenharmony_ci	val = readl(PRCM_CLKOCR);
67162306a36Sopenharmony_ci	if (val & div_mask) {
67262306a36Sopenharmony_ci		if (div) {
67362306a36Sopenharmony_ci			if ((val & mask) != bits) {
67462306a36Sopenharmony_ci				r = -EBUSY;
67562306a36Sopenharmony_ci				goto unlock_and_return;
67662306a36Sopenharmony_ci			}
67762306a36Sopenharmony_ci		} else {
67862306a36Sopenharmony_ci			if ((val & mask & ~div_mask) != bits) {
67962306a36Sopenharmony_ci				r = -EINVAL;
68062306a36Sopenharmony_ci				goto unlock_and_return;
68162306a36Sopenharmony_ci			}
68262306a36Sopenharmony_ci		}
68362306a36Sopenharmony_ci	}
68462306a36Sopenharmony_ci	writel((bits | (val & ~mask)), PRCM_CLKOCR);
68562306a36Sopenharmony_ci	requests[clkout] += (div ? 1 : -1);
68662306a36Sopenharmony_ci
68762306a36Sopenharmony_ciunlock_and_return:
68862306a36Sopenharmony_ci	spin_unlock_irqrestore(&clkout_lock, flags);
68962306a36Sopenharmony_ci
69062306a36Sopenharmony_ci	return r;
69162306a36Sopenharmony_ci}
69262306a36Sopenharmony_ci
69362306a36Sopenharmony_ciint db8500_prcmu_set_power_state(u8 state, bool keep_ulp_clk, bool keep_ap_pll)
69462306a36Sopenharmony_ci{
69562306a36Sopenharmony_ci	unsigned long flags;
69662306a36Sopenharmony_ci
69762306a36Sopenharmony_ci	BUG_ON((state < PRCMU_AP_SLEEP) || (PRCMU_AP_DEEP_IDLE < state));
69862306a36Sopenharmony_ci
69962306a36Sopenharmony_ci	spin_lock_irqsave(&mb0_transfer.lock, flags);
70062306a36Sopenharmony_ci
70162306a36Sopenharmony_ci	while (readl(PRCM_MBOX_CPU_VAL) & MBOX_BIT(0))
70262306a36Sopenharmony_ci		cpu_relax();
70362306a36Sopenharmony_ci
70462306a36Sopenharmony_ci	writeb(MB0H_POWER_STATE_TRANS, (tcdm_base + PRCM_MBOX_HEADER_REQ_MB0));
70562306a36Sopenharmony_ci	writeb(state, (tcdm_base + PRCM_REQ_MB0_AP_POWER_STATE));
70662306a36Sopenharmony_ci	writeb((keep_ap_pll ? 1 : 0), (tcdm_base + PRCM_REQ_MB0_AP_PLL_STATE));
70762306a36Sopenharmony_ci	writeb((keep_ulp_clk ? 1 : 0),
70862306a36Sopenharmony_ci		(tcdm_base + PRCM_REQ_MB0_ULP_CLOCK_STATE));
70962306a36Sopenharmony_ci	writeb(0, (tcdm_base + PRCM_REQ_MB0_DO_NOT_WFI));
71062306a36Sopenharmony_ci	writel(MBOX_BIT(0), PRCM_MBOX_CPU_SET);
71162306a36Sopenharmony_ci
71262306a36Sopenharmony_ci	spin_unlock_irqrestore(&mb0_transfer.lock, flags);
71362306a36Sopenharmony_ci
71462306a36Sopenharmony_ci	return 0;
71562306a36Sopenharmony_ci}
71662306a36Sopenharmony_ci
71762306a36Sopenharmony_ciu8 db8500_prcmu_get_power_state_result(void)
71862306a36Sopenharmony_ci{
71962306a36Sopenharmony_ci	return readb(tcdm_base + PRCM_ACK_MB0_AP_PWRSTTR_STATUS);
72062306a36Sopenharmony_ci}
72162306a36Sopenharmony_ci
72262306a36Sopenharmony_ci/* This function should only be called while mb0_transfer.lock is held. */
72362306a36Sopenharmony_cistatic void config_wakeups(void)
72462306a36Sopenharmony_ci{
72562306a36Sopenharmony_ci	const u8 header[2] = {
72662306a36Sopenharmony_ci		MB0H_CONFIG_WAKEUPS_EXE,
72762306a36Sopenharmony_ci		MB0H_CONFIG_WAKEUPS_SLEEP
72862306a36Sopenharmony_ci	};
72962306a36Sopenharmony_ci	static u32 last_dbb_events;
73062306a36Sopenharmony_ci	static u32 last_abb_events;
73162306a36Sopenharmony_ci	u32 dbb_events;
73262306a36Sopenharmony_ci	u32 abb_events;
73362306a36Sopenharmony_ci	unsigned int i;
73462306a36Sopenharmony_ci
73562306a36Sopenharmony_ci	dbb_events = mb0_transfer.req.dbb_irqs | mb0_transfer.req.dbb_wakeups;
73662306a36Sopenharmony_ci	dbb_events |= (WAKEUP_BIT_AC_WAKE_ACK | WAKEUP_BIT_AC_SLEEP_ACK);
73762306a36Sopenharmony_ci
73862306a36Sopenharmony_ci	abb_events = mb0_transfer.req.abb_events;
73962306a36Sopenharmony_ci
74062306a36Sopenharmony_ci	if ((dbb_events == last_dbb_events) && (abb_events == last_abb_events))
74162306a36Sopenharmony_ci		return;
74262306a36Sopenharmony_ci
74362306a36Sopenharmony_ci	for (i = 0; i < 2; i++) {
74462306a36Sopenharmony_ci		while (readl(PRCM_MBOX_CPU_VAL) & MBOX_BIT(0))
74562306a36Sopenharmony_ci			cpu_relax();
74662306a36Sopenharmony_ci		writel(dbb_events, (tcdm_base + PRCM_REQ_MB0_WAKEUP_8500));
74762306a36Sopenharmony_ci		writel(abb_events, (tcdm_base + PRCM_REQ_MB0_WAKEUP_4500));
74862306a36Sopenharmony_ci		writeb(header[i], (tcdm_base + PRCM_MBOX_HEADER_REQ_MB0));
74962306a36Sopenharmony_ci		writel(MBOX_BIT(0), PRCM_MBOX_CPU_SET);
75062306a36Sopenharmony_ci	}
75162306a36Sopenharmony_ci	last_dbb_events = dbb_events;
75262306a36Sopenharmony_ci	last_abb_events = abb_events;
75362306a36Sopenharmony_ci}
75462306a36Sopenharmony_ci
75562306a36Sopenharmony_civoid db8500_prcmu_enable_wakeups(u32 wakeups)
75662306a36Sopenharmony_ci{
75762306a36Sopenharmony_ci	unsigned long flags;
75862306a36Sopenharmony_ci	u32 bits;
75962306a36Sopenharmony_ci	int i;
76062306a36Sopenharmony_ci
76162306a36Sopenharmony_ci	BUG_ON(wakeups != (wakeups & VALID_WAKEUPS));
76262306a36Sopenharmony_ci
76362306a36Sopenharmony_ci	for (i = 0, bits = 0; i < NUM_PRCMU_WAKEUP_INDICES; i++) {
76462306a36Sopenharmony_ci		if (wakeups & BIT(i))
76562306a36Sopenharmony_ci			bits |= prcmu_wakeup_bit[i];
76662306a36Sopenharmony_ci	}
76762306a36Sopenharmony_ci
76862306a36Sopenharmony_ci	spin_lock_irqsave(&mb0_transfer.lock, flags);
76962306a36Sopenharmony_ci
77062306a36Sopenharmony_ci	mb0_transfer.req.dbb_wakeups = bits;
77162306a36Sopenharmony_ci	config_wakeups();
77262306a36Sopenharmony_ci
77362306a36Sopenharmony_ci	spin_unlock_irqrestore(&mb0_transfer.lock, flags);
77462306a36Sopenharmony_ci}
77562306a36Sopenharmony_ci
77662306a36Sopenharmony_civoid db8500_prcmu_config_abb_event_readout(u32 abb_events)
77762306a36Sopenharmony_ci{
77862306a36Sopenharmony_ci	unsigned long flags;
77962306a36Sopenharmony_ci
78062306a36Sopenharmony_ci	spin_lock_irqsave(&mb0_transfer.lock, flags);
78162306a36Sopenharmony_ci
78262306a36Sopenharmony_ci	mb0_transfer.req.abb_events = abb_events;
78362306a36Sopenharmony_ci	config_wakeups();
78462306a36Sopenharmony_ci
78562306a36Sopenharmony_ci	spin_unlock_irqrestore(&mb0_transfer.lock, flags);
78662306a36Sopenharmony_ci}
78762306a36Sopenharmony_ci
78862306a36Sopenharmony_civoid db8500_prcmu_get_abb_event_buffer(void __iomem **buf)
78962306a36Sopenharmony_ci{
79062306a36Sopenharmony_ci	if (readb(tcdm_base + PRCM_ACK_MB0_READ_POINTER) & 1)
79162306a36Sopenharmony_ci		*buf = (tcdm_base + PRCM_ACK_MB0_WAKEUP_1_4500);
79262306a36Sopenharmony_ci	else
79362306a36Sopenharmony_ci		*buf = (tcdm_base + PRCM_ACK_MB0_WAKEUP_0_4500);
79462306a36Sopenharmony_ci}
79562306a36Sopenharmony_ci
79662306a36Sopenharmony_ci/**
79762306a36Sopenharmony_ci * db8500_prcmu_set_arm_opp - set the appropriate ARM OPP
79862306a36Sopenharmony_ci * @opp: The new ARM operating point to which transition is to be made
79962306a36Sopenharmony_ci * Returns: 0 on success, non-zero on failure
80062306a36Sopenharmony_ci *
80162306a36Sopenharmony_ci * This function sets the operating point of the ARM.
80262306a36Sopenharmony_ci */
80362306a36Sopenharmony_ciint db8500_prcmu_set_arm_opp(u8 opp)
80462306a36Sopenharmony_ci{
80562306a36Sopenharmony_ci	int r;
80662306a36Sopenharmony_ci
80762306a36Sopenharmony_ci	if (opp < ARM_NO_CHANGE || opp > ARM_EXTCLK)
80862306a36Sopenharmony_ci		return -EINVAL;
80962306a36Sopenharmony_ci
81062306a36Sopenharmony_ci	r = 0;
81162306a36Sopenharmony_ci
81262306a36Sopenharmony_ci	mutex_lock(&mb1_transfer.lock);
81362306a36Sopenharmony_ci
81462306a36Sopenharmony_ci	while (readl(PRCM_MBOX_CPU_VAL) & MBOX_BIT(1))
81562306a36Sopenharmony_ci		cpu_relax();
81662306a36Sopenharmony_ci
81762306a36Sopenharmony_ci	writeb(MB1H_ARM_APE_OPP, (tcdm_base + PRCM_MBOX_HEADER_REQ_MB1));
81862306a36Sopenharmony_ci	writeb(opp, (tcdm_base + PRCM_REQ_MB1_ARM_OPP));
81962306a36Sopenharmony_ci	writeb(APE_NO_CHANGE, (tcdm_base + PRCM_REQ_MB1_APE_OPP));
82062306a36Sopenharmony_ci
82162306a36Sopenharmony_ci	writel(MBOX_BIT(1), PRCM_MBOX_CPU_SET);
82262306a36Sopenharmony_ci	wait_for_completion(&mb1_transfer.work);
82362306a36Sopenharmony_ci
82462306a36Sopenharmony_ci	if ((mb1_transfer.ack.header != MB1H_ARM_APE_OPP) ||
82562306a36Sopenharmony_ci		(mb1_transfer.ack.arm_opp != opp))
82662306a36Sopenharmony_ci		r = -EIO;
82762306a36Sopenharmony_ci
82862306a36Sopenharmony_ci	mutex_unlock(&mb1_transfer.lock);
82962306a36Sopenharmony_ci
83062306a36Sopenharmony_ci	return r;
83162306a36Sopenharmony_ci}
83262306a36Sopenharmony_ci
83362306a36Sopenharmony_ci/**
83462306a36Sopenharmony_ci * db8500_prcmu_get_arm_opp - get the current ARM OPP
83562306a36Sopenharmony_ci *
83662306a36Sopenharmony_ci * Returns: the current ARM OPP
83762306a36Sopenharmony_ci */
83862306a36Sopenharmony_ciint db8500_prcmu_get_arm_opp(void)
83962306a36Sopenharmony_ci{
84062306a36Sopenharmony_ci	return readb(tcdm_base + PRCM_ACK_MB1_CURRENT_ARM_OPP);
84162306a36Sopenharmony_ci}
84262306a36Sopenharmony_ci
84362306a36Sopenharmony_ci/**
84462306a36Sopenharmony_ci * db8500_prcmu_get_ddr_opp - get the current DDR OPP
84562306a36Sopenharmony_ci *
84662306a36Sopenharmony_ci * Returns: the current DDR OPP
84762306a36Sopenharmony_ci */
84862306a36Sopenharmony_ciint db8500_prcmu_get_ddr_opp(void)
84962306a36Sopenharmony_ci{
85062306a36Sopenharmony_ci	return readb(PRCM_DDR_SUBSYS_APE_MINBW);
85162306a36Sopenharmony_ci}
85262306a36Sopenharmony_ci
85362306a36Sopenharmony_ci/* Divide the frequency of certain clocks by 2 for APE_50_PARTLY_25_OPP. */
85462306a36Sopenharmony_cistatic void request_even_slower_clocks(bool enable)
85562306a36Sopenharmony_ci{
85662306a36Sopenharmony_ci	u32 clock_reg[] = {
85762306a36Sopenharmony_ci		PRCM_ACLK_MGT,
85862306a36Sopenharmony_ci		PRCM_DMACLK_MGT
85962306a36Sopenharmony_ci	};
86062306a36Sopenharmony_ci	unsigned long flags;
86162306a36Sopenharmony_ci	unsigned int i;
86262306a36Sopenharmony_ci
86362306a36Sopenharmony_ci	spin_lock_irqsave(&clk_mgt_lock, flags);
86462306a36Sopenharmony_ci
86562306a36Sopenharmony_ci	/* Grab the HW semaphore. */
86662306a36Sopenharmony_ci	while ((readl(PRCM_SEM) & PRCM_SEM_PRCM_SEM) != 0)
86762306a36Sopenharmony_ci		cpu_relax();
86862306a36Sopenharmony_ci
86962306a36Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(clock_reg); i++) {
87062306a36Sopenharmony_ci		u32 val;
87162306a36Sopenharmony_ci		u32 div;
87262306a36Sopenharmony_ci
87362306a36Sopenharmony_ci		val = readl(prcmu_base + clock_reg[i]);
87462306a36Sopenharmony_ci		div = (val & PRCM_CLK_MGT_CLKPLLDIV_MASK);
87562306a36Sopenharmony_ci		if (enable) {
87662306a36Sopenharmony_ci			if ((div <= 1) || (div > 15)) {
87762306a36Sopenharmony_ci				pr_err("prcmu: Bad clock divider %d in %s\n",
87862306a36Sopenharmony_ci					div, __func__);
87962306a36Sopenharmony_ci				goto unlock_and_return;
88062306a36Sopenharmony_ci			}
88162306a36Sopenharmony_ci			div <<= 1;
88262306a36Sopenharmony_ci		} else {
88362306a36Sopenharmony_ci			if (div <= 2)
88462306a36Sopenharmony_ci				goto unlock_and_return;
88562306a36Sopenharmony_ci			div >>= 1;
88662306a36Sopenharmony_ci		}
88762306a36Sopenharmony_ci		val = ((val & ~PRCM_CLK_MGT_CLKPLLDIV_MASK) |
88862306a36Sopenharmony_ci			(div & PRCM_CLK_MGT_CLKPLLDIV_MASK));
88962306a36Sopenharmony_ci		writel(val, prcmu_base + clock_reg[i]);
89062306a36Sopenharmony_ci	}
89162306a36Sopenharmony_ci
89262306a36Sopenharmony_ciunlock_and_return:
89362306a36Sopenharmony_ci	/* Release the HW semaphore. */
89462306a36Sopenharmony_ci	writel(0, PRCM_SEM);
89562306a36Sopenharmony_ci
89662306a36Sopenharmony_ci	spin_unlock_irqrestore(&clk_mgt_lock, flags);
89762306a36Sopenharmony_ci}
89862306a36Sopenharmony_ci
89962306a36Sopenharmony_ci/**
90062306a36Sopenharmony_ci * db8500_prcmu_set_ape_opp - set the appropriate APE OPP
90162306a36Sopenharmony_ci * @opp: The new APE operating point to which transition is to be made
90262306a36Sopenharmony_ci * Returns: 0 on success, non-zero on failure
90362306a36Sopenharmony_ci *
90462306a36Sopenharmony_ci * This function sets the operating point of the APE.
90562306a36Sopenharmony_ci */
90662306a36Sopenharmony_ciint db8500_prcmu_set_ape_opp(u8 opp)
90762306a36Sopenharmony_ci{
90862306a36Sopenharmony_ci	int r = 0;
90962306a36Sopenharmony_ci
91062306a36Sopenharmony_ci	if (opp == mb1_transfer.ape_opp)
91162306a36Sopenharmony_ci		return 0;
91262306a36Sopenharmony_ci
91362306a36Sopenharmony_ci	mutex_lock(&mb1_transfer.lock);
91462306a36Sopenharmony_ci
91562306a36Sopenharmony_ci	if (mb1_transfer.ape_opp == APE_50_PARTLY_25_OPP)
91662306a36Sopenharmony_ci		request_even_slower_clocks(false);
91762306a36Sopenharmony_ci
91862306a36Sopenharmony_ci	if ((opp != APE_100_OPP) && (mb1_transfer.ape_opp != APE_100_OPP))
91962306a36Sopenharmony_ci		goto skip_message;
92062306a36Sopenharmony_ci
92162306a36Sopenharmony_ci	while (readl(PRCM_MBOX_CPU_VAL) & MBOX_BIT(1))
92262306a36Sopenharmony_ci		cpu_relax();
92362306a36Sopenharmony_ci
92462306a36Sopenharmony_ci	writeb(MB1H_ARM_APE_OPP, (tcdm_base + PRCM_MBOX_HEADER_REQ_MB1));
92562306a36Sopenharmony_ci	writeb(ARM_NO_CHANGE, (tcdm_base + PRCM_REQ_MB1_ARM_OPP));
92662306a36Sopenharmony_ci	writeb(((opp == APE_50_PARTLY_25_OPP) ? APE_50_OPP : opp),
92762306a36Sopenharmony_ci		(tcdm_base + PRCM_REQ_MB1_APE_OPP));
92862306a36Sopenharmony_ci
92962306a36Sopenharmony_ci	writel(MBOX_BIT(1), PRCM_MBOX_CPU_SET);
93062306a36Sopenharmony_ci	wait_for_completion(&mb1_transfer.work);
93162306a36Sopenharmony_ci
93262306a36Sopenharmony_ci	if ((mb1_transfer.ack.header != MB1H_ARM_APE_OPP) ||
93362306a36Sopenharmony_ci		(mb1_transfer.ack.ape_opp != opp))
93462306a36Sopenharmony_ci		r = -EIO;
93562306a36Sopenharmony_ci
93662306a36Sopenharmony_ciskip_message:
93762306a36Sopenharmony_ci	if ((!r && (opp == APE_50_PARTLY_25_OPP)) ||
93862306a36Sopenharmony_ci		(r && (mb1_transfer.ape_opp == APE_50_PARTLY_25_OPP)))
93962306a36Sopenharmony_ci		request_even_slower_clocks(true);
94062306a36Sopenharmony_ci	if (!r)
94162306a36Sopenharmony_ci		mb1_transfer.ape_opp = opp;
94262306a36Sopenharmony_ci
94362306a36Sopenharmony_ci	mutex_unlock(&mb1_transfer.lock);
94462306a36Sopenharmony_ci
94562306a36Sopenharmony_ci	return r;
94662306a36Sopenharmony_ci}
94762306a36Sopenharmony_ci
94862306a36Sopenharmony_ci/**
94962306a36Sopenharmony_ci * db8500_prcmu_get_ape_opp - get the current APE OPP
95062306a36Sopenharmony_ci *
95162306a36Sopenharmony_ci * Returns: the current APE OPP
95262306a36Sopenharmony_ci */
95362306a36Sopenharmony_ciint db8500_prcmu_get_ape_opp(void)
95462306a36Sopenharmony_ci{
95562306a36Sopenharmony_ci	return readb(tcdm_base + PRCM_ACK_MB1_CURRENT_APE_OPP);
95662306a36Sopenharmony_ci}
95762306a36Sopenharmony_ci
95862306a36Sopenharmony_ci/**
95962306a36Sopenharmony_ci * db8500_prcmu_request_ape_opp_100_voltage - Request APE OPP 100% voltage
96062306a36Sopenharmony_ci * @enable: true to request the higher voltage, false to drop a request.
96162306a36Sopenharmony_ci *
96262306a36Sopenharmony_ci * Calls to this function to enable and disable requests must be balanced.
96362306a36Sopenharmony_ci */
96462306a36Sopenharmony_ciint db8500_prcmu_request_ape_opp_100_voltage(bool enable)
96562306a36Sopenharmony_ci{
96662306a36Sopenharmony_ci	int r = 0;
96762306a36Sopenharmony_ci	u8 header;
96862306a36Sopenharmony_ci	static unsigned int requests;
96962306a36Sopenharmony_ci
97062306a36Sopenharmony_ci	mutex_lock(&mb1_transfer.lock);
97162306a36Sopenharmony_ci
97262306a36Sopenharmony_ci	if (enable) {
97362306a36Sopenharmony_ci		if (0 != requests++)
97462306a36Sopenharmony_ci			goto unlock_and_return;
97562306a36Sopenharmony_ci		header = MB1H_REQUEST_APE_OPP_100_VOLT;
97662306a36Sopenharmony_ci	} else {
97762306a36Sopenharmony_ci		if (requests == 0) {
97862306a36Sopenharmony_ci			r = -EIO;
97962306a36Sopenharmony_ci			goto unlock_and_return;
98062306a36Sopenharmony_ci		} else if (1 != requests--) {
98162306a36Sopenharmony_ci			goto unlock_and_return;
98262306a36Sopenharmony_ci		}
98362306a36Sopenharmony_ci		header = MB1H_RELEASE_APE_OPP_100_VOLT;
98462306a36Sopenharmony_ci	}
98562306a36Sopenharmony_ci
98662306a36Sopenharmony_ci	while (readl(PRCM_MBOX_CPU_VAL) & MBOX_BIT(1))
98762306a36Sopenharmony_ci		cpu_relax();
98862306a36Sopenharmony_ci
98962306a36Sopenharmony_ci	writeb(header, (tcdm_base + PRCM_MBOX_HEADER_REQ_MB1));
99062306a36Sopenharmony_ci
99162306a36Sopenharmony_ci	writel(MBOX_BIT(1), PRCM_MBOX_CPU_SET);
99262306a36Sopenharmony_ci	wait_for_completion(&mb1_transfer.work);
99362306a36Sopenharmony_ci
99462306a36Sopenharmony_ci	if ((mb1_transfer.ack.header != header) ||
99562306a36Sopenharmony_ci		((mb1_transfer.ack.ape_voltage_status & BIT(0)) != 0))
99662306a36Sopenharmony_ci		r = -EIO;
99762306a36Sopenharmony_ci
99862306a36Sopenharmony_ciunlock_and_return:
99962306a36Sopenharmony_ci	mutex_unlock(&mb1_transfer.lock);
100062306a36Sopenharmony_ci
100162306a36Sopenharmony_ci	return r;
100262306a36Sopenharmony_ci}
100362306a36Sopenharmony_ci
100462306a36Sopenharmony_ci/**
100562306a36Sopenharmony_ci * prcmu_release_usb_wakeup_state - release the state required by a USB wakeup
100662306a36Sopenharmony_ci *
100762306a36Sopenharmony_ci * This function releases the power state requirements of a USB wakeup.
100862306a36Sopenharmony_ci */
100962306a36Sopenharmony_ciint prcmu_release_usb_wakeup_state(void)
101062306a36Sopenharmony_ci{
101162306a36Sopenharmony_ci	int r = 0;
101262306a36Sopenharmony_ci
101362306a36Sopenharmony_ci	mutex_lock(&mb1_transfer.lock);
101462306a36Sopenharmony_ci
101562306a36Sopenharmony_ci	while (readl(PRCM_MBOX_CPU_VAL) & MBOX_BIT(1))
101662306a36Sopenharmony_ci		cpu_relax();
101762306a36Sopenharmony_ci
101862306a36Sopenharmony_ci	writeb(MB1H_RELEASE_USB_WAKEUP,
101962306a36Sopenharmony_ci		(tcdm_base + PRCM_MBOX_HEADER_REQ_MB1));
102062306a36Sopenharmony_ci
102162306a36Sopenharmony_ci	writel(MBOX_BIT(1), PRCM_MBOX_CPU_SET);
102262306a36Sopenharmony_ci	wait_for_completion(&mb1_transfer.work);
102362306a36Sopenharmony_ci
102462306a36Sopenharmony_ci	if ((mb1_transfer.ack.header != MB1H_RELEASE_USB_WAKEUP) ||
102562306a36Sopenharmony_ci		((mb1_transfer.ack.ape_voltage_status & BIT(0)) != 0))
102662306a36Sopenharmony_ci		r = -EIO;
102762306a36Sopenharmony_ci
102862306a36Sopenharmony_ci	mutex_unlock(&mb1_transfer.lock);
102962306a36Sopenharmony_ci
103062306a36Sopenharmony_ci	return r;
103162306a36Sopenharmony_ci}
103262306a36Sopenharmony_ci
103362306a36Sopenharmony_cistatic int request_pll(u8 clock, bool enable)
103462306a36Sopenharmony_ci{
103562306a36Sopenharmony_ci	int r = 0;
103662306a36Sopenharmony_ci
103762306a36Sopenharmony_ci	if (clock == PRCMU_PLLSOC0)
103862306a36Sopenharmony_ci		clock = (enable ? PLL_SOC0_ON : PLL_SOC0_OFF);
103962306a36Sopenharmony_ci	else if (clock == PRCMU_PLLSOC1)
104062306a36Sopenharmony_ci		clock = (enable ? PLL_SOC1_ON : PLL_SOC1_OFF);
104162306a36Sopenharmony_ci	else
104262306a36Sopenharmony_ci		return -EINVAL;
104362306a36Sopenharmony_ci
104462306a36Sopenharmony_ci	mutex_lock(&mb1_transfer.lock);
104562306a36Sopenharmony_ci
104662306a36Sopenharmony_ci	while (readl(PRCM_MBOX_CPU_VAL) & MBOX_BIT(1))
104762306a36Sopenharmony_ci		cpu_relax();
104862306a36Sopenharmony_ci
104962306a36Sopenharmony_ci	writeb(MB1H_PLL_ON_OFF, (tcdm_base + PRCM_MBOX_HEADER_REQ_MB1));
105062306a36Sopenharmony_ci	writeb(clock, (tcdm_base + PRCM_REQ_MB1_PLL_ON_OFF));
105162306a36Sopenharmony_ci
105262306a36Sopenharmony_ci	writel(MBOX_BIT(1), PRCM_MBOX_CPU_SET);
105362306a36Sopenharmony_ci	wait_for_completion(&mb1_transfer.work);
105462306a36Sopenharmony_ci
105562306a36Sopenharmony_ci	if (mb1_transfer.ack.header != MB1H_PLL_ON_OFF)
105662306a36Sopenharmony_ci		r = -EIO;
105762306a36Sopenharmony_ci
105862306a36Sopenharmony_ci	mutex_unlock(&mb1_transfer.lock);
105962306a36Sopenharmony_ci
106062306a36Sopenharmony_ci	return r;
106162306a36Sopenharmony_ci}
106262306a36Sopenharmony_ci
106362306a36Sopenharmony_ci/**
106462306a36Sopenharmony_ci * db8500_prcmu_set_epod - set the state of a EPOD (power domain)
106562306a36Sopenharmony_ci * @epod_id: The EPOD to set
106662306a36Sopenharmony_ci * @epod_state: The new EPOD state
106762306a36Sopenharmony_ci *
106862306a36Sopenharmony_ci * This function sets the state of a EPOD (power domain). It may not be called
106962306a36Sopenharmony_ci * from interrupt context.
107062306a36Sopenharmony_ci */
107162306a36Sopenharmony_ciint db8500_prcmu_set_epod(u16 epod_id, u8 epod_state)
107262306a36Sopenharmony_ci{
107362306a36Sopenharmony_ci	int r = 0;
107462306a36Sopenharmony_ci	bool ram_retention = false;
107562306a36Sopenharmony_ci	int i;
107662306a36Sopenharmony_ci
107762306a36Sopenharmony_ci	/* check argument */
107862306a36Sopenharmony_ci	BUG_ON(epod_id >= NUM_EPOD_ID);
107962306a36Sopenharmony_ci
108062306a36Sopenharmony_ci	/* set flag if retention is possible */
108162306a36Sopenharmony_ci	switch (epod_id) {
108262306a36Sopenharmony_ci	case EPOD_ID_SVAMMDSP:
108362306a36Sopenharmony_ci	case EPOD_ID_SIAMMDSP:
108462306a36Sopenharmony_ci	case EPOD_ID_ESRAM12:
108562306a36Sopenharmony_ci	case EPOD_ID_ESRAM34:
108662306a36Sopenharmony_ci		ram_retention = true;
108762306a36Sopenharmony_ci		break;
108862306a36Sopenharmony_ci	}
108962306a36Sopenharmony_ci
109062306a36Sopenharmony_ci	/* check argument */
109162306a36Sopenharmony_ci	BUG_ON(epod_state > EPOD_STATE_ON);
109262306a36Sopenharmony_ci	BUG_ON(epod_state == EPOD_STATE_RAMRET && !ram_retention);
109362306a36Sopenharmony_ci
109462306a36Sopenharmony_ci	/* get lock */
109562306a36Sopenharmony_ci	mutex_lock(&mb2_transfer.lock);
109662306a36Sopenharmony_ci
109762306a36Sopenharmony_ci	/* wait for mailbox */
109862306a36Sopenharmony_ci	while (readl(PRCM_MBOX_CPU_VAL) & MBOX_BIT(2))
109962306a36Sopenharmony_ci		cpu_relax();
110062306a36Sopenharmony_ci
110162306a36Sopenharmony_ci	/* fill in mailbox */
110262306a36Sopenharmony_ci	for (i = 0; i < NUM_EPOD_ID; i++)
110362306a36Sopenharmony_ci		writeb(EPOD_STATE_NO_CHANGE, (tcdm_base + PRCM_REQ_MB2 + i));
110462306a36Sopenharmony_ci	writeb(epod_state, (tcdm_base + PRCM_REQ_MB2 + epod_id));
110562306a36Sopenharmony_ci
110662306a36Sopenharmony_ci	writeb(MB2H_DPS, (tcdm_base + PRCM_MBOX_HEADER_REQ_MB2));
110762306a36Sopenharmony_ci
110862306a36Sopenharmony_ci	writel(MBOX_BIT(2), PRCM_MBOX_CPU_SET);
110962306a36Sopenharmony_ci
111062306a36Sopenharmony_ci	/*
111162306a36Sopenharmony_ci	 * The current firmware version does not handle errors correctly,
111262306a36Sopenharmony_ci	 * and we cannot recover if there is an error.
111362306a36Sopenharmony_ci	 * This is expected to change when the firmware is updated.
111462306a36Sopenharmony_ci	 */
111562306a36Sopenharmony_ci	if (!wait_for_completion_timeout(&mb2_transfer.work,
111662306a36Sopenharmony_ci			msecs_to_jiffies(20000))) {
111762306a36Sopenharmony_ci		pr_err("prcmu: %s timed out (20 s) waiting for a reply.\n",
111862306a36Sopenharmony_ci			__func__);
111962306a36Sopenharmony_ci		r = -EIO;
112062306a36Sopenharmony_ci		goto unlock_and_return;
112162306a36Sopenharmony_ci	}
112262306a36Sopenharmony_ci
112362306a36Sopenharmony_ci	if (mb2_transfer.ack.status != HWACC_PWR_ST_OK)
112462306a36Sopenharmony_ci		r = -EIO;
112562306a36Sopenharmony_ci
112662306a36Sopenharmony_ciunlock_and_return:
112762306a36Sopenharmony_ci	mutex_unlock(&mb2_transfer.lock);
112862306a36Sopenharmony_ci	return r;
112962306a36Sopenharmony_ci}
113062306a36Sopenharmony_ci
113162306a36Sopenharmony_ci/**
113262306a36Sopenharmony_ci * prcmu_configure_auto_pm - Configure autonomous power management.
113362306a36Sopenharmony_ci * @sleep: Configuration for ApSleep.
113462306a36Sopenharmony_ci * @idle:  Configuration for ApIdle.
113562306a36Sopenharmony_ci */
113662306a36Sopenharmony_civoid prcmu_configure_auto_pm(struct prcmu_auto_pm_config *sleep,
113762306a36Sopenharmony_ci	struct prcmu_auto_pm_config *idle)
113862306a36Sopenharmony_ci{
113962306a36Sopenharmony_ci	u32 sleep_cfg;
114062306a36Sopenharmony_ci	u32 idle_cfg;
114162306a36Sopenharmony_ci	unsigned long flags;
114262306a36Sopenharmony_ci
114362306a36Sopenharmony_ci	BUG_ON((sleep == NULL) || (idle == NULL));
114462306a36Sopenharmony_ci
114562306a36Sopenharmony_ci	sleep_cfg = (sleep->sva_auto_pm_enable & 0xF);
114662306a36Sopenharmony_ci	sleep_cfg = ((sleep_cfg << 4) | (sleep->sia_auto_pm_enable & 0xF));
114762306a36Sopenharmony_ci	sleep_cfg = ((sleep_cfg << 8) | (sleep->sva_power_on & 0xFF));
114862306a36Sopenharmony_ci	sleep_cfg = ((sleep_cfg << 8) | (sleep->sia_power_on & 0xFF));
114962306a36Sopenharmony_ci	sleep_cfg = ((sleep_cfg << 4) | (sleep->sva_policy & 0xF));
115062306a36Sopenharmony_ci	sleep_cfg = ((sleep_cfg << 4) | (sleep->sia_policy & 0xF));
115162306a36Sopenharmony_ci
115262306a36Sopenharmony_ci	idle_cfg = (idle->sva_auto_pm_enable & 0xF);
115362306a36Sopenharmony_ci	idle_cfg = ((idle_cfg << 4) | (idle->sia_auto_pm_enable & 0xF));
115462306a36Sopenharmony_ci	idle_cfg = ((idle_cfg << 8) | (idle->sva_power_on & 0xFF));
115562306a36Sopenharmony_ci	idle_cfg = ((idle_cfg << 8) | (idle->sia_power_on & 0xFF));
115662306a36Sopenharmony_ci	idle_cfg = ((idle_cfg << 4) | (idle->sva_policy & 0xF));
115762306a36Sopenharmony_ci	idle_cfg = ((idle_cfg << 4) | (idle->sia_policy & 0xF));
115862306a36Sopenharmony_ci
115962306a36Sopenharmony_ci	spin_lock_irqsave(&mb2_transfer.auto_pm_lock, flags);
116062306a36Sopenharmony_ci
116162306a36Sopenharmony_ci	/*
116262306a36Sopenharmony_ci	 * The autonomous power management configuration is done through
116362306a36Sopenharmony_ci	 * fields in mailbox 2, but these fields are only used as shared
116462306a36Sopenharmony_ci	 * variables - i.e. there is no need to send a message.
116562306a36Sopenharmony_ci	 */
116662306a36Sopenharmony_ci	writel(sleep_cfg, (tcdm_base + PRCM_REQ_MB2_AUTO_PM_SLEEP));
116762306a36Sopenharmony_ci	writel(idle_cfg, (tcdm_base + PRCM_REQ_MB2_AUTO_PM_IDLE));
116862306a36Sopenharmony_ci
116962306a36Sopenharmony_ci	mb2_transfer.auto_pm_enabled =
117062306a36Sopenharmony_ci		((sleep->sva_auto_pm_enable == PRCMU_AUTO_PM_ON) ||
117162306a36Sopenharmony_ci		 (sleep->sia_auto_pm_enable == PRCMU_AUTO_PM_ON) ||
117262306a36Sopenharmony_ci		 (idle->sva_auto_pm_enable == PRCMU_AUTO_PM_ON) ||
117362306a36Sopenharmony_ci		 (idle->sia_auto_pm_enable == PRCMU_AUTO_PM_ON));
117462306a36Sopenharmony_ci
117562306a36Sopenharmony_ci	spin_unlock_irqrestore(&mb2_transfer.auto_pm_lock, flags);
117662306a36Sopenharmony_ci}
117762306a36Sopenharmony_ciEXPORT_SYMBOL(prcmu_configure_auto_pm);
117862306a36Sopenharmony_ci
117962306a36Sopenharmony_cibool prcmu_is_auto_pm_enabled(void)
118062306a36Sopenharmony_ci{
118162306a36Sopenharmony_ci	return mb2_transfer.auto_pm_enabled;
118262306a36Sopenharmony_ci}
118362306a36Sopenharmony_ci
118462306a36Sopenharmony_cistatic int request_sysclk(bool enable)
118562306a36Sopenharmony_ci{
118662306a36Sopenharmony_ci	int r;
118762306a36Sopenharmony_ci	unsigned long flags;
118862306a36Sopenharmony_ci
118962306a36Sopenharmony_ci	r = 0;
119062306a36Sopenharmony_ci
119162306a36Sopenharmony_ci	mutex_lock(&mb3_transfer.sysclk_lock);
119262306a36Sopenharmony_ci
119362306a36Sopenharmony_ci	spin_lock_irqsave(&mb3_transfer.lock, flags);
119462306a36Sopenharmony_ci
119562306a36Sopenharmony_ci	while (readl(PRCM_MBOX_CPU_VAL) & MBOX_BIT(3))
119662306a36Sopenharmony_ci		cpu_relax();
119762306a36Sopenharmony_ci
119862306a36Sopenharmony_ci	writeb((enable ? ON : OFF), (tcdm_base + PRCM_REQ_MB3_SYSCLK_MGT));
119962306a36Sopenharmony_ci
120062306a36Sopenharmony_ci	writeb(MB3H_SYSCLK, (tcdm_base + PRCM_MBOX_HEADER_REQ_MB3));
120162306a36Sopenharmony_ci	writel(MBOX_BIT(3), PRCM_MBOX_CPU_SET);
120262306a36Sopenharmony_ci
120362306a36Sopenharmony_ci	spin_unlock_irqrestore(&mb3_transfer.lock, flags);
120462306a36Sopenharmony_ci
120562306a36Sopenharmony_ci	/*
120662306a36Sopenharmony_ci	 * The firmware only sends an ACK if we want to enable the
120762306a36Sopenharmony_ci	 * SysClk, and it succeeds.
120862306a36Sopenharmony_ci	 */
120962306a36Sopenharmony_ci	if (enable && !wait_for_completion_timeout(&mb3_transfer.sysclk_work,
121062306a36Sopenharmony_ci			msecs_to_jiffies(20000))) {
121162306a36Sopenharmony_ci		pr_err("prcmu: %s timed out (20 s) waiting for a reply.\n",
121262306a36Sopenharmony_ci			__func__);
121362306a36Sopenharmony_ci		r = -EIO;
121462306a36Sopenharmony_ci	}
121562306a36Sopenharmony_ci
121662306a36Sopenharmony_ci	mutex_unlock(&mb3_transfer.sysclk_lock);
121762306a36Sopenharmony_ci
121862306a36Sopenharmony_ci	return r;
121962306a36Sopenharmony_ci}
122062306a36Sopenharmony_ci
122162306a36Sopenharmony_cistatic int request_timclk(bool enable)
122262306a36Sopenharmony_ci{
122362306a36Sopenharmony_ci	u32 val;
122462306a36Sopenharmony_ci
122562306a36Sopenharmony_ci	/*
122662306a36Sopenharmony_ci	 * On the U8420_CLKSEL firmware, the ULP (Ultra Low Power)
122762306a36Sopenharmony_ci	 * PLL is disabled so we cannot use doze mode, this will
122862306a36Sopenharmony_ci	 * stop the clock on this firmware.
122962306a36Sopenharmony_ci	 */
123062306a36Sopenharmony_ci	if (prcmu_is_ulppll_disabled())
123162306a36Sopenharmony_ci		val = 0;
123262306a36Sopenharmony_ci	else
123362306a36Sopenharmony_ci		val = (PRCM_TCR_DOZE_MODE | PRCM_TCR_TENSEL_MASK);
123462306a36Sopenharmony_ci
123562306a36Sopenharmony_ci	if (!enable)
123662306a36Sopenharmony_ci		val |= PRCM_TCR_STOP_TIMERS |
123762306a36Sopenharmony_ci			PRCM_TCR_DOZE_MODE |
123862306a36Sopenharmony_ci			PRCM_TCR_TENSEL_MASK;
123962306a36Sopenharmony_ci
124062306a36Sopenharmony_ci	writel(val, PRCM_TCR);
124162306a36Sopenharmony_ci
124262306a36Sopenharmony_ci	return 0;
124362306a36Sopenharmony_ci}
124462306a36Sopenharmony_ci
124562306a36Sopenharmony_cistatic int request_clock(u8 clock, bool enable)
124662306a36Sopenharmony_ci{
124762306a36Sopenharmony_ci	u32 val;
124862306a36Sopenharmony_ci	unsigned long flags;
124962306a36Sopenharmony_ci
125062306a36Sopenharmony_ci	spin_lock_irqsave(&clk_mgt_lock, flags);
125162306a36Sopenharmony_ci
125262306a36Sopenharmony_ci	/* Grab the HW semaphore. */
125362306a36Sopenharmony_ci	while ((readl(PRCM_SEM) & PRCM_SEM_PRCM_SEM) != 0)
125462306a36Sopenharmony_ci		cpu_relax();
125562306a36Sopenharmony_ci
125662306a36Sopenharmony_ci	val = readl(prcmu_base + clk_mgt[clock].offset);
125762306a36Sopenharmony_ci	if (enable) {
125862306a36Sopenharmony_ci		val |= (PRCM_CLK_MGT_CLKEN | clk_mgt[clock].pllsw);
125962306a36Sopenharmony_ci	} else {
126062306a36Sopenharmony_ci		clk_mgt[clock].pllsw = (val & PRCM_CLK_MGT_CLKPLLSW_MASK);
126162306a36Sopenharmony_ci		val &= ~(PRCM_CLK_MGT_CLKEN | PRCM_CLK_MGT_CLKPLLSW_MASK);
126262306a36Sopenharmony_ci	}
126362306a36Sopenharmony_ci	writel(val, prcmu_base + clk_mgt[clock].offset);
126462306a36Sopenharmony_ci
126562306a36Sopenharmony_ci	/* Release the HW semaphore. */
126662306a36Sopenharmony_ci	writel(0, PRCM_SEM);
126762306a36Sopenharmony_ci
126862306a36Sopenharmony_ci	spin_unlock_irqrestore(&clk_mgt_lock, flags);
126962306a36Sopenharmony_ci
127062306a36Sopenharmony_ci	return 0;
127162306a36Sopenharmony_ci}
127262306a36Sopenharmony_ci
127362306a36Sopenharmony_cistatic int request_sga_clock(u8 clock, bool enable)
127462306a36Sopenharmony_ci{
127562306a36Sopenharmony_ci	u32 val;
127662306a36Sopenharmony_ci	int ret;
127762306a36Sopenharmony_ci
127862306a36Sopenharmony_ci	if (enable) {
127962306a36Sopenharmony_ci		val = readl(PRCM_CGATING_BYPASS);
128062306a36Sopenharmony_ci		writel(val | PRCM_CGATING_BYPASS_ICN2, PRCM_CGATING_BYPASS);
128162306a36Sopenharmony_ci	}
128262306a36Sopenharmony_ci
128362306a36Sopenharmony_ci	ret = request_clock(clock, enable);
128462306a36Sopenharmony_ci
128562306a36Sopenharmony_ci	if (!ret && !enable) {
128662306a36Sopenharmony_ci		val = readl(PRCM_CGATING_BYPASS);
128762306a36Sopenharmony_ci		writel(val & ~PRCM_CGATING_BYPASS_ICN2, PRCM_CGATING_BYPASS);
128862306a36Sopenharmony_ci	}
128962306a36Sopenharmony_ci
129062306a36Sopenharmony_ci	return ret;
129162306a36Sopenharmony_ci}
129262306a36Sopenharmony_ci
129362306a36Sopenharmony_cistatic inline bool plldsi_locked(void)
129462306a36Sopenharmony_ci{
129562306a36Sopenharmony_ci	return (readl(PRCM_PLLDSI_LOCKP) &
129662306a36Sopenharmony_ci		(PRCM_PLLDSI_LOCKP_PRCM_PLLDSI_LOCKP10 |
129762306a36Sopenharmony_ci		 PRCM_PLLDSI_LOCKP_PRCM_PLLDSI_LOCKP3)) ==
129862306a36Sopenharmony_ci		(PRCM_PLLDSI_LOCKP_PRCM_PLLDSI_LOCKP10 |
129962306a36Sopenharmony_ci		 PRCM_PLLDSI_LOCKP_PRCM_PLLDSI_LOCKP3);
130062306a36Sopenharmony_ci}
130162306a36Sopenharmony_ci
130262306a36Sopenharmony_cistatic int request_plldsi(bool enable)
130362306a36Sopenharmony_ci{
130462306a36Sopenharmony_ci	int r = 0;
130562306a36Sopenharmony_ci	u32 val;
130662306a36Sopenharmony_ci
130762306a36Sopenharmony_ci	writel((PRCM_MMIP_LS_CLAMP_DSIPLL_CLAMP |
130862306a36Sopenharmony_ci		PRCM_MMIP_LS_CLAMP_DSIPLL_CLAMPI), (enable ?
130962306a36Sopenharmony_ci		PRCM_MMIP_LS_CLAMP_CLR : PRCM_MMIP_LS_CLAMP_SET));
131062306a36Sopenharmony_ci
131162306a36Sopenharmony_ci	val = readl(PRCM_PLLDSI_ENABLE);
131262306a36Sopenharmony_ci	if (enable)
131362306a36Sopenharmony_ci		val |= PRCM_PLLDSI_ENABLE_PRCM_PLLDSI_ENABLE;
131462306a36Sopenharmony_ci	else
131562306a36Sopenharmony_ci		val &= ~PRCM_PLLDSI_ENABLE_PRCM_PLLDSI_ENABLE;
131662306a36Sopenharmony_ci	writel(val, PRCM_PLLDSI_ENABLE);
131762306a36Sopenharmony_ci
131862306a36Sopenharmony_ci	if (enable) {
131962306a36Sopenharmony_ci		unsigned int i;
132062306a36Sopenharmony_ci		bool locked = plldsi_locked();
132162306a36Sopenharmony_ci
132262306a36Sopenharmony_ci		for (i = 10; !locked && (i > 0); --i) {
132362306a36Sopenharmony_ci			udelay(100);
132462306a36Sopenharmony_ci			locked = plldsi_locked();
132562306a36Sopenharmony_ci		}
132662306a36Sopenharmony_ci		if (locked) {
132762306a36Sopenharmony_ci			writel(PRCM_APE_RESETN_DSIPLL_RESETN,
132862306a36Sopenharmony_ci				PRCM_APE_RESETN_SET);
132962306a36Sopenharmony_ci		} else {
133062306a36Sopenharmony_ci			writel((PRCM_MMIP_LS_CLAMP_DSIPLL_CLAMP |
133162306a36Sopenharmony_ci				PRCM_MMIP_LS_CLAMP_DSIPLL_CLAMPI),
133262306a36Sopenharmony_ci				PRCM_MMIP_LS_CLAMP_SET);
133362306a36Sopenharmony_ci			val &= ~PRCM_PLLDSI_ENABLE_PRCM_PLLDSI_ENABLE;
133462306a36Sopenharmony_ci			writel(val, PRCM_PLLDSI_ENABLE);
133562306a36Sopenharmony_ci			r = -EAGAIN;
133662306a36Sopenharmony_ci		}
133762306a36Sopenharmony_ci	} else {
133862306a36Sopenharmony_ci		writel(PRCM_APE_RESETN_DSIPLL_RESETN, PRCM_APE_RESETN_CLR);
133962306a36Sopenharmony_ci	}
134062306a36Sopenharmony_ci	return r;
134162306a36Sopenharmony_ci}
134262306a36Sopenharmony_ci
134362306a36Sopenharmony_cistatic int request_dsiclk(u8 n, bool enable)
134462306a36Sopenharmony_ci{
134562306a36Sopenharmony_ci	u32 val;
134662306a36Sopenharmony_ci
134762306a36Sopenharmony_ci	val = readl(PRCM_DSI_PLLOUT_SEL);
134862306a36Sopenharmony_ci	val &= ~dsiclk[n].divsel_mask;
134962306a36Sopenharmony_ci	val |= ((enable ? dsiclk[n].divsel : PRCM_DSI_PLLOUT_SEL_OFF) <<
135062306a36Sopenharmony_ci		dsiclk[n].divsel_shift);
135162306a36Sopenharmony_ci	writel(val, PRCM_DSI_PLLOUT_SEL);
135262306a36Sopenharmony_ci	return 0;
135362306a36Sopenharmony_ci}
135462306a36Sopenharmony_ci
135562306a36Sopenharmony_cistatic int request_dsiescclk(u8 n, bool enable)
135662306a36Sopenharmony_ci{
135762306a36Sopenharmony_ci	u32 val;
135862306a36Sopenharmony_ci
135962306a36Sopenharmony_ci	val = readl(PRCM_DSITVCLK_DIV);
136062306a36Sopenharmony_ci	enable ? (val |= dsiescclk[n].en) : (val &= ~dsiescclk[n].en);
136162306a36Sopenharmony_ci	writel(val, PRCM_DSITVCLK_DIV);
136262306a36Sopenharmony_ci	return 0;
136362306a36Sopenharmony_ci}
136462306a36Sopenharmony_ci
136562306a36Sopenharmony_ci/**
136662306a36Sopenharmony_ci * db8500_prcmu_request_clock() - Request for a clock to be enabled or disabled.
136762306a36Sopenharmony_ci * @clock:      The clock for which the request is made.
136862306a36Sopenharmony_ci * @enable:     Whether the clock should be enabled (true) or disabled (false).
136962306a36Sopenharmony_ci *
137062306a36Sopenharmony_ci * This function should only be used by the clock implementation.
137162306a36Sopenharmony_ci * Do not use it from any other place!
137262306a36Sopenharmony_ci */
137362306a36Sopenharmony_ciint db8500_prcmu_request_clock(u8 clock, bool enable)
137462306a36Sopenharmony_ci{
137562306a36Sopenharmony_ci	if (clock == PRCMU_SGACLK)
137662306a36Sopenharmony_ci		return request_sga_clock(clock, enable);
137762306a36Sopenharmony_ci	else if (clock < PRCMU_NUM_REG_CLOCKS)
137862306a36Sopenharmony_ci		return request_clock(clock, enable);
137962306a36Sopenharmony_ci	else if (clock == PRCMU_TIMCLK)
138062306a36Sopenharmony_ci		return request_timclk(enable);
138162306a36Sopenharmony_ci	else if ((clock == PRCMU_DSI0CLK) || (clock == PRCMU_DSI1CLK))
138262306a36Sopenharmony_ci		return request_dsiclk((clock - PRCMU_DSI0CLK), enable);
138362306a36Sopenharmony_ci	else if ((PRCMU_DSI0ESCCLK <= clock) && (clock <= PRCMU_DSI2ESCCLK))
138462306a36Sopenharmony_ci		return request_dsiescclk((clock - PRCMU_DSI0ESCCLK), enable);
138562306a36Sopenharmony_ci	else if (clock == PRCMU_PLLDSI)
138662306a36Sopenharmony_ci		return request_plldsi(enable);
138762306a36Sopenharmony_ci	else if (clock == PRCMU_SYSCLK)
138862306a36Sopenharmony_ci		return request_sysclk(enable);
138962306a36Sopenharmony_ci	else if ((clock == PRCMU_PLLSOC0) || (clock == PRCMU_PLLSOC1))
139062306a36Sopenharmony_ci		return request_pll(clock, enable);
139162306a36Sopenharmony_ci	else
139262306a36Sopenharmony_ci		return -EINVAL;
139362306a36Sopenharmony_ci}
139462306a36Sopenharmony_ci
139562306a36Sopenharmony_cistatic unsigned long pll_rate(void __iomem *reg, unsigned long src_rate,
139662306a36Sopenharmony_ci	int branch)
139762306a36Sopenharmony_ci{
139862306a36Sopenharmony_ci	u64 rate;
139962306a36Sopenharmony_ci	u32 val;
140062306a36Sopenharmony_ci	u32 d;
140162306a36Sopenharmony_ci	u32 div = 1;
140262306a36Sopenharmony_ci
140362306a36Sopenharmony_ci	val = readl(reg);
140462306a36Sopenharmony_ci
140562306a36Sopenharmony_ci	rate = src_rate;
140662306a36Sopenharmony_ci	rate *= ((val & PRCM_PLL_FREQ_D_MASK) >> PRCM_PLL_FREQ_D_SHIFT);
140762306a36Sopenharmony_ci
140862306a36Sopenharmony_ci	d = ((val & PRCM_PLL_FREQ_N_MASK) >> PRCM_PLL_FREQ_N_SHIFT);
140962306a36Sopenharmony_ci	if (d > 1)
141062306a36Sopenharmony_ci		div *= d;
141162306a36Sopenharmony_ci
141262306a36Sopenharmony_ci	d = ((val & PRCM_PLL_FREQ_R_MASK) >> PRCM_PLL_FREQ_R_SHIFT);
141362306a36Sopenharmony_ci	if (d > 1)
141462306a36Sopenharmony_ci		div *= d;
141562306a36Sopenharmony_ci
141662306a36Sopenharmony_ci	if (val & PRCM_PLL_FREQ_SELDIV2)
141762306a36Sopenharmony_ci		div *= 2;
141862306a36Sopenharmony_ci
141962306a36Sopenharmony_ci	if ((branch == PLL_FIX) || ((branch == PLL_DIV) &&
142062306a36Sopenharmony_ci		(val & PRCM_PLL_FREQ_DIV2EN) &&
142162306a36Sopenharmony_ci		((reg == PRCM_PLLSOC0_FREQ) ||
142262306a36Sopenharmony_ci		 (reg == PRCM_PLLARM_FREQ) ||
142362306a36Sopenharmony_ci		 (reg == PRCM_PLLDDR_FREQ))))
142462306a36Sopenharmony_ci		div *= 2;
142562306a36Sopenharmony_ci
142662306a36Sopenharmony_ci	(void)do_div(rate, div);
142762306a36Sopenharmony_ci
142862306a36Sopenharmony_ci	return (unsigned long)rate;
142962306a36Sopenharmony_ci}
143062306a36Sopenharmony_ci
143162306a36Sopenharmony_ci#define ROOT_CLOCK_RATE 38400000
143262306a36Sopenharmony_ci
143362306a36Sopenharmony_cistatic unsigned long clock_rate(u8 clock)
143462306a36Sopenharmony_ci{
143562306a36Sopenharmony_ci	u32 val;
143662306a36Sopenharmony_ci	u32 pllsw;
143762306a36Sopenharmony_ci	unsigned long rate = ROOT_CLOCK_RATE;
143862306a36Sopenharmony_ci
143962306a36Sopenharmony_ci	val = readl(prcmu_base + clk_mgt[clock].offset);
144062306a36Sopenharmony_ci
144162306a36Sopenharmony_ci	if (val & PRCM_CLK_MGT_CLK38) {
144262306a36Sopenharmony_ci		if (clk_mgt[clock].clk38div && (val & PRCM_CLK_MGT_CLK38DIV))
144362306a36Sopenharmony_ci			rate /= 2;
144462306a36Sopenharmony_ci		return rate;
144562306a36Sopenharmony_ci	}
144662306a36Sopenharmony_ci
144762306a36Sopenharmony_ci	val |= clk_mgt[clock].pllsw;
144862306a36Sopenharmony_ci	pllsw = (val & PRCM_CLK_MGT_CLKPLLSW_MASK);
144962306a36Sopenharmony_ci
145062306a36Sopenharmony_ci	if (pllsw == PRCM_CLK_MGT_CLKPLLSW_SOC0)
145162306a36Sopenharmony_ci		rate = pll_rate(PRCM_PLLSOC0_FREQ, rate, clk_mgt[clock].branch);
145262306a36Sopenharmony_ci	else if (pllsw == PRCM_CLK_MGT_CLKPLLSW_SOC1)
145362306a36Sopenharmony_ci		rate = pll_rate(PRCM_PLLSOC1_FREQ, rate, clk_mgt[clock].branch);
145462306a36Sopenharmony_ci	else if (pllsw == PRCM_CLK_MGT_CLKPLLSW_DDR)
145562306a36Sopenharmony_ci		rate = pll_rate(PRCM_PLLDDR_FREQ, rate, clk_mgt[clock].branch);
145662306a36Sopenharmony_ci	else
145762306a36Sopenharmony_ci		return 0;
145862306a36Sopenharmony_ci
145962306a36Sopenharmony_ci	if ((clock == PRCMU_SGACLK) &&
146062306a36Sopenharmony_ci		(val & PRCM_SGACLK_MGT_SGACLKDIV_BY_2_5_EN)) {
146162306a36Sopenharmony_ci		u64 r = (rate * 10);
146262306a36Sopenharmony_ci
146362306a36Sopenharmony_ci		(void)do_div(r, 25);
146462306a36Sopenharmony_ci		return (unsigned long)r;
146562306a36Sopenharmony_ci	}
146662306a36Sopenharmony_ci	val &= PRCM_CLK_MGT_CLKPLLDIV_MASK;
146762306a36Sopenharmony_ci	if (val)
146862306a36Sopenharmony_ci		return rate / val;
146962306a36Sopenharmony_ci	else
147062306a36Sopenharmony_ci		return 0;
147162306a36Sopenharmony_ci}
147262306a36Sopenharmony_ci
147362306a36Sopenharmony_cistatic unsigned long armss_rate(void)
147462306a36Sopenharmony_ci{
147562306a36Sopenharmony_ci	u32 r;
147662306a36Sopenharmony_ci	unsigned long rate;
147762306a36Sopenharmony_ci
147862306a36Sopenharmony_ci	r = readl(PRCM_ARM_CHGCLKREQ);
147962306a36Sopenharmony_ci
148062306a36Sopenharmony_ci	if (r & PRCM_ARM_CHGCLKREQ_PRCM_ARM_CHGCLKREQ) {
148162306a36Sopenharmony_ci		/* External ARMCLKFIX clock */
148262306a36Sopenharmony_ci
148362306a36Sopenharmony_ci		rate = pll_rate(PRCM_PLLDDR_FREQ, ROOT_CLOCK_RATE, PLL_FIX);
148462306a36Sopenharmony_ci
148562306a36Sopenharmony_ci		/* Check PRCM_ARM_CHGCLKREQ divider */
148662306a36Sopenharmony_ci		if (!(r & PRCM_ARM_CHGCLKREQ_PRCM_ARM_DIVSEL))
148762306a36Sopenharmony_ci			rate /= 2;
148862306a36Sopenharmony_ci
148962306a36Sopenharmony_ci		/* Check PRCM_ARMCLKFIX_MGT divider */
149062306a36Sopenharmony_ci		r = readl(PRCM_ARMCLKFIX_MGT);
149162306a36Sopenharmony_ci		r &= PRCM_CLK_MGT_CLKPLLDIV_MASK;
149262306a36Sopenharmony_ci		rate /= r;
149362306a36Sopenharmony_ci
149462306a36Sopenharmony_ci	} else {/* ARM PLL */
149562306a36Sopenharmony_ci		rate = pll_rate(PRCM_PLLARM_FREQ, ROOT_CLOCK_RATE, PLL_DIV);
149662306a36Sopenharmony_ci	}
149762306a36Sopenharmony_ci
149862306a36Sopenharmony_ci	return rate;
149962306a36Sopenharmony_ci}
150062306a36Sopenharmony_ci
150162306a36Sopenharmony_cistatic unsigned long dsiclk_rate(u8 n)
150262306a36Sopenharmony_ci{
150362306a36Sopenharmony_ci	u32 divsel;
150462306a36Sopenharmony_ci	u32 div = 1;
150562306a36Sopenharmony_ci
150662306a36Sopenharmony_ci	divsel = readl(PRCM_DSI_PLLOUT_SEL);
150762306a36Sopenharmony_ci	divsel = ((divsel & dsiclk[n].divsel_mask) >> dsiclk[n].divsel_shift);
150862306a36Sopenharmony_ci
150962306a36Sopenharmony_ci	if (divsel == PRCM_DSI_PLLOUT_SEL_OFF)
151062306a36Sopenharmony_ci		divsel = dsiclk[n].divsel;
151162306a36Sopenharmony_ci	else
151262306a36Sopenharmony_ci		dsiclk[n].divsel = divsel;
151362306a36Sopenharmony_ci
151462306a36Sopenharmony_ci	switch (divsel) {
151562306a36Sopenharmony_ci	case PRCM_DSI_PLLOUT_SEL_PHI_4:
151662306a36Sopenharmony_ci		div *= 2;
151762306a36Sopenharmony_ci		fallthrough;
151862306a36Sopenharmony_ci	case PRCM_DSI_PLLOUT_SEL_PHI_2:
151962306a36Sopenharmony_ci		div *= 2;
152062306a36Sopenharmony_ci		fallthrough;
152162306a36Sopenharmony_ci	case PRCM_DSI_PLLOUT_SEL_PHI:
152262306a36Sopenharmony_ci		return pll_rate(PRCM_PLLDSI_FREQ, clock_rate(PRCMU_HDMICLK),
152362306a36Sopenharmony_ci			PLL_RAW) / div;
152462306a36Sopenharmony_ci	default:
152562306a36Sopenharmony_ci		return 0;
152662306a36Sopenharmony_ci	}
152762306a36Sopenharmony_ci}
152862306a36Sopenharmony_ci
152962306a36Sopenharmony_cistatic unsigned long dsiescclk_rate(u8 n)
153062306a36Sopenharmony_ci{
153162306a36Sopenharmony_ci	u32 div;
153262306a36Sopenharmony_ci
153362306a36Sopenharmony_ci	div = readl(PRCM_DSITVCLK_DIV);
153462306a36Sopenharmony_ci	div = ((div & dsiescclk[n].div_mask) >> (dsiescclk[n].div_shift));
153562306a36Sopenharmony_ci	return clock_rate(PRCMU_TVCLK) / max((u32)1, div);
153662306a36Sopenharmony_ci}
153762306a36Sopenharmony_ci
153862306a36Sopenharmony_ciunsigned long prcmu_clock_rate(u8 clock)
153962306a36Sopenharmony_ci{
154062306a36Sopenharmony_ci	if (clock < PRCMU_NUM_REG_CLOCKS)
154162306a36Sopenharmony_ci		return clock_rate(clock);
154262306a36Sopenharmony_ci	else if (clock == PRCMU_TIMCLK)
154362306a36Sopenharmony_ci		return prcmu_is_ulppll_disabled() ?
154462306a36Sopenharmony_ci			32768 : ROOT_CLOCK_RATE / 16;
154562306a36Sopenharmony_ci	else if (clock == PRCMU_SYSCLK)
154662306a36Sopenharmony_ci		return ROOT_CLOCK_RATE;
154762306a36Sopenharmony_ci	else if (clock == PRCMU_PLLSOC0)
154862306a36Sopenharmony_ci		return pll_rate(PRCM_PLLSOC0_FREQ, ROOT_CLOCK_RATE, PLL_RAW);
154962306a36Sopenharmony_ci	else if (clock == PRCMU_PLLSOC1)
155062306a36Sopenharmony_ci		return pll_rate(PRCM_PLLSOC1_FREQ, ROOT_CLOCK_RATE, PLL_RAW);
155162306a36Sopenharmony_ci	else if (clock == PRCMU_ARMSS)
155262306a36Sopenharmony_ci		return armss_rate();
155362306a36Sopenharmony_ci	else if (clock == PRCMU_PLLDDR)
155462306a36Sopenharmony_ci		return pll_rate(PRCM_PLLDDR_FREQ, ROOT_CLOCK_RATE, PLL_RAW);
155562306a36Sopenharmony_ci	else if (clock == PRCMU_PLLDSI)
155662306a36Sopenharmony_ci		return pll_rate(PRCM_PLLDSI_FREQ, clock_rate(PRCMU_HDMICLK),
155762306a36Sopenharmony_ci			PLL_RAW);
155862306a36Sopenharmony_ci	else if ((clock == PRCMU_DSI0CLK) || (clock == PRCMU_DSI1CLK))
155962306a36Sopenharmony_ci		return dsiclk_rate(clock - PRCMU_DSI0CLK);
156062306a36Sopenharmony_ci	else if ((PRCMU_DSI0ESCCLK <= clock) && (clock <= PRCMU_DSI2ESCCLK))
156162306a36Sopenharmony_ci		return dsiescclk_rate(clock - PRCMU_DSI0ESCCLK);
156262306a36Sopenharmony_ci	else
156362306a36Sopenharmony_ci		return 0;
156462306a36Sopenharmony_ci}
156562306a36Sopenharmony_ci
156662306a36Sopenharmony_cistatic unsigned long clock_source_rate(u32 clk_mgt_val, int branch)
156762306a36Sopenharmony_ci{
156862306a36Sopenharmony_ci	if (clk_mgt_val & PRCM_CLK_MGT_CLK38)
156962306a36Sopenharmony_ci		return ROOT_CLOCK_RATE;
157062306a36Sopenharmony_ci	clk_mgt_val &= PRCM_CLK_MGT_CLKPLLSW_MASK;
157162306a36Sopenharmony_ci	if (clk_mgt_val == PRCM_CLK_MGT_CLKPLLSW_SOC0)
157262306a36Sopenharmony_ci		return pll_rate(PRCM_PLLSOC0_FREQ, ROOT_CLOCK_RATE, branch);
157362306a36Sopenharmony_ci	else if (clk_mgt_val == PRCM_CLK_MGT_CLKPLLSW_SOC1)
157462306a36Sopenharmony_ci		return pll_rate(PRCM_PLLSOC1_FREQ, ROOT_CLOCK_RATE, branch);
157562306a36Sopenharmony_ci	else if (clk_mgt_val == PRCM_CLK_MGT_CLKPLLSW_DDR)
157662306a36Sopenharmony_ci		return pll_rate(PRCM_PLLDDR_FREQ, ROOT_CLOCK_RATE, branch);
157762306a36Sopenharmony_ci	else
157862306a36Sopenharmony_ci		return 0;
157962306a36Sopenharmony_ci}
158062306a36Sopenharmony_ci
158162306a36Sopenharmony_cistatic u32 clock_divider(unsigned long src_rate, unsigned long rate)
158262306a36Sopenharmony_ci{
158362306a36Sopenharmony_ci	u32 div;
158462306a36Sopenharmony_ci
158562306a36Sopenharmony_ci	div = (src_rate / rate);
158662306a36Sopenharmony_ci	if (div == 0)
158762306a36Sopenharmony_ci		return 1;
158862306a36Sopenharmony_ci	if (rate < (src_rate / div))
158962306a36Sopenharmony_ci		div++;
159062306a36Sopenharmony_ci	return div;
159162306a36Sopenharmony_ci}
159262306a36Sopenharmony_ci
159362306a36Sopenharmony_cistatic long round_clock_rate(u8 clock, unsigned long rate)
159462306a36Sopenharmony_ci{
159562306a36Sopenharmony_ci	u32 val;
159662306a36Sopenharmony_ci	u32 div;
159762306a36Sopenharmony_ci	unsigned long src_rate;
159862306a36Sopenharmony_ci	long rounded_rate;
159962306a36Sopenharmony_ci
160062306a36Sopenharmony_ci	val = readl(prcmu_base + clk_mgt[clock].offset);
160162306a36Sopenharmony_ci	src_rate = clock_source_rate((val | clk_mgt[clock].pllsw),
160262306a36Sopenharmony_ci		clk_mgt[clock].branch);
160362306a36Sopenharmony_ci	div = clock_divider(src_rate, rate);
160462306a36Sopenharmony_ci	if (val & PRCM_CLK_MGT_CLK38) {
160562306a36Sopenharmony_ci		if (clk_mgt[clock].clk38div) {
160662306a36Sopenharmony_ci			if (div > 2)
160762306a36Sopenharmony_ci				div = 2;
160862306a36Sopenharmony_ci		} else {
160962306a36Sopenharmony_ci			div = 1;
161062306a36Sopenharmony_ci		}
161162306a36Sopenharmony_ci	} else if ((clock == PRCMU_SGACLK) && (div == 3)) {
161262306a36Sopenharmony_ci		u64 r = (src_rate * 10);
161362306a36Sopenharmony_ci
161462306a36Sopenharmony_ci		(void)do_div(r, 25);
161562306a36Sopenharmony_ci		if (r <= rate)
161662306a36Sopenharmony_ci			return (unsigned long)r;
161762306a36Sopenharmony_ci	}
161862306a36Sopenharmony_ci	rounded_rate = (src_rate / min(div, (u32)31));
161962306a36Sopenharmony_ci
162062306a36Sopenharmony_ci	return rounded_rate;
162162306a36Sopenharmony_ci}
162262306a36Sopenharmony_ci
162362306a36Sopenharmony_cistatic const unsigned long db8500_armss_freqs[] = {
162462306a36Sopenharmony_ci	199680000,
162562306a36Sopenharmony_ci	399360000,
162662306a36Sopenharmony_ci	798720000,
162762306a36Sopenharmony_ci	998400000
162862306a36Sopenharmony_ci};
162962306a36Sopenharmony_ci
163062306a36Sopenharmony_ci/* The DB8520 has slightly higher ARMSS max frequency */
163162306a36Sopenharmony_cistatic const unsigned long db8520_armss_freqs[] = {
163262306a36Sopenharmony_ci	199680000,
163362306a36Sopenharmony_ci	399360000,
163462306a36Sopenharmony_ci	798720000,
163562306a36Sopenharmony_ci	1152000000
163662306a36Sopenharmony_ci};
163762306a36Sopenharmony_ci
163862306a36Sopenharmony_cistatic long round_armss_rate(unsigned long rate)
163962306a36Sopenharmony_ci{
164062306a36Sopenharmony_ci	unsigned long freq = 0;
164162306a36Sopenharmony_ci	const unsigned long *freqs;
164262306a36Sopenharmony_ci	int nfreqs;
164362306a36Sopenharmony_ci	int i;
164462306a36Sopenharmony_ci
164562306a36Sopenharmony_ci	if (fw_info.version.project == PRCMU_FW_PROJECT_U8520) {
164662306a36Sopenharmony_ci		freqs = db8520_armss_freqs;
164762306a36Sopenharmony_ci		nfreqs = ARRAY_SIZE(db8520_armss_freqs);
164862306a36Sopenharmony_ci	} else {
164962306a36Sopenharmony_ci		freqs = db8500_armss_freqs;
165062306a36Sopenharmony_ci		nfreqs = ARRAY_SIZE(db8500_armss_freqs);
165162306a36Sopenharmony_ci	}
165262306a36Sopenharmony_ci
165362306a36Sopenharmony_ci	/* Find the corresponding arm opp from the cpufreq table. */
165462306a36Sopenharmony_ci	for (i = 0; i < nfreqs; i++) {
165562306a36Sopenharmony_ci		freq = freqs[i];
165662306a36Sopenharmony_ci		if (rate <= freq)
165762306a36Sopenharmony_ci			break;
165862306a36Sopenharmony_ci	}
165962306a36Sopenharmony_ci
166062306a36Sopenharmony_ci	/* Return the last valid value, even if a match was not found. */
166162306a36Sopenharmony_ci	return freq;
166262306a36Sopenharmony_ci}
166362306a36Sopenharmony_ci
166462306a36Sopenharmony_ci#define MIN_PLL_VCO_RATE 600000000ULL
166562306a36Sopenharmony_ci#define MAX_PLL_VCO_RATE 1680640000ULL
166662306a36Sopenharmony_ci
166762306a36Sopenharmony_cistatic long round_plldsi_rate(unsigned long rate)
166862306a36Sopenharmony_ci{
166962306a36Sopenharmony_ci	long rounded_rate = 0;
167062306a36Sopenharmony_ci	unsigned long src_rate;
167162306a36Sopenharmony_ci	unsigned long rem;
167262306a36Sopenharmony_ci	u32 r;
167362306a36Sopenharmony_ci
167462306a36Sopenharmony_ci	src_rate = clock_rate(PRCMU_HDMICLK);
167562306a36Sopenharmony_ci	rem = rate;
167662306a36Sopenharmony_ci
167762306a36Sopenharmony_ci	for (r = 7; (rem > 0) && (r > 0); r--) {
167862306a36Sopenharmony_ci		u64 d;
167962306a36Sopenharmony_ci
168062306a36Sopenharmony_ci		d = (r * rate);
168162306a36Sopenharmony_ci		(void)do_div(d, src_rate);
168262306a36Sopenharmony_ci		if (d < 6)
168362306a36Sopenharmony_ci			d = 6;
168462306a36Sopenharmony_ci		else if (d > 255)
168562306a36Sopenharmony_ci			d = 255;
168662306a36Sopenharmony_ci		d *= src_rate;
168762306a36Sopenharmony_ci		if (((2 * d) < (r * MIN_PLL_VCO_RATE)) ||
168862306a36Sopenharmony_ci			((r * MAX_PLL_VCO_RATE) < (2 * d)))
168962306a36Sopenharmony_ci			continue;
169062306a36Sopenharmony_ci		(void)do_div(d, r);
169162306a36Sopenharmony_ci		if (rate < d) {
169262306a36Sopenharmony_ci			if (rounded_rate == 0)
169362306a36Sopenharmony_ci				rounded_rate = (long)d;
169462306a36Sopenharmony_ci			break;
169562306a36Sopenharmony_ci		}
169662306a36Sopenharmony_ci		if ((rate - d) < rem) {
169762306a36Sopenharmony_ci			rem = (rate - d);
169862306a36Sopenharmony_ci			rounded_rate = (long)d;
169962306a36Sopenharmony_ci		}
170062306a36Sopenharmony_ci	}
170162306a36Sopenharmony_ci	return rounded_rate;
170262306a36Sopenharmony_ci}
170362306a36Sopenharmony_ci
170462306a36Sopenharmony_cistatic long round_dsiclk_rate(unsigned long rate)
170562306a36Sopenharmony_ci{
170662306a36Sopenharmony_ci	u32 div;
170762306a36Sopenharmony_ci	unsigned long src_rate;
170862306a36Sopenharmony_ci	long rounded_rate;
170962306a36Sopenharmony_ci
171062306a36Sopenharmony_ci	src_rate = pll_rate(PRCM_PLLDSI_FREQ, clock_rate(PRCMU_HDMICLK),
171162306a36Sopenharmony_ci		PLL_RAW);
171262306a36Sopenharmony_ci	div = clock_divider(src_rate, rate);
171362306a36Sopenharmony_ci	rounded_rate = (src_rate / ((div > 2) ? 4 : div));
171462306a36Sopenharmony_ci
171562306a36Sopenharmony_ci	return rounded_rate;
171662306a36Sopenharmony_ci}
171762306a36Sopenharmony_ci
171862306a36Sopenharmony_cistatic long round_dsiescclk_rate(unsigned long rate)
171962306a36Sopenharmony_ci{
172062306a36Sopenharmony_ci	u32 div;
172162306a36Sopenharmony_ci	unsigned long src_rate;
172262306a36Sopenharmony_ci	long rounded_rate;
172362306a36Sopenharmony_ci
172462306a36Sopenharmony_ci	src_rate = clock_rate(PRCMU_TVCLK);
172562306a36Sopenharmony_ci	div = clock_divider(src_rate, rate);
172662306a36Sopenharmony_ci	rounded_rate = (src_rate / min(div, (u32)255));
172762306a36Sopenharmony_ci
172862306a36Sopenharmony_ci	return rounded_rate;
172962306a36Sopenharmony_ci}
173062306a36Sopenharmony_ci
173162306a36Sopenharmony_cilong prcmu_round_clock_rate(u8 clock, unsigned long rate)
173262306a36Sopenharmony_ci{
173362306a36Sopenharmony_ci	if (clock < PRCMU_NUM_REG_CLOCKS)
173462306a36Sopenharmony_ci		return round_clock_rate(clock, rate);
173562306a36Sopenharmony_ci	else if (clock == PRCMU_ARMSS)
173662306a36Sopenharmony_ci		return round_armss_rate(rate);
173762306a36Sopenharmony_ci	else if (clock == PRCMU_PLLDSI)
173862306a36Sopenharmony_ci		return round_plldsi_rate(rate);
173962306a36Sopenharmony_ci	else if ((clock == PRCMU_DSI0CLK) || (clock == PRCMU_DSI1CLK))
174062306a36Sopenharmony_ci		return round_dsiclk_rate(rate);
174162306a36Sopenharmony_ci	else if ((PRCMU_DSI0ESCCLK <= clock) && (clock <= PRCMU_DSI2ESCCLK))
174262306a36Sopenharmony_ci		return round_dsiescclk_rate(rate);
174362306a36Sopenharmony_ci	else
174462306a36Sopenharmony_ci		return (long)prcmu_clock_rate(clock);
174562306a36Sopenharmony_ci}
174662306a36Sopenharmony_ci
174762306a36Sopenharmony_cistatic void set_clock_rate(u8 clock, unsigned long rate)
174862306a36Sopenharmony_ci{
174962306a36Sopenharmony_ci	u32 val;
175062306a36Sopenharmony_ci	u32 div;
175162306a36Sopenharmony_ci	unsigned long src_rate;
175262306a36Sopenharmony_ci	unsigned long flags;
175362306a36Sopenharmony_ci
175462306a36Sopenharmony_ci	spin_lock_irqsave(&clk_mgt_lock, flags);
175562306a36Sopenharmony_ci
175662306a36Sopenharmony_ci	/* Grab the HW semaphore. */
175762306a36Sopenharmony_ci	while ((readl(PRCM_SEM) & PRCM_SEM_PRCM_SEM) != 0)
175862306a36Sopenharmony_ci		cpu_relax();
175962306a36Sopenharmony_ci
176062306a36Sopenharmony_ci	val = readl(prcmu_base + clk_mgt[clock].offset);
176162306a36Sopenharmony_ci	src_rate = clock_source_rate((val | clk_mgt[clock].pllsw),
176262306a36Sopenharmony_ci		clk_mgt[clock].branch);
176362306a36Sopenharmony_ci	div = clock_divider(src_rate, rate);
176462306a36Sopenharmony_ci	if (val & PRCM_CLK_MGT_CLK38) {
176562306a36Sopenharmony_ci		if (clk_mgt[clock].clk38div) {
176662306a36Sopenharmony_ci			if (div > 1)
176762306a36Sopenharmony_ci				val |= PRCM_CLK_MGT_CLK38DIV;
176862306a36Sopenharmony_ci			else
176962306a36Sopenharmony_ci				val &= ~PRCM_CLK_MGT_CLK38DIV;
177062306a36Sopenharmony_ci		}
177162306a36Sopenharmony_ci	} else if (clock == PRCMU_SGACLK) {
177262306a36Sopenharmony_ci		val &= ~(PRCM_CLK_MGT_CLKPLLDIV_MASK |
177362306a36Sopenharmony_ci			PRCM_SGACLK_MGT_SGACLKDIV_BY_2_5_EN);
177462306a36Sopenharmony_ci		if (div == 3) {
177562306a36Sopenharmony_ci			u64 r = (src_rate * 10);
177662306a36Sopenharmony_ci
177762306a36Sopenharmony_ci			(void)do_div(r, 25);
177862306a36Sopenharmony_ci			if (r <= rate) {
177962306a36Sopenharmony_ci				val |= PRCM_SGACLK_MGT_SGACLKDIV_BY_2_5_EN;
178062306a36Sopenharmony_ci				div = 0;
178162306a36Sopenharmony_ci			}
178262306a36Sopenharmony_ci		}
178362306a36Sopenharmony_ci		val |= min(div, (u32)31);
178462306a36Sopenharmony_ci	} else {
178562306a36Sopenharmony_ci		val &= ~PRCM_CLK_MGT_CLKPLLDIV_MASK;
178662306a36Sopenharmony_ci		val |= min(div, (u32)31);
178762306a36Sopenharmony_ci	}
178862306a36Sopenharmony_ci	writel(val, prcmu_base + clk_mgt[clock].offset);
178962306a36Sopenharmony_ci
179062306a36Sopenharmony_ci	/* Release the HW semaphore. */
179162306a36Sopenharmony_ci	writel(0, PRCM_SEM);
179262306a36Sopenharmony_ci
179362306a36Sopenharmony_ci	spin_unlock_irqrestore(&clk_mgt_lock, flags);
179462306a36Sopenharmony_ci}
179562306a36Sopenharmony_ci
179662306a36Sopenharmony_cistatic int set_armss_rate(unsigned long rate)
179762306a36Sopenharmony_ci{
179862306a36Sopenharmony_ci	unsigned long freq;
179962306a36Sopenharmony_ci	u8 opps[] = { ARM_EXTCLK, ARM_50_OPP, ARM_100_OPP, ARM_MAX_OPP };
180062306a36Sopenharmony_ci	const unsigned long *freqs;
180162306a36Sopenharmony_ci	int nfreqs;
180262306a36Sopenharmony_ci	int i;
180362306a36Sopenharmony_ci
180462306a36Sopenharmony_ci	if (fw_info.version.project == PRCMU_FW_PROJECT_U8520) {
180562306a36Sopenharmony_ci		freqs = db8520_armss_freqs;
180662306a36Sopenharmony_ci		nfreqs = ARRAY_SIZE(db8520_armss_freqs);
180762306a36Sopenharmony_ci	} else {
180862306a36Sopenharmony_ci		freqs = db8500_armss_freqs;
180962306a36Sopenharmony_ci		nfreqs = ARRAY_SIZE(db8500_armss_freqs);
181062306a36Sopenharmony_ci	}
181162306a36Sopenharmony_ci
181262306a36Sopenharmony_ci	/* Find the corresponding arm opp from the cpufreq table. */
181362306a36Sopenharmony_ci	for (i = 0; i < nfreqs; i++) {
181462306a36Sopenharmony_ci		freq = freqs[i];
181562306a36Sopenharmony_ci		if (rate == freq)
181662306a36Sopenharmony_ci			break;
181762306a36Sopenharmony_ci	}
181862306a36Sopenharmony_ci
181962306a36Sopenharmony_ci	if (rate != freq)
182062306a36Sopenharmony_ci		return -EINVAL;
182162306a36Sopenharmony_ci
182262306a36Sopenharmony_ci	/* Set the new arm opp. */
182362306a36Sopenharmony_ci	pr_debug("SET ARM OPP 0x%02x\n", opps[i]);
182462306a36Sopenharmony_ci	return db8500_prcmu_set_arm_opp(opps[i]);
182562306a36Sopenharmony_ci}
182662306a36Sopenharmony_ci
182762306a36Sopenharmony_cistatic int set_plldsi_rate(unsigned long rate)
182862306a36Sopenharmony_ci{
182962306a36Sopenharmony_ci	unsigned long src_rate;
183062306a36Sopenharmony_ci	unsigned long rem;
183162306a36Sopenharmony_ci	u32 pll_freq = 0;
183262306a36Sopenharmony_ci	u32 r;
183362306a36Sopenharmony_ci
183462306a36Sopenharmony_ci	src_rate = clock_rate(PRCMU_HDMICLK);
183562306a36Sopenharmony_ci	rem = rate;
183662306a36Sopenharmony_ci
183762306a36Sopenharmony_ci	for (r = 7; (rem > 0) && (r > 0); r--) {
183862306a36Sopenharmony_ci		u64 d;
183962306a36Sopenharmony_ci		u64 hwrate;
184062306a36Sopenharmony_ci
184162306a36Sopenharmony_ci		d = (r * rate);
184262306a36Sopenharmony_ci		(void)do_div(d, src_rate);
184362306a36Sopenharmony_ci		if (d < 6)
184462306a36Sopenharmony_ci			d = 6;
184562306a36Sopenharmony_ci		else if (d > 255)
184662306a36Sopenharmony_ci			d = 255;
184762306a36Sopenharmony_ci		hwrate = (d * src_rate);
184862306a36Sopenharmony_ci		if (((2 * hwrate) < (r * MIN_PLL_VCO_RATE)) ||
184962306a36Sopenharmony_ci			((r * MAX_PLL_VCO_RATE) < (2 * hwrate)))
185062306a36Sopenharmony_ci			continue;
185162306a36Sopenharmony_ci		(void)do_div(hwrate, r);
185262306a36Sopenharmony_ci		if (rate < hwrate) {
185362306a36Sopenharmony_ci			if (pll_freq == 0)
185462306a36Sopenharmony_ci				pll_freq = (((u32)d << PRCM_PLL_FREQ_D_SHIFT) |
185562306a36Sopenharmony_ci					(r << PRCM_PLL_FREQ_R_SHIFT));
185662306a36Sopenharmony_ci			break;
185762306a36Sopenharmony_ci		}
185862306a36Sopenharmony_ci		if ((rate - hwrate) < rem) {
185962306a36Sopenharmony_ci			rem = (rate - hwrate);
186062306a36Sopenharmony_ci			pll_freq = (((u32)d << PRCM_PLL_FREQ_D_SHIFT) |
186162306a36Sopenharmony_ci				(r << PRCM_PLL_FREQ_R_SHIFT));
186262306a36Sopenharmony_ci		}
186362306a36Sopenharmony_ci	}
186462306a36Sopenharmony_ci	if (pll_freq == 0)
186562306a36Sopenharmony_ci		return -EINVAL;
186662306a36Sopenharmony_ci
186762306a36Sopenharmony_ci	pll_freq |= (1 << PRCM_PLL_FREQ_N_SHIFT);
186862306a36Sopenharmony_ci	writel(pll_freq, PRCM_PLLDSI_FREQ);
186962306a36Sopenharmony_ci
187062306a36Sopenharmony_ci	return 0;
187162306a36Sopenharmony_ci}
187262306a36Sopenharmony_ci
187362306a36Sopenharmony_cistatic void set_dsiclk_rate(u8 n, unsigned long rate)
187462306a36Sopenharmony_ci{
187562306a36Sopenharmony_ci	u32 val;
187662306a36Sopenharmony_ci	u32 div;
187762306a36Sopenharmony_ci
187862306a36Sopenharmony_ci	div = clock_divider(pll_rate(PRCM_PLLDSI_FREQ,
187962306a36Sopenharmony_ci			clock_rate(PRCMU_HDMICLK), PLL_RAW), rate);
188062306a36Sopenharmony_ci
188162306a36Sopenharmony_ci	dsiclk[n].divsel = (div == 1) ? PRCM_DSI_PLLOUT_SEL_PHI :
188262306a36Sopenharmony_ci			   (div == 2) ? PRCM_DSI_PLLOUT_SEL_PHI_2 :
188362306a36Sopenharmony_ci			   /* else */	PRCM_DSI_PLLOUT_SEL_PHI_4;
188462306a36Sopenharmony_ci
188562306a36Sopenharmony_ci	val = readl(PRCM_DSI_PLLOUT_SEL);
188662306a36Sopenharmony_ci	val &= ~dsiclk[n].divsel_mask;
188762306a36Sopenharmony_ci	val |= (dsiclk[n].divsel << dsiclk[n].divsel_shift);
188862306a36Sopenharmony_ci	writel(val, PRCM_DSI_PLLOUT_SEL);
188962306a36Sopenharmony_ci}
189062306a36Sopenharmony_ci
189162306a36Sopenharmony_cistatic void set_dsiescclk_rate(u8 n, unsigned long rate)
189262306a36Sopenharmony_ci{
189362306a36Sopenharmony_ci	u32 val;
189462306a36Sopenharmony_ci	u32 div;
189562306a36Sopenharmony_ci
189662306a36Sopenharmony_ci	div = clock_divider(clock_rate(PRCMU_TVCLK), rate);
189762306a36Sopenharmony_ci	val = readl(PRCM_DSITVCLK_DIV);
189862306a36Sopenharmony_ci	val &= ~dsiescclk[n].div_mask;
189962306a36Sopenharmony_ci	val |= (min(div, (u32)255) << dsiescclk[n].div_shift);
190062306a36Sopenharmony_ci	writel(val, PRCM_DSITVCLK_DIV);
190162306a36Sopenharmony_ci}
190262306a36Sopenharmony_ci
190362306a36Sopenharmony_ciint prcmu_set_clock_rate(u8 clock, unsigned long rate)
190462306a36Sopenharmony_ci{
190562306a36Sopenharmony_ci	if (clock < PRCMU_NUM_REG_CLOCKS)
190662306a36Sopenharmony_ci		set_clock_rate(clock, rate);
190762306a36Sopenharmony_ci	else if (clock == PRCMU_ARMSS)
190862306a36Sopenharmony_ci		return set_armss_rate(rate);
190962306a36Sopenharmony_ci	else if (clock == PRCMU_PLLDSI)
191062306a36Sopenharmony_ci		return set_plldsi_rate(rate);
191162306a36Sopenharmony_ci	else if ((clock == PRCMU_DSI0CLK) || (clock == PRCMU_DSI1CLK))
191262306a36Sopenharmony_ci		set_dsiclk_rate((clock - PRCMU_DSI0CLK), rate);
191362306a36Sopenharmony_ci	else if ((PRCMU_DSI0ESCCLK <= clock) && (clock <= PRCMU_DSI2ESCCLK))
191462306a36Sopenharmony_ci		set_dsiescclk_rate((clock - PRCMU_DSI0ESCCLK), rate);
191562306a36Sopenharmony_ci	return 0;
191662306a36Sopenharmony_ci}
191762306a36Sopenharmony_ci
191862306a36Sopenharmony_ciint db8500_prcmu_config_esram0_deep_sleep(u8 state)
191962306a36Sopenharmony_ci{
192062306a36Sopenharmony_ci	if ((state > ESRAM0_DEEP_SLEEP_STATE_RET) ||
192162306a36Sopenharmony_ci	    (state < ESRAM0_DEEP_SLEEP_STATE_OFF))
192262306a36Sopenharmony_ci		return -EINVAL;
192362306a36Sopenharmony_ci
192462306a36Sopenharmony_ci	mutex_lock(&mb4_transfer.lock);
192562306a36Sopenharmony_ci
192662306a36Sopenharmony_ci	while (readl(PRCM_MBOX_CPU_VAL) & MBOX_BIT(4))
192762306a36Sopenharmony_ci		cpu_relax();
192862306a36Sopenharmony_ci
192962306a36Sopenharmony_ci	writeb(MB4H_MEM_ST, (tcdm_base + PRCM_MBOX_HEADER_REQ_MB4));
193062306a36Sopenharmony_ci	writeb(((DDR_PWR_STATE_OFFHIGHLAT << 4) | DDR_PWR_STATE_ON),
193162306a36Sopenharmony_ci	       (tcdm_base + PRCM_REQ_MB4_DDR_ST_AP_SLEEP_IDLE));
193262306a36Sopenharmony_ci	writeb(DDR_PWR_STATE_ON,
193362306a36Sopenharmony_ci	       (tcdm_base + PRCM_REQ_MB4_DDR_ST_AP_DEEP_IDLE));
193462306a36Sopenharmony_ci	writeb(state, (tcdm_base + PRCM_REQ_MB4_ESRAM0_ST));
193562306a36Sopenharmony_ci
193662306a36Sopenharmony_ci	writel(MBOX_BIT(4), PRCM_MBOX_CPU_SET);
193762306a36Sopenharmony_ci	wait_for_completion(&mb4_transfer.work);
193862306a36Sopenharmony_ci
193962306a36Sopenharmony_ci	mutex_unlock(&mb4_transfer.lock);
194062306a36Sopenharmony_ci
194162306a36Sopenharmony_ci	return 0;
194262306a36Sopenharmony_ci}
194362306a36Sopenharmony_ci
194462306a36Sopenharmony_ciint db8500_prcmu_config_hotdog(u8 threshold)
194562306a36Sopenharmony_ci{
194662306a36Sopenharmony_ci	mutex_lock(&mb4_transfer.lock);
194762306a36Sopenharmony_ci
194862306a36Sopenharmony_ci	while (readl(PRCM_MBOX_CPU_VAL) & MBOX_BIT(4))
194962306a36Sopenharmony_ci		cpu_relax();
195062306a36Sopenharmony_ci
195162306a36Sopenharmony_ci	writeb(threshold, (tcdm_base + PRCM_REQ_MB4_HOTDOG_THRESHOLD));
195262306a36Sopenharmony_ci	writeb(MB4H_HOTDOG, (tcdm_base + PRCM_MBOX_HEADER_REQ_MB4));
195362306a36Sopenharmony_ci
195462306a36Sopenharmony_ci	writel(MBOX_BIT(4), PRCM_MBOX_CPU_SET);
195562306a36Sopenharmony_ci	wait_for_completion(&mb4_transfer.work);
195662306a36Sopenharmony_ci
195762306a36Sopenharmony_ci	mutex_unlock(&mb4_transfer.lock);
195862306a36Sopenharmony_ci
195962306a36Sopenharmony_ci	return 0;
196062306a36Sopenharmony_ci}
196162306a36Sopenharmony_ci
196262306a36Sopenharmony_ciint db8500_prcmu_config_hotmon(u8 low, u8 high)
196362306a36Sopenharmony_ci{
196462306a36Sopenharmony_ci	mutex_lock(&mb4_transfer.lock);
196562306a36Sopenharmony_ci
196662306a36Sopenharmony_ci	while (readl(PRCM_MBOX_CPU_VAL) & MBOX_BIT(4))
196762306a36Sopenharmony_ci		cpu_relax();
196862306a36Sopenharmony_ci
196962306a36Sopenharmony_ci	writeb(low, (tcdm_base + PRCM_REQ_MB4_HOTMON_LOW));
197062306a36Sopenharmony_ci	writeb(high, (tcdm_base + PRCM_REQ_MB4_HOTMON_HIGH));
197162306a36Sopenharmony_ci	writeb((HOTMON_CONFIG_LOW | HOTMON_CONFIG_HIGH),
197262306a36Sopenharmony_ci		(tcdm_base + PRCM_REQ_MB4_HOTMON_CONFIG));
197362306a36Sopenharmony_ci	writeb(MB4H_HOTMON, (tcdm_base + PRCM_MBOX_HEADER_REQ_MB4));
197462306a36Sopenharmony_ci
197562306a36Sopenharmony_ci	writel(MBOX_BIT(4), PRCM_MBOX_CPU_SET);
197662306a36Sopenharmony_ci	wait_for_completion(&mb4_transfer.work);
197762306a36Sopenharmony_ci
197862306a36Sopenharmony_ci	mutex_unlock(&mb4_transfer.lock);
197962306a36Sopenharmony_ci
198062306a36Sopenharmony_ci	return 0;
198162306a36Sopenharmony_ci}
198262306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(db8500_prcmu_config_hotmon);
198362306a36Sopenharmony_ci
198462306a36Sopenharmony_cistatic int config_hot_period(u16 val)
198562306a36Sopenharmony_ci{
198662306a36Sopenharmony_ci	mutex_lock(&mb4_transfer.lock);
198762306a36Sopenharmony_ci
198862306a36Sopenharmony_ci	while (readl(PRCM_MBOX_CPU_VAL) & MBOX_BIT(4))
198962306a36Sopenharmony_ci		cpu_relax();
199062306a36Sopenharmony_ci
199162306a36Sopenharmony_ci	writew(val, (tcdm_base + PRCM_REQ_MB4_HOT_PERIOD));
199262306a36Sopenharmony_ci	writeb(MB4H_HOT_PERIOD, (tcdm_base + PRCM_MBOX_HEADER_REQ_MB4));
199362306a36Sopenharmony_ci
199462306a36Sopenharmony_ci	writel(MBOX_BIT(4), PRCM_MBOX_CPU_SET);
199562306a36Sopenharmony_ci	wait_for_completion(&mb4_transfer.work);
199662306a36Sopenharmony_ci
199762306a36Sopenharmony_ci	mutex_unlock(&mb4_transfer.lock);
199862306a36Sopenharmony_ci
199962306a36Sopenharmony_ci	return 0;
200062306a36Sopenharmony_ci}
200162306a36Sopenharmony_ci
200262306a36Sopenharmony_ciint db8500_prcmu_start_temp_sense(u16 cycles32k)
200362306a36Sopenharmony_ci{
200462306a36Sopenharmony_ci	if (cycles32k == 0xFFFF)
200562306a36Sopenharmony_ci		return -EINVAL;
200662306a36Sopenharmony_ci
200762306a36Sopenharmony_ci	return config_hot_period(cycles32k);
200862306a36Sopenharmony_ci}
200962306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(db8500_prcmu_start_temp_sense);
201062306a36Sopenharmony_ci
201162306a36Sopenharmony_ciint db8500_prcmu_stop_temp_sense(void)
201262306a36Sopenharmony_ci{
201362306a36Sopenharmony_ci	return config_hot_period(0xFFFF);
201462306a36Sopenharmony_ci}
201562306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(db8500_prcmu_stop_temp_sense);
201662306a36Sopenharmony_ci
201762306a36Sopenharmony_cistatic int prcmu_a9wdog(u8 cmd, u8 d0, u8 d1, u8 d2, u8 d3)
201862306a36Sopenharmony_ci{
201962306a36Sopenharmony_ci
202062306a36Sopenharmony_ci	mutex_lock(&mb4_transfer.lock);
202162306a36Sopenharmony_ci
202262306a36Sopenharmony_ci	while (readl(PRCM_MBOX_CPU_VAL) & MBOX_BIT(4))
202362306a36Sopenharmony_ci		cpu_relax();
202462306a36Sopenharmony_ci
202562306a36Sopenharmony_ci	writeb(d0, (tcdm_base + PRCM_REQ_MB4_A9WDOG_0));
202662306a36Sopenharmony_ci	writeb(d1, (tcdm_base + PRCM_REQ_MB4_A9WDOG_1));
202762306a36Sopenharmony_ci	writeb(d2, (tcdm_base + PRCM_REQ_MB4_A9WDOG_2));
202862306a36Sopenharmony_ci	writeb(d3, (tcdm_base + PRCM_REQ_MB4_A9WDOG_3));
202962306a36Sopenharmony_ci
203062306a36Sopenharmony_ci	writeb(cmd, (tcdm_base + PRCM_MBOX_HEADER_REQ_MB4));
203162306a36Sopenharmony_ci
203262306a36Sopenharmony_ci	writel(MBOX_BIT(4), PRCM_MBOX_CPU_SET);
203362306a36Sopenharmony_ci	wait_for_completion(&mb4_transfer.work);
203462306a36Sopenharmony_ci
203562306a36Sopenharmony_ci	mutex_unlock(&mb4_transfer.lock);
203662306a36Sopenharmony_ci
203762306a36Sopenharmony_ci	return 0;
203862306a36Sopenharmony_ci
203962306a36Sopenharmony_ci}
204062306a36Sopenharmony_ci
204162306a36Sopenharmony_ciint db8500_prcmu_config_a9wdog(u8 num, bool sleep_auto_off)
204262306a36Sopenharmony_ci{
204362306a36Sopenharmony_ci	BUG_ON(num == 0 || num > 0xf);
204462306a36Sopenharmony_ci	return prcmu_a9wdog(MB4H_A9WDOG_CONF, num, 0, 0,
204562306a36Sopenharmony_ci			    sleep_auto_off ? A9WDOG_AUTO_OFF_EN :
204662306a36Sopenharmony_ci			    A9WDOG_AUTO_OFF_DIS);
204762306a36Sopenharmony_ci}
204862306a36Sopenharmony_ciEXPORT_SYMBOL(db8500_prcmu_config_a9wdog);
204962306a36Sopenharmony_ci
205062306a36Sopenharmony_ciint db8500_prcmu_enable_a9wdog(u8 id)
205162306a36Sopenharmony_ci{
205262306a36Sopenharmony_ci	return prcmu_a9wdog(MB4H_A9WDOG_EN, id, 0, 0, 0);
205362306a36Sopenharmony_ci}
205462306a36Sopenharmony_ciEXPORT_SYMBOL(db8500_prcmu_enable_a9wdog);
205562306a36Sopenharmony_ci
205662306a36Sopenharmony_ciint db8500_prcmu_disable_a9wdog(u8 id)
205762306a36Sopenharmony_ci{
205862306a36Sopenharmony_ci	return prcmu_a9wdog(MB4H_A9WDOG_DIS, id, 0, 0, 0);
205962306a36Sopenharmony_ci}
206062306a36Sopenharmony_ciEXPORT_SYMBOL(db8500_prcmu_disable_a9wdog);
206162306a36Sopenharmony_ci
206262306a36Sopenharmony_ciint db8500_prcmu_kick_a9wdog(u8 id)
206362306a36Sopenharmony_ci{
206462306a36Sopenharmony_ci	return prcmu_a9wdog(MB4H_A9WDOG_KICK, id, 0, 0, 0);
206562306a36Sopenharmony_ci}
206662306a36Sopenharmony_ciEXPORT_SYMBOL(db8500_prcmu_kick_a9wdog);
206762306a36Sopenharmony_ci
206862306a36Sopenharmony_ci/*
206962306a36Sopenharmony_ci * timeout is 28 bit, in ms.
207062306a36Sopenharmony_ci */
207162306a36Sopenharmony_ciint db8500_prcmu_load_a9wdog(u8 id, u32 timeout)
207262306a36Sopenharmony_ci{
207362306a36Sopenharmony_ci	return prcmu_a9wdog(MB4H_A9WDOG_LOAD,
207462306a36Sopenharmony_ci			    (id & A9WDOG_ID_MASK) |
207562306a36Sopenharmony_ci			    /*
207662306a36Sopenharmony_ci			     * Put the lowest 28 bits of timeout at
207762306a36Sopenharmony_ci			     * offset 4. Four first bits are used for id.
207862306a36Sopenharmony_ci			     */
207962306a36Sopenharmony_ci			    (u8)((timeout << 4) & 0xf0),
208062306a36Sopenharmony_ci			    (u8)((timeout >> 4) & 0xff),
208162306a36Sopenharmony_ci			    (u8)((timeout >> 12) & 0xff),
208262306a36Sopenharmony_ci			    (u8)((timeout >> 20) & 0xff));
208362306a36Sopenharmony_ci}
208462306a36Sopenharmony_ciEXPORT_SYMBOL(db8500_prcmu_load_a9wdog);
208562306a36Sopenharmony_ci
208662306a36Sopenharmony_ci/**
208762306a36Sopenharmony_ci * prcmu_abb_read() - Read register value(s) from the ABB.
208862306a36Sopenharmony_ci * @slave:	The I2C slave address.
208962306a36Sopenharmony_ci * @reg:	The (start) register address.
209062306a36Sopenharmony_ci * @value:	The read out value(s).
209162306a36Sopenharmony_ci * @size:	The number of registers to read.
209262306a36Sopenharmony_ci *
209362306a36Sopenharmony_ci * Reads register value(s) from the ABB.
209462306a36Sopenharmony_ci * @size has to be 1 for the current firmware version.
209562306a36Sopenharmony_ci */
209662306a36Sopenharmony_ciint prcmu_abb_read(u8 slave, u8 reg, u8 *value, u8 size)
209762306a36Sopenharmony_ci{
209862306a36Sopenharmony_ci	int r;
209962306a36Sopenharmony_ci
210062306a36Sopenharmony_ci	if (size != 1)
210162306a36Sopenharmony_ci		return -EINVAL;
210262306a36Sopenharmony_ci
210362306a36Sopenharmony_ci	mutex_lock(&mb5_transfer.lock);
210462306a36Sopenharmony_ci
210562306a36Sopenharmony_ci	while (readl(PRCM_MBOX_CPU_VAL) & MBOX_BIT(5))
210662306a36Sopenharmony_ci		cpu_relax();
210762306a36Sopenharmony_ci
210862306a36Sopenharmony_ci	writeb(0, (tcdm_base + PRCM_MBOX_HEADER_REQ_MB5));
210962306a36Sopenharmony_ci	writeb(PRCMU_I2C_READ(slave), (tcdm_base + PRCM_REQ_MB5_I2C_SLAVE_OP));
211062306a36Sopenharmony_ci	writeb(PRCMU_I2C_STOP_EN, (tcdm_base + PRCM_REQ_MB5_I2C_HW_BITS));
211162306a36Sopenharmony_ci	writeb(reg, (tcdm_base + PRCM_REQ_MB5_I2C_REG));
211262306a36Sopenharmony_ci	writeb(0, (tcdm_base + PRCM_REQ_MB5_I2C_VAL));
211362306a36Sopenharmony_ci
211462306a36Sopenharmony_ci	writel(MBOX_BIT(5), PRCM_MBOX_CPU_SET);
211562306a36Sopenharmony_ci
211662306a36Sopenharmony_ci	if (!wait_for_completion_timeout(&mb5_transfer.work,
211762306a36Sopenharmony_ci				msecs_to_jiffies(20000))) {
211862306a36Sopenharmony_ci		pr_err("prcmu: %s timed out (20 s) waiting for a reply.\n",
211962306a36Sopenharmony_ci			__func__);
212062306a36Sopenharmony_ci		r = -EIO;
212162306a36Sopenharmony_ci	} else {
212262306a36Sopenharmony_ci		r = ((mb5_transfer.ack.status == I2C_RD_OK) ? 0 : -EIO);
212362306a36Sopenharmony_ci	}
212462306a36Sopenharmony_ci
212562306a36Sopenharmony_ci	if (!r)
212662306a36Sopenharmony_ci		*value = mb5_transfer.ack.value;
212762306a36Sopenharmony_ci
212862306a36Sopenharmony_ci	mutex_unlock(&mb5_transfer.lock);
212962306a36Sopenharmony_ci
213062306a36Sopenharmony_ci	return r;
213162306a36Sopenharmony_ci}
213262306a36Sopenharmony_ci
213362306a36Sopenharmony_ci/**
213462306a36Sopenharmony_ci * prcmu_abb_write_masked() - Write masked register value(s) to the ABB.
213562306a36Sopenharmony_ci * @slave:	The I2C slave address.
213662306a36Sopenharmony_ci * @reg:	The (start) register address.
213762306a36Sopenharmony_ci * @value:	The value(s) to write.
213862306a36Sopenharmony_ci * @mask:	The mask(s) to use.
213962306a36Sopenharmony_ci * @size:	The number of registers to write.
214062306a36Sopenharmony_ci *
214162306a36Sopenharmony_ci * Writes masked register value(s) to the ABB.
214262306a36Sopenharmony_ci * For each @value, only the bits set to 1 in the corresponding @mask
214362306a36Sopenharmony_ci * will be written. The other bits are not changed.
214462306a36Sopenharmony_ci * @size has to be 1 for the current firmware version.
214562306a36Sopenharmony_ci */
214662306a36Sopenharmony_ciint prcmu_abb_write_masked(u8 slave, u8 reg, u8 *value, u8 *mask, u8 size)
214762306a36Sopenharmony_ci{
214862306a36Sopenharmony_ci	int r;
214962306a36Sopenharmony_ci
215062306a36Sopenharmony_ci	if (size != 1)
215162306a36Sopenharmony_ci		return -EINVAL;
215262306a36Sopenharmony_ci
215362306a36Sopenharmony_ci	mutex_lock(&mb5_transfer.lock);
215462306a36Sopenharmony_ci
215562306a36Sopenharmony_ci	while (readl(PRCM_MBOX_CPU_VAL) & MBOX_BIT(5))
215662306a36Sopenharmony_ci		cpu_relax();
215762306a36Sopenharmony_ci
215862306a36Sopenharmony_ci	writeb(~*mask, (tcdm_base + PRCM_MBOX_HEADER_REQ_MB5));
215962306a36Sopenharmony_ci	writeb(PRCMU_I2C_WRITE(slave), (tcdm_base + PRCM_REQ_MB5_I2C_SLAVE_OP));
216062306a36Sopenharmony_ci	writeb(PRCMU_I2C_STOP_EN, (tcdm_base + PRCM_REQ_MB5_I2C_HW_BITS));
216162306a36Sopenharmony_ci	writeb(reg, (tcdm_base + PRCM_REQ_MB5_I2C_REG));
216262306a36Sopenharmony_ci	writeb(*value, (tcdm_base + PRCM_REQ_MB5_I2C_VAL));
216362306a36Sopenharmony_ci
216462306a36Sopenharmony_ci	writel(MBOX_BIT(5), PRCM_MBOX_CPU_SET);
216562306a36Sopenharmony_ci
216662306a36Sopenharmony_ci	if (!wait_for_completion_timeout(&mb5_transfer.work,
216762306a36Sopenharmony_ci				msecs_to_jiffies(20000))) {
216862306a36Sopenharmony_ci		pr_err("prcmu: %s timed out (20 s) waiting for a reply.\n",
216962306a36Sopenharmony_ci			__func__);
217062306a36Sopenharmony_ci		r = -EIO;
217162306a36Sopenharmony_ci	} else {
217262306a36Sopenharmony_ci		r = ((mb5_transfer.ack.status == I2C_WR_OK) ? 0 : -EIO);
217362306a36Sopenharmony_ci	}
217462306a36Sopenharmony_ci
217562306a36Sopenharmony_ci	mutex_unlock(&mb5_transfer.lock);
217662306a36Sopenharmony_ci
217762306a36Sopenharmony_ci	return r;
217862306a36Sopenharmony_ci}
217962306a36Sopenharmony_ci
218062306a36Sopenharmony_ci/**
218162306a36Sopenharmony_ci * prcmu_abb_write() - Write register value(s) to the ABB.
218262306a36Sopenharmony_ci * @slave:	The I2C slave address.
218362306a36Sopenharmony_ci * @reg:	The (start) register address.
218462306a36Sopenharmony_ci * @value:	The value(s) to write.
218562306a36Sopenharmony_ci * @size:	The number of registers to write.
218662306a36Sopenharmony_ci *
218762306a36Sopenharmony_ci * Writes register value(s) to the ABB.
218862306a36Sopenharmony_ci * @size has to be 1 for the current firmware version.
218962306a36Sopenharmony_ci */
219062306a36Sopenharmony_ciint prcmu_abb_write(u8 slave, u8 reg, u8 *value, u8 size)
219162306a36Sopenharmony_ci{
219262306a36Sopenharmony_ci	u8 mask = ~0;
219362306a36Sopenharmony_ci
219462306a36Sopenharmony_ci	return prcmu_abb_write_masked(slave, reg, value, &mask, size);
219562306a36Sopenharmony_ci}
219662306a36Sopenharmony_ci
219762306a36Sopenharmony_ci/**
219862306a36Sopenharmony_ci * prcmu_ac_wake_req - should be called whenever ARM wants to wakeup Modem
219962306a36Sopenharmony_ci */
220062306a36Sopenharmony_ciint prcmu_ac_wake_req(void)
220162306a36Sopenharmony_ci{
220262306a36Sopenharmony_ci	u32 val;
220362306a36Sopenharmony_ci	int ret = 0;
220462306a36Sopenharmony_ci
220562306a36Sopenharmony_ci	mutex_lock(&mb0_transfer.ac_wake_lock);
220662306a36Sopenharmony_ci
220762306a36Sopenharmony_ci	val = readl(PRCM_HOSTACCESS_REQ);
220862306a36Sopenharmony_ci	if (val & PRCM_HOSTACCESS_REQ_HOSTACCESS_REQ)
220962306a36Sopenharmony_ci		goto unlock_and_return;
221062306a36Sopenharmony_ci
221162306a36Sopenharmony_ci	atomic_set(&ac_wake_req_state, 1);
221262306a36Sopenharmony_ci
221362306a36Sopenharmony_ci	/*
221462306a36Sopenharmony_ci	 * Force Modem Wake-up before hostaccess_req ping-pong.
221562306a36Sopenharmony_ci	 * It prevents Modem to enter in Sleep while acking the hostaccess
221662306a36Sopenharmony_ci	 * request. The 31us delay has been calculated by HWI.
221762306a36Sopenharmony_ci	 */
221862306a36Sopenharmony_ci	val |= PRCM_HOSTACCESS_REQ_WAKE_REQ;
221962306a36Sopenharmony_ci	writel(val, PRCM_HOSTACCESS_REQ);
222062306a36Sopenharmony_ci
222162306a36Sopenharmony_ci	udelay(31);
222262306a36Sopenharmony_ci
222362306a36Sopenharmony_ci	val |= PRCM_HOSTACCESS_REQ_HOSTACCESS_REQ;
222462306a36Sopenharmony_ci	writel(val, PRCM_HOSTACCESS_REQ);
222562306a36Sopenharmony_ci
222662306a36Sopenharmony_ci	if (!wait_for_completion_timeout(&mb0_transfer.ac_wake_work,
222762306a36Sopenharmony_ci			msecs_to_jiffies(5000))) {
222862306a36Sopenharmony_ci		pr_crit("prcmu: %s timed out (5 s) waiting for a reply.\n",
222962306a36Sopenharmony_ci			__func__);
223062306a36Sopenharmony_ci		ret = -EFAULT;
223162306a36Sopenharmony_ci	}
223262306a36Sopenharmony_ci
223362306a36Sopenharmony_ciunlock_and_return:
223462306a36Sopenharmony_ci	mutex_unlock(&mb0_transfer.ac_wake_lock);
223562306a36Sopenharmony_ci	return ret;
223662306a36Sopenharmony_ci}
223762306a36Sopenharmony_ci
223862306a36Sopenharmony_ci/**
223962306a36Sopenharmony_ci * prcmu_ac_sleep_req - called when ARM no longer needs to talk to modem
224062306a36Sopenharmony_ci */
224162306a36Sopenharmony_civoid prcmu_ac_sleep_req(void)
224262306a36Sopenharmony_ci{
224362306a36Sopenharmony_ci	u32 val;
224462306a36Sopenharmony_ci
224562306a36Sopenharmony_ci	mutex_lock(&mb0_transfer.ac_wake_lock);
224662306a36Sopenharmony_ci
224762306a36Sopenharmony_ci	val = readl(PRCM_HOSTACCESS_REQ);
224862306a36Sopenharmony_ci	if (!(val & PRCM_HOSTACCESS_REQ_HOSTACCESS_REQ))
224962306a36Sopenharmony_ci		goto unlock_and_return;
225062306a36Sopenharmony_ci
225162306a36Sopenharmony_ci	writel((val & ~PRCM_HOSTACCESS_REQ_HOSTACCESS_REQ),
225262306a36Sopenharmony_ci		PRCM_HOSTACCESS_REQ);
225362306a36Sopenharmony_ci
225462306a36Sopenharmony_ci	if (!wait_for_completion_timeout(&mb0_transfer.ac_wake_work,
225562306a36Sopenharmony_ci			msecs_to_jiffies(5000))) {
225662306a36Sopenharmony_ci		pr_crit("prcmu: %s timed out (5 s) waiting for a reply.\n",
225762306a36Sopenharmony_ci			__func__);
225862306a36Sopenharmony_ci	}
225962306a36Sopenharmony_ci
226062306a36Sopenharmony_ci	atomic_set(&ac_wake_req_state, 0);
226162306a36Sopenharmony_ci
226262306a36Sopenharmony_ciunlock_and_return:
226362306a36Sopenharmony_ci	mutex_unlock(&mb0_transfer.ac_wake_lock);
226462306a36Sopenharmony_ci}
226562306a36Sopenharmony_ci
226662306a36Sopenharmony_cibool db8500_prcmu_is_ac_wake_requested(void)
226762306a36Sopenharmony_ci{
226862306a36Sopenharmony_ci	return (atomic_read(&ac_wake_req_state) != 0);
226962306a36Sopenharmony_ci}
227062306a36Sopenharmony_ci
227162306a36Sopenharmony_ci/**
227262306a36Sopenharmony_ci * db8500_prcmu_system_reset - System reset
227362306a36Sopenharmony_ci *
227462306a36Sopenharmony_ci * Saves the reset reason code and then sets the APE_SOFTRST register which
227562306a36Sopenharmony_ci * fires interrupt to fw
227662306a36Sopenharmony_ci *
227762306a36Sopenharmony_ci * @reset_code: The reason for system reset
227862306a36Sopenharmony_ci */
227962306a36Sopenharmony_civoid db8500_prcmu_system_reset(u16 reset_code)
228062306a36Sopenharmony_ci{
228162306a36Sopenharmony_ci	writew(reset_code, (tcdm_base + PRCM_SW_RST_REASON));
228262306a36Sopenharmony_ci	writel(1, PRCM_APE_SOFTRST);
228362306a36Sopenharmony_ci}
228462306a36Sopenharmony_ci
228562306a36Sopenharmony_ci/**
228662306a36Sopenharmony_ci * db8500_prcmu_get_reset_code - Retrieve SW reset reason code
228762306a36Sopenharmony_ci *
228862306a36Sopenharmony_ci * Retrieves the reset reason code stored by prcmu_system_reset() before
228962306a36Sopenharmony_ci * last restart.
229062306a36Sopenharmony_ci */
229162306a36Sopenharmony_ciu16 db8500_prcmu_get_reset_code(void)
229262306a36Sopenharmony_ci{
229362306a36Sopenharmony_ci	return readw(tcdm_base + PRCM_SW_RST_REASON);
229462306a36Sopenharmony_ci}
229562306a36Sopenharmony_ci
229662306a36Sopenharmony_ci/**
229762306a36Sopenharmony_ci * db8500_prcmu_modem_reset - ask the PRCMU to reset modem
229862306a36Sopenharmony_ci */
229962306a36Sopenharmony_civoid db8500_prcmu_modem_reset(void)
230062306a36Sopenharmony_ci{
230162306a36Sopenharmony_ci	mutex_lock(&mb1_transfer.lock);
230262306a36Sopenharmony_ci
230362306a36Sopenharmony_ci	while (readl(PRCM_MBOX_CPU_VAL) & MBOX_BIT(1))
230462306a36Sopenharmony_ci		cpu_relax();
230562306a36Sopenharmony_ci
230662306a36Sopenharmony_ci	writeb(MB1H_RESET_MODEM, (tcdm_base + PRCM_MBOX_HEADER_REQ_MB1));
230762306a36Sopenharmony_ci	writel(MBOX_BIT(1), PRCM_MBOX_CPU_SET);
230862306a36Sopenharmony_ci	wait_for_completion(&mb1_transfer.work);
230962306a36Sopenharmony_ci
231062306a36Sopenharmony_ci	/*
231162306a36Sopenharmony_ci	 * No need to check return from PRCMU as modem should go in reset state
231262306a36Sopenharmony_ci	 * This state is already managed by upper layer
231362306a36Sopenharmony_ci	 */
231462306a36Sopenharmony_ci
231562306a36Sopenharmony_ci	mutex_unlock(&mb1_transfer.lock);
231662306a36Sopenharmony_ci}
231762306a36Sopenharmony_ci
231862306a36Sopenharmony_cistatic void ack_dbb_wakeup(void)
231962306a36Sopenharmony_ci{
232062306a36Sopenharmony_ci	unsigned long flags;
232162306a36Sopenharmony_ci
232262306a36Sopenharmony_ci	spin_lock_irqsave(&mb0_transfer.lock, flags);
232362306a36Sopenharmony_ci
232462306a36Sopenharmony_ci	while (readl(PRCM_MBOX_CPU_VAL) & MBOX_BIT(0))
232562306a36Sopenharmony_ci		cpu_relax();
232662306a36Sopenharmony_ci
232762306a36Sopenharmony_ci	writeb(MB0H_READ_WAKEUP_ACK, (tcdm_base + PRCM_MBOX_HEADER_REQ_MB0));
232862306a36Sopenharmony_ci	writel(MBOX_BIT(0), PRCM_MBOX_CPU_SET);
232962306a36Sopenharmony_ci
233062306a36Sopenharmony_ci	spin_unlock_irqrestore(&mb0_transfer.lock, flags);
233162306a36Sopenharmony_ci}
233262306a36Sopenharmony_ci
233362306a36Sopenharmony_cistatic inline void print_unknown_header_warning(u8 n, u8 header)
233462306a36Sopenharmony_ci{
233562306a36Sopenharmony_ci	pr_warn("prcmu: Unknown message header (%d) in mailbox %d\n",
233662306a36Sopenharmony_ci		header, n);
233762306a36Sopenharmony_ci}
233862306a36Sopenharmony_ci
233962306a36Sopenharmony_cistatic bool read_mailbox_0(void)
234062306a36Sopenharmony_ci{
234162306a36Sopenharmony_ci	bool r;
234262306a36Sopenharmony_ci	u32 ev;
234362306a36Sopenharmony_ci	unsigned int n;
234462306a36Sopenharmony_ci	u8 header;
234562306a36Sopenharmony_ci
234662306a36Sopenharmony_ci	header = readb(tcdm_base + PRCM_MBOX_HEADER_ACK_MB0);
234762306a36Sopenharmony_ci	switch (header) {
234862306a36Sopenharmony_ci	case MB0H_WAKEUP_EXE:
234962306a36Sopenharmony_ci	case MB0H_WAKEUP_SLEEP:
235062306a36Sopenharmony_ci		if (readb(tcdm_base + PRCM_ACK_MB0_READ_POINTER) & 1)
235162306a36Sopenharmony_ci			ev = readl(tcdm_base + PRCM_ACK_MB0_WAKEUP_1_8500);
235262306a36Sopenharmony_ci		else
235362306a36Sopenharmony_ci			ev = readl(tcdm_base + PRCM_ACK_MB0_WAKEUP_0_8500);
235462306a36Sopenharmony_ci
235562306a36Sopenharmony_ci		if (ev & (WAKEUP_BIT_AC_WAKE_ACK | WAKEUP_BIT_AC_SLEEP_ACK))
235662306a36Sopenharmony_ci			complete(&mb0_transfer.ac_wake_work);
235762306a36Sopenharmony_ci		if (ev & WAKEUP_BIT_SYSCLK_OK)
235862306a36Sopenharmony_ci			complete(&mb3_transfer.sysclk_work);
235962306a36Sopenharmony_ci
236062306a36Sopenharmony_ci		ev &= mb0_transfer.req.dbb_irqs;
236162306a36Sopenharmony_ci
236262306a36Sopenharmony_ci		for (n = 0; n < NUM_PRCMU_WAKEUPS; n++) {
236362306a36Sopenharmony_ci			if (ev & prcmu_irq_bit[n])
236462306a36Sopenharmony_ci				generic_handle_domain_irq(db8500_irq_domain, n);
236562306a36Sopenharmony_ci		}
236662306a36Sopenharmony_ci		r = true;
236762306a36Sopenharmony_ci		break;
236862306a36Sopenharmony_ci	default:
236962306a36Sopenharmony_ci		print_unknown_header_warning(0, header);
237062306a36Sopenharmony_ci		r = false;
237162306a36Sopenharmony_ci		break;
237262306a36Sopenharmony_ci	}
237362306a36Sopenharmony_ci	writel(MBOX_BIT(0), PRCM_ARM_IT1_CLR);
237462306a36Sopenharmony_ci	return r;
237562306a36Sopenharmony_ci}
237662306a36Sopenharmony_ci
237762306a36Sopenharmony_cistatic bool read_mailbox_1(void)
237862306a36Sopenharmony_ci{
237962306a36Sopenharmony_ci	mb1_transfer.ack.header = readb(tcdm_base + PRCM_MBOX_HEADER_REQ_MB1);
238062306a36Sopenharmony_ci	mb1_transfer.ack.arm_opp = readb(tcdm_base +
238162306a36Sopenharmony_ci		PRCM_ACK_MB1_CURRENT_ARM_OPP);
238262306a36Sopenharmony_ci	mb1_transfer.ack.ape_opp = readb(tcdm_base +
238362306a36Sopenharmony_ci		PRCM_ACK_MB1_CURRENT_APE_OPP);
238462306a36Sopenharmony_ci	mb1_transfer.ack.ape_voltage_status = readb(tcdm_base +
238562306a36Sopenharmony_ci		PRCM_ACK_MB1_APE_VOLTAGE_STATUS);
238662306a36Sopenharmony_ci	writel(MBOX_BIT(1), PRCM_ARM_IT1_CLR);
238762306a36Sopenharmony_ci	complete(&mb1_transfer.work);
238862306a36Sopenharmony_ci	return false;
238962306a36Sopenharmony_ci}
239062306a36Sopenharmony_ci
239162306a36Sopenharmony_cistatic bool read_mailbox_2(void)
239262306a36Sopenharmony_ci{
239362306a36Sopenharmony_ci	mb2_transfer.ack.status = readb(tcdm_base + PRCM_ACK_MB2_DPS_STATUS);
239462306a36Sopenharmony_ci	writel(MBOX_BIT(2), PRCM_ARM_IT1_CLR);
239562306a36Sopenharmony_ci	complete(&mb2_transfer.work);
239662306a36Sopenharmony_ci	return false;
239762306a36Sopenharmony_ci}
239862306a36Sopenharmony_ci
239962306a36Sopenharmony_cistatic bool read_mailbox_3(void)
240062306a36Sopenharmony_ci{
240162306a36Sopenharmony_ci	writel(MBOX_BIT(3), PRCM_ARM_IT1_CLR);
240262306a36Sopenharmony_ci	return false;
240362306a36Sopenharmony_ci}
240462306a36Sopenharmony_ci
240562306a36Sopenharmony_cistatic bool read_mailbox_4(void)
240662306a36Sopenharmony_ci{
240762306a36Sopenharmony_ci	u8 header;
240862306a36Sopenharmony_ci	bool do_complete = true;
240962306a36Sopenharmony_ci
241062306a36Sopenharmony_ci	header = readb(tcdm_base + PRCM_MBOX_HEADER_REQ_MB4);
241162306a36Sopenharmony_ci	switch (header) {
241262306a36Sopenharmony_ci	case MB4H_MEM_ST:
241362306a36Sopenharmony_ci	case MB4H_HOTDOG:
241462306a36Sopenharmony_ci	case MB4H_HOTMON:
241562306a36Sopenharmony_ci	case MB4H_HOT_PERIOD:
241662306a36Sopenharmony_ci	case MB4H_A9WDOG_CONF:
241762306a36Sopenharmony_ci	case MB4H_A9WDOG_EN:
241862306a36Sopenharmony_ci	case MB4H_A9WDOG_DIS:
241962306a36Sopenharmony_ci	case MB4H_A9WDOG_LOAD:
242062306a36Sopenharmony_ci	case MB4H_A9WDOG_KICK:
242162306a36Sopenharmony_ci		break;
242262306a36Sopenharmony_ci	default:
242362306a36Sopenharmony_ci		print_unknown_header_warning(4, header);
242462306a36Sopenharmony_ci		do_complete = false;
242562306a36Sopenharmony_ci		break;
242662306a36Sopenharmony_ci	}
242762306a36Sopenharmony_ci
242862306a36Sopenharmony_ci	writel(MBOX_BIT(4), PRCM_ARM_IT1_CLR);
242962306a36Sopenharmony_ci
243062306a36Sopenharmony_ci	if (do_complete)
243162306a36Sopenharmony_ci		complete(&mb4_transfer.work);
243262306a36Sopenharmony_ci
243362306a36Sopenharmony_ci	return false;
243462306a36Sopenharmony_ci}
243562306a36Sopenharmony_ci
243662306a36Sopenharmony_cistatic bool read_mailbox_5(void)
243762306a36Sopenharmony_ci{
243862306a36Sopenharmony_ci	mb5_transfer.ack.status = readb(tcdm_base + PRCM_ACK_MB5_I2C_STATUS);
243962306a36Sopenharmony_ci	mb5_transfer.ack.value = readb(tcdm_base + PRCM_ACK_MB5_I2C_VAL);
244062306a36Sopenharmony_ci	writel(MBOX_BIT(5), PRCM_ARM_IT1_CLR);
244162306a36Sopenharmony_ci	complete(&mb5_transfer.work);
244262306a36Sopenharmony_ci	return false;
244362306a36Sopenharmony_ci}
244462306a36Sopenharmony_ci
244562306a36Sopenharmony_cistatic bool read_mailbox_6(void)
244662306a36Sopenharmony_ci{
244762306a36Sopenharmony_ci	writel(MBOX_BIT(6), PRCM_ARM_IT1_CLR);
244862306a36Sopenharmony_ci	return false;
244962306a36Sopenharmony_ci}
245062306a36Sopenharmony_ci
245162306a36Sopenharmony_cistatic bool read_mailbox_7(void)
245262306a36Sopenharmony_ci{
245362306a36Sopenharmony_ci	writel(MBOX_BIT(7), PRCM_ARM_IT1_CLR);
245462306a36Sopenharmony_ci	return false;
245562306a36Sopenharmony_ci}
245662306a36Sopenharmony_ci
245762306a36Sopenharmony_cistatic bool (* const read_mailbox[NUM_MB])(void) = {
245862306a36Sopenharmony_ci	read_mailbox_0,
245962306a36Sopenharmony_ci	read_mailbox_1,
246062306a36Sopenharmony_ci	read_mailbox_2,
246162306a36Sopenharmony_ci	read_mailbox_3,
246262306a36Sopenharmony_ci	read_mailbox_4,
246362306a36Sopenharmony_ci	read_mailbox_5,
246462306a36Sopenharmony_ci	read_mailbox_6,
246562306a36Sopenharmony_ci	read_mailbox_7
246662306a36Sopenharmony_ci};
246762306a36Sopenharmony_ci
246862306a36Sopenharmony_cistatic irqreturn_t prcmu_irq_handler(int irq, void *data)
246962306a36Sopenharmony_ci{
247062306a36Sopenharmony_ci	u32 bits;
247162306a36Sopenharmony_ci	u8 n;
247262306a36Sopenharmony_ci	irqreturn_t r;
247362306a36Sopenharmony_ci
247462306a36Sopenharmony_ci	bits = (readl(PRCM_ARM_IT1_VAL) & ALL_MBOX_BITS);
247562306a36Sopenharmony_ci	if (unlikely(!bits))
247662306a36Sopenharmony_ci		return IRQ_NONE;
247762306a36Sopenharmony_ci
247862306a36Sopenharmony_ci	r = IRQ_HANDLED;
247962306a36Sopenharmony_ci	for (n = 0; bits; n++) {
248062306a36Sopenharmony_ci		if (bits & MBOX_BIT(n)) {
248162306a36Sopenharmony_ci			bits -= MBOX_BIT(n);
248262306a36Sopenharmony_ci			if (read_mailbox[n]())
248362306a36Sopenharmony_ci				r = IRQ_WAKE_THREAD;
248462306a36Sopenharmony_ci		}
248562306a36Sopenharmony_ci	}
248662306a36Sopenharmony_ci	return r;
248762306a36Sopenharmony_ci}
248862306a36Sopenharmony_ci
248962306a36Sopenharmony_cistatic irqreturn_t prcmu_irq_thread_fn(int irq, void *data)
249062306a36Sopenharmony_ci{
249162306a36Sopenharmony_ci	ack_dbb_wakeup();
249262306a36Sopenharmony_ci	return IRQ_HANDLED;
249362306a36Sopenharmony_ci}
249462306a36Sopenharmony_ci
249562306a36Sopenharmony_cistatic void prcmu_mask_work(struct work_struct *work)
249662306a36Sopenharmony_ci{
249762306a36Sopenharmony_ci	unsigned long flags;
249862306a36Sopenharmony_ci
249962306a36Sopenharmony_ci	spin_lock_irqsave(&mb0_transfer.lock, flags);
250062306a36Sopenharmony_ci
250162306a36Sopenharmony_ci	config_wakeups();
250262306a36Sopenharmony_ci
250362306a36Sopenharmony_ci	spin_unlock_irqrestore(&mb0_transfer.lock, flags);
250462306a36Sopenharmony_ci}
250562306a36Sopenharmony_ci
250662306a36Sopenharmony_cistatic void prcmu_irq_mask(struct irq_data *d)
250762306a36Sopenharmony_ci{
250862306a36Sopenharmony_ci	unsigned long flags;
250962306a36Sopenharmony_ci
251062306a36Sopenharmony_ci	spin_lock_irqsave(&mb0_transfer.dbb_irqs_lock, flags);
251162306a36Sopenharmony_ci
251262306a36Sopenharmony_ci	mb0_transfer.req.dbb_irqs &= ~prcmu_irq_bit[d->hwirq];
251362306a36Sopenharmony_ci
251462306a36Sopenharmony_ci	spin_unlock_irqrestore(&mb0_transfer.dbb_irqs_lock, flags);
251562306a36Sopenharmony_ci
251662306a36Sopenharmony_ci	if (d->irq != IRQ_PRCMU_CA_SLEEP)
251762306a36Sopenharmony_ci		schedule_work(&mb0_transfer.mask_work);
251862306a36Sopenharmony_ci}
251962306a36Sopenharmony_ci
252062306a36Sopenharmony_cistatic void prcmu_irq_unmask(struct irq_data *d)
252162306a36Sopenharmony_ci{
252262306a36Sopenharmony_ci	unsigned long flags;
252362306a36Sopenharmony_ci
252462306a36Sopenharmony_ci	spin_lock_irqsave(&mb0_transfer.dbb_irqs_lock, flags);
252562306a36Sopenharmony_ci
252662306a36Sopenharmony_ci	mb0_transfer.req.dbb_irqs |= prcmu_irq_bit[d->hwirq];
252762306a36Sopenharmony_ci
252862306a36Sopenharmony_ci	spin_unlock_irqrestore(&mb0_transfer.dbb_irqs_lock, flags);
252962306a36Sopenharmony_ci
253062306a36Sopenharmony_ci	if (d->irq != IRQ_PRCMU_CA_SLEEP)
253162306a36Sopenharmony_ci		schedule_work(&mb0_transfer.mask_work);
253262306a36Sopenharmony_ci}
253362306a36Sopenharmony_ci
253462306a36Sopenharmony_cistatic void noop(struct irq_data *d)
253562306a36Sopenharmony_ci{
253662306a36Sopenharmony_ci}
253762306a36Sopenharmony_ci
253862306a36Sopenharmony_cistatic struct irq_chip prcmu_irq_chip = {
253962306a36Sopenharmony_ci	.name		= "prcmu",
254062306a36Sopenharmony_ci	.irq_disable	= prcmu_irq_mask,
254162306a36Sopenharmony_ci	.irq_ack	= noop,
254262306a36Sopenharmony_ci	.irq_mask	= prcmu_irq_mask,
254362306a36Sopenharmony_ci	.irq_unmask	= prcmu_irq_unmask,
254462306a36Sopenharmony_ci};
254562306a36Sopenharmony_ci
254662306a36Sopenharmony_cistatic char *fw_project_name(u32 project)
254762306a36Sopenharmony_ci{
254862306a36Sopenharmony_ci	switch (project) {
254962306a36Sopenharmony_ci	case PRCMU_FW_PROJECT_U8500:
255062306a36Sopenharmony_ci		return "U8500";
255162306a36Sopenharmony_ci	case PRCMU_FW_PROJECT_U8400:
255262306a36Sopenharmony_ci		return "U8400";
255362306a36Sopenharmony_ci	case PRCMU_FW_PROJECT_U9500:
255462306a36Sopenharmony_ci		return "U9500";
255562306a36Sopenharmony_ci	case PRCMU_FW_PROJECT_U8500_MBB:
255662306a36Sopenharmony_ci		return "U8500 MBB";
255762306a36Sopenharmony_ci	case PRCMU_FW_PROJECT_U8500_C1:
255862306a36Sopenharmony_ci		return "U8500 C1";
255962306a36Sopenharmony_ci	case PRCMU_FW_PROJECT_U8500_C2:
256062306a36Sopenharmony_ci		return "U8500 C2";
256162306a36Sopenharmony_ci	case PRCMU_FW_PROJECT_U8500_C3:
256262306a36Sopenharmony_ci		return "U8500 C3";
256362306a36Sopenharmony_ci	case PRCMU_FW_PROJECT_U8500_C4:
256462306a36Sopenharmony_ci		return "U8500 C4";
256562306a36Sopenharmony_ci	case PRCMU_FW_PROJECT_U9500_MBL:
256662306a36Sopenharmony_ci		return "U9500 MBL";
256762306a36Sopenharmony_ci	case PRCMU_FW_PROJECT_U8500_SSG1:
256862306a36Sopenharmony_ci		return "U8500 Samsung 1";
256962306a36Sopenharmony_ci	case PRCMU_FW_PROJECT_U8500_MBL2:
257062306a36Sopenharmony_ci		return "U8500 MBL2";
257162306a36Sopenharmony_ci	case PRCMU_FW_PROJECT_U8520:
257262306a36Sopenharmony_ci		return "U8520 MBL";
257362306a36Sopenharmony_ci	case PRCMU_FW_PROJECT_U8420:
257462306a36Sopenharmony_ci		return "U8420";
257562306a36Sopenharmony_ci	case PRCMU_FW_PROJECT_U8500_SSG2:
257662306a36Sopenharmony_ci		return "U8500 Samsung 2";
257762306a36Sopenharmony_ci	case PRCMU_FW_PROJECT_U8420_SYSCLK:
257862306a36Sopenharmony_ci		return "U8420-sysclk";
257962306a36Sopenharmony_ci	case PRCMU_FW_PROJECT_U9540:
258062306a36Sopenharmony_ci		return "U9540";
258162306a36Sopenharmony_ci	case PRCMU_FW_PROJECT_A9420:
258262306a36Sopenharmony_ci		return "A9420";
258362306a36Sopenharmony_ci	case PRCMU_FW_PROJECT_L8540:
258462306a36Sopenharmony_ci		return "L8540";
258562306a36Sopenharmony_ci	case PRCMU_FW_PROJECT_L8580:
258662306a36Sopenharmony_ci		return "L8580";
258762306a36Sopenharmony_ci	default:
258862306a36Sopenharmony_ci		return "Unknown";
258962306a36Sopenharmony_ci	}
259062306a36Sopenharmony_ci}
259162306a36Sopenharmony_ci
259262306a36Sopenharmony_cistatic int db8500_irq_map(struct irq_domain *d, unsigned int virq,
259362306a36Sopenharmony_ci				irq_hw_number_t hwirq)
259462306a36Sopenharmony_ci{
259562306a36Sopenharmony_ci	irq_set_chip_and_handler(virq, &prcmu_irq_chip,
259662306a36Sopenharmony_ci				handle_simple_irq);
259762306a36Sopenharmony_ci
259862306a36Sopenharmony_ci	return 0;
259962306a36Sopenharmony_ci}
260062306a36Sopenharmony_ci
260162306a36Sopenharmony_cistatic const struct irq_domain_ops db8500_irq_ops = {
260262306a36Sopenharmony_ci	.map    = db8500_irq_map,
260362306a36Sopenharmony_ci	.xlate  = irq_domain_xlate_twocell,
260462306a36Sopenharmony_ci};
260562306a36Sopenharmony_ci
260662306a36Sopenharmony_cistatic int db8500_irq_init(struct device_node *np)
260762306a36Sopenharmony_ci{
260862306a36Sopenharmony_ci	int i;
260962306a36Sopenharmony_ci
261062306a36Sopenharmony_ci	db8500_irq_domain = irq_domain_add_simple(
261162306a36Sopenharmony_ci		np, NUM_PRCMU_WAKEUPS, 0,
261262306a36Sopenharmony_ci		&db8500_irq_ops, NULL);
261362306a36Sopenharmony_ci
261462306a36Sopenharmony_ci	if (!db8500_irq_domain) {
261562306a36Sopenharmony_ci		pr_err("Failed to create irqdomain\n");
261662306a36Sopenharmony_ci		return -ENOSYS;
261762306a36Sopenharmony_ci	}
261862306a36Sopenharmony_ci
261962306a36Sopenharmony_ci	/* All wakeups will be used, so create mappings for all */
262062306a36Sopenharmony_ci	for (i = 0; i < NUM_PRCMU_WAKEUPS; i++)
262162306a36Sopenharmony_ci		irq_create_mapping(db8500_irq_domain, i);
262262306a36Sopenharmony_ci
262362306a36Sopenharmony_ci	return 0;
262462306a36Sopenharmony_ci}
262562306a36Sopenharmony_ci
262662306a36Sopenharmony_cistatic void dbx500_fw_version_init(struct device_node *np)
262762306a36Sopenharmony_ci{
262862306a36Sopenharmony_ci	void __iomem *tcpm_base;
262962306a36Sopenharmony_ci	u32 version;
263062306a36Sopenharmony_ci
263162306a36Sopenharmony_ci	tcpm_base = of_iomap(np, 1);
263262306a36Sopenharmony_ci	if (!tcpm_base) {
263362306a36Sopenharmony_ci		pr_err("no prcmu tcpm mem region provided\n");
263462306a36Sopenharmony_ci		return;
263562306a36Sopenharmony_ci	}
263662306a36Sopenharmony_ci
263762306a36Sopenharmony_ci	version = readl(tcpm_base + DB8500_PRCMU_FW_VERSION_OFFSET);
263862306a36Sopenharmony_ci	fw_info.version.project = (version & 0xFF);
263962306a36Sopenharmony_ci	fw_info.version.api_version = (version >> 8) & 0xFF;
264062306a36Sopenharmony_ci	fw_info.version.func_version = (version >> 16) & 0xFF;
264162306a36Sopenharmony_ci	fw_info.version.errata = (version >> 24) & 0xFF;
264262306a36Sopenharmony_ci	strncpy(fw_info.version.project_name,
264362306a36Sopenharmony_ci		fw_project_name(fw_info.version.project),
264462306a36Sopenharmony_ci		PRCMU_FW_PROJECT_NAME_LEN);
264562306a36Sopenharmony_ci	fw_info.valid = true;
264662306a36Sopenharmony_ci	pr_info("PRCMU firmware: %s(%d), version %d.%d.%d\n",
264762306a36Sopenharmony_ci		fw_info.version.project_name,
264862306a36Sopenharmony_ci		fw_info.version.project,
264962306a36Sopenharmony_ci		fw_info.version.api_version,
265062306a36Sopenharmony_ci		fw_info.version.func_version,
265162306a36Sopenharmony_ci		fw_info.version.errata);
265262306a36Sopenharmony_ci	iounmap(tcpm_base);
265362306a36Sopenharmony_ci}
265462306a36Sopenharmony_ci
265562306a36Sopenharmony_civoid __init db8500_prcmu_early_init(void)
265662306a36Sopenharmony_ci{
265762306a36Sopenharmony_ci	/*
265862306a36Sopenharmony_ci	 * This is a temporary remap to bring up the clocks. It is
265962306a36Sopenharmony_ci	 * subsequently replaces with a real remap. After the merge of
266062306a36Sopenharmony_ci	 * the mailbox subsystem all of this early code goes away, and the
266162306a36Sopenharmony_ci	 * clock driver can probe independently. An early initcall will
266262306a36Sopenharmony_ci	 * still be needed, but it can be diverted into drivers/clk/ux500.
266362306a36Sopenharmony_ci	 */
266462306a36Sopenharmony_ci	struct device_node *np;
266562306a36Sopenharmony_ci
266662306a36Sopenharmony_ci	np = of_find_compatible_node(NULL, NULL, "stericsson,db8500-prcmu");
266762306a36Sopenharmony_ci	prcmu_base = of_iomap(np, 0);
266862306a36Sopenharmony_ci	if (!prcmu_base) {
266962306a36Sopenharmony_ci		of_node_put(np);
267062306a36Sopenharmony_ci		pr_err("%s: ioremap() of prcmu registers failed!\n", __func__);
267162306a36Sopenharmony_ci		return;
267262306a36Sopenharmony_ci	}
267362306a36Sopenharmony_ci	dbx500_fw_version_init(np);
267462306a36Sopenharmony_ci	of_node_put(np);
267562306a36Sopenharmony_ci
267662306a36Sopenharmony_ci	spin_lock_init(&mb0_transfer.lock);
267762306a36Sopenharmony_ci	spin_lock_init(&mb0_transfer.dbb_irqs_lock);
267862306a36Sopenharmony_ci	mutex_init(&mb0_transfer.ac_wake_lock);
267962306a36Sopenharmony_ci	init_completion(&mb0_transfer.ac_wake_work);
268062306a36Sopenharmony_ci	mutex_init(&mb1_transfer.lock);
268162306a36Sopenharmony_ci	init_completion(&mb1_transfer.work);
268262306a36Sopenharmony_ci	mb1_transfer.ape_opp = APE_NO_CHANGE;
268362306a36Sopenharmony_ci	mutex_init(&mb2_transfer.lock);
268462306a36Sopenharmony_ci	init_completion(&mb2_transfer.work);
268562306a36Sopenharmony_ci	spin_lock_init(&mb2_transfer.auto_pm_lock);
268662306a36Sopenharmony_ci	spin_lock_init(&mb3_transfer.lock);
268762306a36Sopenharmony_ci	mutex_init(&mb3_transfer.sysclk_lock);
268862306a36Sopenharmony_ci	init_completion(&mb3_transfer.sysclk_work);
268962306a36Sopenharmony_ci	mutex_init(&mb4_transfer.lock);
269062306a36Sopenharmony_ci	init_completion(&mb4_transfer.work);
269162306a36Sopenharmony_ci	mutex_init(&mb5_transfer.lock);
269262306a36Sopenharmony_ci	init_completion(&mb5_transfer.work);
269362306a36Sopenharmony_ci
269462306a36Sopenharmony_ci	INIT_WORK(&mb0_transfer.mask_work, prcmu_mask_work);
269562306a36Sopenharmony_ci}
269662306a36Sopenharmony_ci
269762306a36Sopenharmony_cistatic void init_prcm_registers(void)
269862306a36Sopenharmony_ci{
269962306a36Sopenharmony_ci	u32 val;
270062306a36Sopenharmony_ci
270162306a36Sopenharmony_ci	val = readl(PRCM_A9PL_FORCE_CLKEN);
270262306a36Sopenharmony_ci	val &= ~(PRCM_A9PL_FORCE_CLKEN_PRCM_A9PL_FORCE_CLKEN |
270362306a36Sopenharmony_ci		PRCM_A9PL_FORCE_CLKEN_PRCM_A9AXI_FORCE_CLKEN);
270462306a36Sopenharmony_ci	writel(val, (PRCM_A9PL_FORCE_CLKEN));
270562306a36Sopenharmony_ci}
270662306a36Sopenharmony_ci
270762306a36Sopenharmony_ci/*
270862306a36Sopenharmony_ci * Power domain switches (ePODs) modeled as regulators for the DB8500 SoC
270962306a36Sopenharmony_ci */
271062306a36Sopenharmony_cistatic struct regulator_consumer_supply db8500_vape_consumers[] = {
271162306a36Sopenharmony_ci	REGULATOR_SUPPLY("v-ape", NULL),
271262306a36Sopenharmony_ci	REGULATOR_SUPPLY("v-i2c", "nmk-i2c.0"),
271362306a36Sopenharmony_ci	REGULATOR_SUPPLY("v-i2c", "nmk-i2c.1"),
271462306a36Sopenharmony_ci	REGULATOR_SUPPLY("v-i2c", "nmk-i2c.2"),
271562306a36Sopenharmony_ci	REGULATOR_SUPPLY("v-i2c", "nmk-i2c.3"),
271662306a36Sopenharmony_ci	REGULATOR_SUPPLY("v-i2c", "nmk-i2c.4"),
271762306a36Sopenharmony_ci	/* "v-mmc" changed to "vcore" in the mainline kernel */
271862306a36Sopenharmony_ci	REGULATOR_SUPPLY("vcore", "sdi0"),
271962306a36Sopenharmony_ci	REGULATOR_SUPPLY("vcore", "sdi1"),
272062306a36Sopenharmony_ci	REGULATOR_SUPPLY("vcore", "sdi2"),
272162306a36Sopenharmony_ci	REGULATOR_SUPPLY("vcore", "sdi3"),
272262306a36Sopenharmony_ci	REGULATOR_SUPPLY("vcore", "sdi4"),
272362306a36Sopenharmony_ci	REGULATOR_SUPPLY("v-dma", "dma40.0"),
272462306a36Sopenharmony_ci	REGULATOR_SUPPLY("v-ape", "ab8500-usb.0"),
272562306a36Sopenharmony_ci	/* "v-uart" changed to "vcore" in the mainline kernel */
272662306a36Sopenharmony_ci	REGULATOR_SUPPLY("vcore", "uart0"),
272762306a36Sopenharmony_ci	REGULATOR_SUPPLY("vcore", "uart1"),
272862306a36Sopenharmony_ci	REGULATOR_SUPPLY("vcore", "uart2"),
272962306a36Sopenharmony_ci	REGULATOR_SUPPLY("v-ape", "nmk-ske-keypad.0"),
273062306a36Sopenharmony_ci	REGULATOR_SUPPLY("v-hsi", "ste_hsi.0"),
273162306a36Sopenharmony_ci	REGULATOR_SUPPLY("vddvario", "smsc911x.0"),
273262306a36Sopenharmony_ci};
273362306a36Sopenharmony_ci
273462306a36Sopenharmony_cistatic struct regulator_consumer_supply db8500_vsmps2_consumers[] = {
273562306a36Sopenharmony_ci	REGULATOR_SUPPLY("musb_1v8", "ab8500-usb.0"),
273662306a36Sopenharmony_ci	/* AV8100 regulator */
273762306a36Sopenharmony_ci	REGULATOR_SUPPLY("hdmi_1v8", "0-0070"),
273862306a36Sopenharmony_ci};
273962306a36Sopenharmony_ci
274062306a36Sopenharmony_cistatic struct regulator_consumer_supply db8500_b2r2_mcde_consumers[] = {
274162306a36Sopenharmony_ci	REGULATOR_SUPPLY("vsupply", "b2r2_bus"),
274262306a36Sopenharmony_ci	REGULATOR_SUPPLY("vsupply", "mcde"),
274362306a36Sopenharmony_ci};
274462306a36Sopenharmony_ci
274562306a36Sopenharmony_ci/* SVA MMDSP regulator switch */
274662306a36Sopenharmony_cistatic struct regulator_consumer_supply db8500_svammdsp_consumers[] = {
274762306a36Sopenharmony_ci	REGULATOR_SUPPLY("sva-mmdsp", "cm_control"),
274862306a36Sopenharmony_ci};
274962306a36Sopenharmony_ci
275062306a36Sopenharmony_ci/* SVA pipe regulator switch */
275162306a36Sopenharmony_cistatic struct regulator_consumer_supply db8500_svapipe_consumers[] = {
275262306a36Sopenharmony_ci	REGULATOR_SUPPLY("sva-pipe", "cm_control"),
275362306a36Sopenharmony_ci};
275462306a36Sopenharmony_ci
275562306a36Sopenharmony_ci/* SIA MMDSP regulator switch */
275662306a36Sopenharmony_cistatic struct regulator_consumer_supply db8500_siammdsp_consumers[] = {
275762306a36Sopenharmony_ci	REGULATOR_SUPPLY("sia-mmdsp", "cm_control"),
275862306a36Sopenharmony_ci};
275962306a36Sopenharmony_ci
276062306a36Sopenharmony_ci/* SIA pipe regulator switch */
276162306a36Sopenharmony_cistatic struct regulator_consumer_supply db8500_siapipe_consumers[] = {
276262306a36Sopenharmony_ci	REGULATOR_SUPPLY("sia-pipe", "cm_control"),
276362306a36Sopenharmony_ci};
276462306a36Sopenharmony_ci
276562306a36Sopenharmony_cistatic struct regulator_consumer_supply db8500_sga_consumers[] = {
276662306a36Sopenharmony_ci	REGULATOR_SUPPLY("v-mali", NULL),
276762306a36Sopenharmony_ci};
276862306a36Sopenharmony_ci
276962306a36Sopenharmony_ci/* ESRAM1 and 2 regulator switch */
277062306a36Sopenharmony_cistatic struct regulator_consumer_supply db8500_esram12_consumers[] = {
277162306a36Sopenharmony_ci	REGULATOR_SUPPLY("esram12", "cm_control"),
277262306a36Sopenharmony_ci};
277362306a36Sopenharmony_ci
277462306a36Sopenharmony_ci/* ESRAM3 and 4 regulator switch */
277562306a36Sopenharmony_cistatic struct regulator_consumer_supply db8500_esram34_consumers[] = {
277662306a36Sopenharmony_ci	REGULATOR_SUPPLY("v-esram34", "mcde"),
277762306a36Sopenharmony_ci	REGULATOR_SUPPLY("esram34", "cm_control"),
277862306a36Sopenharmony_ci	REGULATOR_SUPPLY("lcla_esram", "dma40.0"),
277962306a36Sopenharmony_ci};
278062306a36Sopenharmony_ci
278162306a36Sopenharmony_cistatic struct regulator_init_data db8500_regulators[DB8500_NUM_REGULATORS] = {
278262306a36Sopenharmony_ci	[DB8500_REGULATOR_VAPE] = {
278362306a36Sopenharmony_ci		.constraints = {
278462306a36Sopenharmony_ci			.name = "db8500-vape",
278562306a36Sopenharmony_ci			.valid_ops_mask = REGULATOR_CHANGE_STATUS,
278662306a36Sopenharmony_ci			.always_on = true,
278762306a36Sopenharmony_ci		},
278862306a36Sopenharmony_ci		.consumer_supplies = db8500_vape_consumers,
278962306a36Sopenharmony_ci		.num_consumer_supplies = ARRAY_SIZE(db8500_vape_consumers),
279062306a36Sopenharmony_ci	},
279162306a36Sopenharmony_ci	[DB8500_REGULATOR_VARM] = {
279262306a36Sopenharmony_ci		.constraints = {
279362306a36Sopenharmony_ci			.name = "db8500-varm",
279462306a36Sopenharmony_ci			.valid_ops_mask = REGULATOR_CHANGE_STATUS,
279562306a36Sopenharmony_ci		},
279662306a36Sopenharmony_ci	},
279762306a36Sopenharmony_ci	[DB8500_REGULATOR_VMODEM] = {
279862306a36Sopenharmony_ci		.constraints = {
279962306a36Sopenharmony_ci			.name = "db8500-vmodem",
280062306a36Sopenharmony_ci			.valid_ops_mask = REGULATOR_CHANGE_STATUS,
280162306a36Sopenharmony_ci		},
280262306a36Sopenharmony_ci	},
280362306a36Sopenharmony_ci	[DB8500_REGULATOR_VPLL] = {
280462306a36Sopenharmony_ci		.constraints = {
280562306a36Sopenharmony_ci			.name = "db8500-vpll",
280662306a36Sopenharmony_ci			.valid_ops_mask = REGULATOR_CHANGE_STATUS,
280762306a36Sopenharmony_ci		},
280862306a36Sopenharmony_ci	},
280962306a36Sopenharmony_ci	[DB8500_REGULATOR_VSMPS1] = {
281062306a36Sopenharmony_ci		.constraints = {
281162306a36Sopenharmony_ci			.name = "db8500-vsmps1",
281262306a36Sopenharmony_ci			.valid_ops_mask = REGULATOR_CHANGE_STATUS,
281362306a36Sopenharmony_ci		},
281462306a36Sopenharmony_ci	},
281562306a36Sopenharmony_ci	[DB8500_REGULATOR_VSMPS2] = {
281662306a36Sopenharmony_ci		.constraints = {
281762306a36Sopenharmony_ci			.name = "db8500-vsmps2",
281862306a36Sopenharmony_ci			.valid_ops_mask = REGULATOR_CHANGE_STATUS,
281962306a36Sopenharmony_ci		},
282062306a36Sopenharmony_ci		.consumer_supplies = db8500_vsmps2_consumers,
282162306a36Sopenharmony_ci		.num_consumer_supplies = ARRAY_SIZE(db8500_vsmps2_consumers),
282262306a36Sopenharmony_ci	},
282362306a36Sopenharmony_ci	[DB8500_REGULATOR_VSMPS3] = {
282462306a36Sopenharmony_ci		.constraints = {
282562306a36Sopenharmony_ci			.name = "db8500-vsmps3",
282662306a36Sopenharmony_ci			.valid_ops_mask = REGULATOR_CHANGE_STATUS,
282762306a36Sopenharmony_ci		},
282862306a36Sopenharmony_ci	},
282962306a36Sopenharmony_ci	[DB8500_REGULATOR_VRF1] = {
283062306a36Sopenharmony_ci		.constraints = {
283162306a36Sopenharmony_ci			.name = "db8500-vrf1",
283262306a36Sopenharmony_ci			.valid_ops_mask = REGULATOR_CHANGE_STATUS,
283362306a36Sopenharmony_ci		},
283462306a36Sopenharmony_ci	},
283562306a36Sopenharmony_ci	[DB8500_REGULATOR_SWITCH_SVAMMDSP] = {
283662306a36Sopenharmony_ci		/* dependency to u8500-vape is handled outside regulator framework */
283762306a36Sopenharmony_ci		.constraints = {
283862306a36Sopenharmony_ci			.name = "db8500-sva-mmdsp",
283962306a36Sopenharmony_ci			.valid_ops_mask = REGULATOR_CHANGE_STATUS,
284062306a36Sopenharmony_ci		},
284162306a36Sopenharmony_ci		.consumer_supplies = db8500_svammdsp_consumers,
284262306a36Sopenharmony_ci		.num_consumer_supplies = ARRAY_SIZE(db8500_svammdsp_consumers),
284362306a36Sopenharmony_ci	},
284462306a36Sopenharmony_ci	[DB8500_REGULATOR_SWITCH_SVAMMDSPRET] = {
284562306a36Sopenharmony_ci		.constraints = {
284662306a36Sopenharmony_ci			/* "ret" means "retention" */
284762306a36Sopenharmony_ci			.name = "db8500-sva-mmdsp-ret",
284862306a36Sopenharmony_ci			.valid_ops_mask = REGULATOR_CHANGE_STATUS,
284962306a36Sopenharmony_ci		},
285062306a36Sopenharmony_ci	},
285162306a36Sopenharmony_ci	[DB8500_REGULATOR_SWITCH_SVAPIPE] = {
285262306a36Sopenharmony_ci		/* dependency to u8500-vape is handled outside regulator framework */
285362306a36Sopenharmony_ci		.constraints = {
285462306a36Sopenharmony_ci			.name = "db8500-sva-pipe",
285562306a36Sopenharmony_ci			.valid_ops_mask = REGULATOR_CHANGE_STATUS,
285662306a36Sopenharmony_ci		},
285762306a36Sopenharmony_ci		.consumer_supplies = db8500_svapipe_consumers,
285862306a36Sopenharmony_ci		.num_consumer_supplies = ARRAY_SIZE(db8500_svapipe_consumers),
285962306a36Sopenharmony_ci	},
286062306a36Sopenharmony_ci	[DB8500_REGULATOR_SWITCH_SIAMMDSP] = {
286162306a36Sopenharmony_ci		/* dependency to u8500-vape is handled outside regulator framework */
286262306a36Sopenharmony_ci		.constraints = {
286362306a36Sopenharmony_ci			.name = "db8500-sia-mmdsp",
286462306a36Sopenharmony_ci			.valid_ops_mask = REGULATOR_CHANGE_STATUS,
286562306a36Sopenharmony_ci		},
286662306a36Sopenharmony_ci		.consumer_supplies = db8500_siammdsp_consumers,
286762306a36Sopenharmony_ci		.num_consumer_supplies = ARRAY_SIZE(db8500_siammdsp_consumers),
286862306a36Sopenharmony_ci	},
286962306a36Sopenharmony_ci	[DB8500_REGULATOR_SWITCH_SIAMMDSPRET] = {
287062306a36Sopenharmony_ci		.constraints = {
287162306a36Sopenharmony_ci			.name = "db8500-sia-mmdsp-ret",
287262306a36Sopenharmony_ci			.valid_ops_mask = REGULATOR_CHANGE_STATUS,
287362306a36Sopenharmony_ci		},
287462306a36Sopenharmony_ci	},
287562306a36Sopenharmony_ci	[DB8500_REGULATOR_SWITCH_SIAPIPE] = {
287662306a36Sopenharmony_ci		/* dependency to u8500-vape is handled outside regulator framework */
287762306a36Sopenharmony_ci		.constraints = {
287862306a36Sopenharmony_ci			.name = "db8500-sia-pipe",
287962306a36Sopenharmony_ci			.valid_ops_mask = REGULATOR_CHANGE_STATUS,
288062306a36Sopenharmony_ci		},
288162306a36Sopenharmony_ci		.consumer_supplies = db8500_siapipe_consumers,
288262306a36Sopenharmony_ci		.num_consumer_supplies = ARRAY_SIZE(db8500_siapipe_consumers),
288362306a36Sopenharmony_ci	},
288462306a36Sopenharmony_ci	[DB8500_REGULATOR_SWITCH_SGA] = {
288562306a36Sopenharmony_ci		.supply_regulator = "db8500-vape",
288662306a36Sopenharmony_ci		.constraints = {
288762306a36Sopenharmony_ci			.name = "db8500-sga",
288862306a36Sopenharmony_ci			.valid_ops_mask = REGULATOR_CHANGE_STATUS,
288962306a36Sopenharmony_ci		},
289062306a36Sopenharmony_ci		.consumer_supplies = db8500_sga_consumers,
289162306a36Sopenharmony_ci		.num_consumer_supplies = ARRAY_SIZE(db8500_sga_consumers),
289262306a36Sopenharmony_ci
289362306a36Sopenharmony_ci	},
289462306a36Sopenharmony_ci	[DB8500_REGULATOR_SWITCH_B2R2_MCDE] = {
289562306a36Sopenharmony_ci		.supply_regulator = "db8500-vape",
289662306a36Sopenharmony_ci		.constraints = {
289762306a36Sopenharmony_ci			.name = "db8500-b2r2-mcde",
289862306a36Sopenharmony_ci			.valid_ops_mask = REGULATOR_CHANGE_STATUS,
289962306a36Sopenharmony_ci		},
290062306a36Sopenharmony_ci		.consumer_supplies = db8500_b2r2_mcde_consumers,
290162306a36Sopenharmony_ci		.num_consumer_supplies = ARRAY_SIZE(db8500_b2r2_mcde_consumers),
290262306a36Sopenharmony_ci	},
290362306a36Sopenharmony_ci	[DB8500_REGULATOR_SWITCH_ESRAM12] = {
290462306a36Sopenharmony_ci		/*
290562306a36Sopenharmony_ci		 * esram12 is set in retention and supplied by Vsafe when Vape is off,
290662306a36Sopenharmony_ci		 * no need to hold Vape
290762306a36Sopenharmony_ci		 */
290862306a36Sopenharmony_ci		.constraints = {
290962306a36Sopenharmony_ci			.name = "db8500-esram12",
291062306a36Sopenharmony_ci			.valid_ops_mask = REGULATOR_CHANGE_STATUS,
291162306a36Sopenharmony_ci		},
291262306a36Sopenharmony_ci		.consumer_supplies = db8500_esram12_consumers,
291362306a36Sopenharmony_ci		.num_consumer_supplies = ARRAY_SIZE(db8500_esram12_consumers),
291462306a36Sopenharmony_ci	},
291562306a36Sopenharmony_ci	[DB8500_REGULATOR_SWITCH_ESRAM12RET] = {
291662306a36Sopenharmony_ci		.constraints = {
291762306a36Sopenharmony_ci			.name = "db8500-esram12-ret",
291862306a36Sopenharmony_ci			.valid_ops_mask = REGULATOR_CHANGE_STATUS,
291962306a36Sopenharmony_ci		},
292062306a36Sopenharmony_ci	},
292162306a36Sopenharmony_ci	[DB8500_REGULATOR_SWITCH_ESRAM34] = {
292262306a36Sopenharmony_ci		/*
292362306a36Sopenharmony_ci		 * esram34 is set in retention and supplied by Vsafe when Vape is off,
292462306a36Sopenharmony_ci		 * no need to hold Vape
292562306a36Sopenharmony_ci		 */
292662306a36Sopenharmony_ci		.constraints = {
292762306a36Sopenharmony_ci			.name = "db8500-esram34",
292862306a36Sopenharmony_ci			.valid_ops_mask = REGULATOR_CHANGE_STATUS,
292962306a36Sopenharmony_ci		},
293062306a36Sopenharmony_ci		.consumer_supplies = db8500_esram34_consumers,
293162306a36Sopenharmony_ci		.num_consumer_supplies = ARRAY_SIZE(db8500_esram34_consumers),
293262306a36Sopenharmony_ci	},
293362306a36Sopenharmony_ci	[DB8500_REGULATOR_SWITCH_ESRAM34RET] = {
293462306a36Sopenharmony_ci		.constraints = {
293562306a36Sopenharmony_ci			.name = "db8500-esram34-ret",
293662306a36Sopenharmony_ci			.valid_ops_mask = REGULATOR_CHANGE_STATUS,
293762306a36Sopenharmony_ci		},
293862306a36Sopenharmony_ci	},
293962306a36Sopenharmony_ci};
294062306a36Sopenharmony_ci
294162306a36Sopenharmony_cistatic const struct mfd_cell common_prcmu_devs[] = {
294262306a36Sopenharmony_ci	MFD_CELL_NAME("db8500_wdt"),
294362306a36Sopenharmony_ci	MFD_CELL_NAME("db8500-cpuidle"),
294462306a36Sopenharmony_ci};
294562306a36Sopenharmony_ci
294662306a36Sopenharmony_cistatic const struct mfd_cell db8500_prcmu_devs[] = {
294762306a36Sopenharmony_ci	MFD_CELL_OF("db8500-prcmu-regulators", NULL,
294862306a36Sopenharmony_ci		    &db8500_regulators, sizeof(db8500_regulators), 0,
294962306a36Sopenharmony_ci		    "stericsson,db8500-prcmu-regulator"),
295062306a36Sopenharmony_ci	MFD_CELL_OF("db8500-thermal",
295162306a36Sopenharmony_ci		    NULL, NULL, 0, 0, "stericsson,db8500-thermal"),
295262306a36Sopenharmony_ci};
295362306a36Sopenharmony_ci
295462306a36Sopenharmony_cistatic int db8500_prcmu_register_ab8500(struct device *parent)
295562306a36Sopenharmony_ci{
295662306a36Sopenharmony_ci	struct device_node *np;
295762306a36Sopenharmony_ci	struct resource ab850x_resource;
295862306a36Sopenharmony_ci	const struct mfd_cell ab8500_cell = {
295962306a36Sopenharmony_ci		.name = "ab8500-core",
296062306a36Sopenharmony_ci		.of_compatible = "stericsson,ab8500",
296162306a36Sopenharmony_ci		.id = AB8500_VERSION_AB8500,
296262306a36Sopenharmony_ci		.resources = &ab850x_resource,
296362306a36Sopenharmony_ci		.num_resources = 1,
296462306a36Sopenharmony_ci	};
296562306a36Sopenharmony_ci	const struct mfd_cell ab8505_cell = {
296662306a36Sopenharmony_ci		.name = "ab8505-core",
296762306a36Sopenharmony_ci		.of_compatible = "stericsson,ab8505",
296862306a36Sopenharmony_ci		.id = AB8500_VERSION_AB8505,
296962306a36Sopenharmony_ci		.resources = &ab850x_resource,
297062306a36Sopenharmony_ci		.num_resources = 1,
297162306a36Sopenharmony_ci	};
297262306a36Sopenharmony_ci	const struct mfd_cell *ab850x_cell;
297362306a36Sopenharmony_ci
297462306a36Sopenharmony_ci	if (!parent->of_node)
297562306a36Sopenharmony_ci		return -ENODEV;
297662306a36Sopenharmony_ci
297762306a36Sopenharmony_ci	/* Look up the device node, sneak the IRQ out of it */
297862306a36Sopenharmony_ci	for_each_child_of_node(parent->of_node, np) {
297962306a36Sopenharmony_ci		if (of_device_is_compatible(np, ab8500_cell.of_compatible)) {
298062306a36Sopenharmony_ci			ab850x_cell = &ab8500_cell;
298162306a36Sopenharmony_ci			break;
298262306a36Sopenharmony_ci		}
298362306a36Sopenharmony_ci		if (of_device_is_compatible(np, ab8505_cell.of_compatible)) {
298462306a36Sopenharmony_ci			ab850x_cell = &ab8505_cell;
298562306a36Sopenharmony_ci			break;
298662306a36Sopenharmony_ci		}
298762306a36Sopenharmony_ci	}
298862306a36Sopenharmony_ci	if (!np) {
298962306a36Sopenharmony_ci		dev_info(parent, "could not find AB850X node in the device tree\n");
299062306a36Sopenharmony_ci		return -ENODEV;
299162306a36Sopenharmony_ci	}
299262306a36Sopenharmony_ci	of_irq_to_resource_table(np, &ab850x_resource, 1);
299362306a36Sopenharmony_ci
299462306a36Sopenharmony_ci	return mfd_add_devices(parent, 0, ab850x_cell, 1, NULL, 0, NULL);
299562306a36Sopenharmony_ci}
299662306a36Sopenharmony_ci
299762306a36Sopenharmony_cistatic int db8500_prcmu_probe(struct platform_device *pdev)
299862306a36Sopenharmony_ci{
299962306a36Sopenharmony_ci	struct device_node *np = pdev->dev.of_node;
300062306a36Sopenharmony_ci	int irq = 0, err = 0;
300162306a36Sopenharmony_ci	struct resource *res;
300262306a36Sopenharmony_ci
300362306a36Sopenharmony_ci	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "prcmu");
300462306a36Sopenharmony_ci	if (!res) {
300562306a36Sopenharmony_ci		dev_err(&pdev->dev, "no prcmu memory region provided\n");
300662306a36Sopenharmony_ci		return -EINVAL;
300762306a36Sopenharmony_ci	}
300862306a36Sopenharmony_ci	prcmu_base = devm_ioremap(&pdev->dev, res->start, resource_size(res));
300962306a36Sopenharmony_ci	if (!prcmu_base) {
301062306a36Sopenharmony_ci		dev_err(&pdev->dev,
301162306a36Sopenharmony_ci			"failed to ioremap prcmu register memory\n");
301262306a36Sopenharmony_ci		return -ENOMEM;
301362306a36Sopenharmony_ci	}
301462306a36Sopenharmony_ci	init_prcm_registers();
301562306a36Sopenharmony_ci	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "prcmu-tcdm");
301662306a36Sopenharmony_ci	if (!res) {
301762306a36Sopenharmony_ci		dev_err(&pdev->dev, "no prcmu tcdm region provided\n");
301862306a36Sopenharmony_ci		return -EINVAL;
301962306a36Sopenharmony_ci	}
302062306a36Sopenharmony_ci	tcdm_base = devm_ioremap(&pdev->dev, res->start,
302162306a36Sopenharmony_ci			resource_size(res));
302262306a36Sopenharmony_ci	if (!tcdm_base) {
302362306a36Sopenharmony_ci		dev_err(&pdev->dev,
302462306a36Sopenharmony_ci			"failed to ioremap prcmu-tcdm register memory\n");
302562306a36Sopenharmony_ci		return -ENOMEM;
302662306a36Sopenharmony_ci	}
302762306a36Sopenharmony_ci
302862306a36Sopenharmony_ci	/* Clean up the mailbox interrupts after pre-kernel code. */
302962306a36Sopenharmony_ci	writel(ALL_MBOX_BITS, PRCM_ARM_IT1_CLR);
303062306a36Sopenharmony_ci
303162306a36Sopenharmony_ci	irq = platform_get_irq(pdev, 0);
303262306a36Sopenharmony_ci	if (irq <= 0)
303362306a36Sopenharmony_ci		return irq;
303462306a36Sopenharmony_ci
303562306a36Sopenharmony_ci	err = request_threaded_irq(irq, prcmu_irq_handler,
303662306a36Sopenharmony_ci	        prcmu_irq_thread_fn, IRQF_NO_SUSPEND, "prcmu", NULL);
303762306a36Sopenharmony_ci	if (err < 0) {
303862306a36Sopenharmony_ci		pr_err("prcmu: Failed to allocate IRQ_DB8500_PRCMU1.\n");
303962306a36Sopenharmony_ci		return err;
304062306a36Sopenharmony_ci	}
304162306a36Sopenharmony_ci
304262306a36Sopenharmony_ci	db8500_irq_init(np);
304362306a36Sopenharmony_ci
304462306a36Sopenharmony_ci	prcmu_config_esram0_deep_sleep(ESRAM0_DEEP_SLEEP_STATE_RET);
304562306a36Sopenharmony_ci
304662306a36Sopenharmony_ci	err = mfd_add_devices(&pdev->dev, 0, common_prcmu_devs,
304762306a36Sopenharmony_ci			      ARRAY_SIZE(common_prcmu_devs), NULL, 0, db8500_irq_domain);
304862306a36Sopenharmony_ci	if (err) {
304962306a36Sopenharmony_ci		pr_err("prcmu: Failed to add subdevices\n");
305062306a36Sopenharmony_ci		return err;
305162306a36Sopenharmony_ci	}
305262306a36Sopenharmony_ci
305362306a36Sopenharmony_ci	/* TODO: Remove restriction when clk definitions are available. */
305462306a36Sopenharmony_ci	if (!of_machine_is_compatible("st-ericsson,u8540")) {
305562306a36Sopenharmony_ci		err = mfd_add_devices(&pdev->dev, 0, db8500_prcmu_devs,
305662306a36Sopenharmony_ci				      ARRAY_SIZE(db8500_prcmu_devs), NULL, 0,
305762306a36Sopenharmony_ci				      db8500_irq_domain);
305862306a36Sopenharmony_ci		if (err) {
305962306a36Sopenharmony_ci			mfd_remove_devices(&pdev->dev);
306062306a36Sopenharmony_ci			pr_err("prcmu: Failed to add subdevices\n");
306162306a36Sopenharmony_ci			return err;
306262306a36Sopenharmony_ci		}
306362306a36Sopenharmony_ci	}
306462306a36Sopenharmony_ci
306562306a36Sopenharmony_ci	err = db8500_prcmu_register_ab8500(&pdev->dev);
306662306a36Sopenharmony_ci	if (err) {
306762306a36Sopenharmony_ci		mfd_remove_devices(&pdev->dev);
306862306a36Sopenharmony_ci		pr_err("prcmu: Failed to add ab8500 subdevice\n");
306962306a36Sopenharmony_ci		return err;
307062306a36Sopenharmony_ci	}
307162306a36Sopenharmony_ci
307262306a36Sopenharmony_ci	pr_info("DB8500 PRCMU initialized\n");
307362306a36Sopenharmony_ci	return err;
307462306a36Sopenharmony_ci}
307562306a36Sopenharmony_cistatic const struct of_device_id db8500_prcmu_match[] = {
307662306a36Sopenharmony_ci	{ .compatible = "stericsson,db8500-prcmu"},
307762306a36Sopenharmony_ci	{ },
307862306a36Sopenharmony_ci};
307962306a36Sopenharmony_ci
308062306a36Sopenharmony_cistatic struct platform_driver db8500_prcmu_driver = {
308162306a36Sopenharmony_ci	.driver = {
308262306a36Sopenharmony_ci		.name = "db8500-prcmu",
308362306a36Sopenharmony_ci		.of_match_table = db8500_prcmu_match,
308462306a36Sopenharmony_ci	},
308562306a36Sopenharmony_ci	.probe = db8500_prcmu_probe,
308662306a36Sopenharmony_ci};
308762306a36Sopenharmony_ci
308862306a36Sopenharmony_cistatic int __init db8500_prcmu_init(void)
308962306a36Sopenharmony_ci{
309062306a36Sopenharmony_ci	return platform_driver_register(&db8500_prcmu_driver);
309162306a36Sopenharmony_ci}
309262306a36Sopenharmony_cicore_initcall(db8500_prcmu_init);
3093