Merge branch 'for-torvalds' of git://git.kernel.org/pub/scm/linux/kernel/git/linusw/linux-stericsson

* 'for-torvalds' of git://git.kernel.org/pub/scm/linux/kernel/git/linusw/linux-stericsson:
  mach-ux500: voltage domain regulators for DB8500
  cpufreq: make DB8500 cpufreq driver compile
  cpufreq: update DB8500 cpufreq driver
  mach-ux500: move CPUfreq driver to cpufreq subsystem
  mfd: add DB5500 PRCMU driver
  mfd: update DB8500 PRCMU driver
  mach-ux500: move the DB8500 PRCMU driver to MFD
  mach-ux500: make PRCMU base address dynamic
  mach-ux500: rename PRCMU driver per SoC
  mach-ux500: update ASIC version detection
  mach-ux500: update SoC and board IRQ handling
  mach-ux500: update the DB5500 register file
  mach-ux500: update the DB8500 register file
This commit is contained in:
Linus Torvalds 2011-05-25 15:35:03 -07:00
commit ad363e0916
33 changed files with 4755 additions and 707 deletions

View File

@ -12,9 +12,12 @@ menu "Ux500 SoC"
config UX500_SOC_DB5500
bool "DB5500"
select MFD_DB5500_PRCMU
config UX500_SOC_DB8500
bool "DB8500"
select MFD_DB8500_PRCMU
select REGULATOR_DB8500_PRCMU
endmenu

View File

@ -5,7 +5,7 @@
obj-y := clock.o cpu.o devices.o devices-common.o \
id.o usb.o
obj-$(CONFIG_UX500_SOC_DB5500) += cpu-db5500.o dma-db5500.o
obj-$(CONFIG_UX500_SOC_DB8500) += cpu-db8500.o devices-db8500.o prcmu.o
obj-$(CONFIG_UX500_SOC_DB8500) += cpu-db8500.o devices-db8500.o
obj-$(CONFIG_MACH_U8500) += board-mop500.o board-mop500-sdi.o \
board-mop500-regulators.o \
board-mop500-uib.o board-mop500-stuib.o \
@ -17,4 +17,4 @@ obj-$(CONFIG_HOTPLUG_CPU) += hotplug.o
obj-$(CONFIG_LOCAL_TIMERS) += localtimer.o
obj-$(CONFIG_U5500_MODEM_IRQ) += modem-irq-db5500.o
obj-$(CONFIG_U5500_MBOX) += mbox-db5500.o
obj-$(CONFIG_CPU_FREQ) += cpufreq.o

View File

@ -188,6 +188,8 @@ void __init u5500_map_io(void)
ux500_map_io();
iotable_init(u5500_io_desc, ARRAY_SIZE(u5500_io_desc));
_PRCMU_BASE = __io_address(U5500_PRCMU_BASE);
}
static int usb_db5500_rx_dma_cfg[] = {

View File

@ -87,6 +87,8 @@ void __init u8500_map_io(void)
iotable_init(u8500_v1_io_desc, ARRAY_SIZE(u8500_v1_io_desc));
else if (cpu_is_u8500v2())
iotable_init(u8500_v2_io_desc, ARRAY_SIZE(u8500_v2_io_desc));
_PRCMU_BASE = __io_address(U8500_PRCMU_BASE);
}
static struct resource db8500_pmu_resources[] = {
@ -129,9 +131,14 @@ static struct platform_device db8500_pmu_device = {
.dev.platform_data = &db8500_pmu_platdata,
};
static struct platform_device db8500_prcmu_device = {
.name = "db8500-prcmu",
};
static struct platform_device *platform_devs[] __initdata = {
&u8500_dma40_device,
&db8500_pmu_device,
&db8500_prcmu_device,
};
static resource_size_t __initdata db8500_gpio_base[] = {

View File

@ -8,6 +8,8 @@
#include <linux/platform_device.h>
#include <linux/io.h>
#include <linux/clk.h>
#include <linux/mfd/db8500-prcmu.h>
#include <linux/mfd/db5500-prcmu.h>
#include <asm/cacheflush.h>
#include <asm/hardware/cache-l2x0.h>
@ -19,10 +21,11 @@
#include <mach/hardware.h>
#include <mach/setup.h>
#include <mach/devices.h>
#include <mach/prcmu.h>
#include "clock.h"
void __iomem *_PRCMU_BASE;
#ifdef CONFIG_CACHE_L2X0
static void __iomem *l2x0_base;
#endif
@ -47,6 +50,8 @@ void __init ux500_init_irq(void)
* Init clocks here so that they are available for system timer
* initialization.
*/
if (cpu_is_u5500())
db5500_prcmu_early_init();
if (cpu_is_u8500())
prcmu_early_init();
clk_init();

View File

@ -1,211 +0,0 @@
/*
* CPU frequency scaling for u8500
* Inspired by linux/arch/arm/mach-davinci/cpufreq.c
*
* Copyright (C) STMicroelectronics 2009
* Copyright (C) ST-Ericsson SA 2010
*
* License Terms: GNU General Public License v2
*
* Author: Sundar Iyer <sundar.iyer@stericsson.com>
* Author: Martin Persson <martin.persson@stericsson.com>
* Author: Jonas Aaberg <jonas.aberg@stericsson.com>
*
*/
#include <linux/platform_device.h>
#include <linux/kernel.h>
#include <linux/cpufreq.h>
#include <linux/delay.h>
#include <mach/hardware.h>
#include <mach/prcmu.h>
#include <mach/prcmu-defs.h>
#define DRIVER_NAME "cpufreq-u8500"
#define CPUFREQ_NAME "u8500"
static struct device *dev;
static struct cpufreq_frequency_table freq_table[] = {
[0] = {
.index = 0,
.frequency = 200000,
},
[1] = {
.index = 1,
.frequency = 300000,
},
[2] = {
.index = 2,
.frequency = 600000,
},
[3] = {
/* Used for CPU_OPP_MAX, if available */
.index = 3,
.frequency = CPUFREQ_TABLE_END,
},
[4] = {
.index = 4,
.frequency = CPUFREQ_TABLE_END,
},
};
static enum prcmu_cpu_opp index2opp[] = {
CPU_OPP_EXT_CLK,
CPU_OPP_50,
CPU_OPP_100,
CPU_OPP_MAX
};
static int u8500_cpufreq_verify_speed(struct cpufreq_policy *policy)
{
return cpufreq_frequency_table_verify(policy, freq_table);
}
static int u8500_cpufreq_target(struct cpufreq_policy *policy,
unsigned int target_freq,
unsigned int relation)
{
struct cpufreq_freqs freqs;
unsigned int index;
int ret = 0;
/*
* Ensure desired rate is within allowed range. Some govenors
* (ondemand) will just pass target_freq=0 to get the minimum.
*/
if (target_freq < policy->cpuinfo.min_freq)
target_freq = policy->cpuinfo.min_freq;
if (target_freq > policy->cpuinfo.max_freq)
target_freq = policy->cpuinfo.max_freq;
ret = cpufreq_frequency_table_target(policy, freq_table,
target_freq, relation, &index);
if (ret < 0) {
dev_err(dev, "Could not look up next frequency\n");
return ret;
}
freqs.old = policy->cur;
freqs.new = freq_table[index].frequency;
freqs.cpu = policy->cpu;
if (freqs.old == freqs.new) {
dev_dbg(dev, "Current and target frequencies are equal\n");
return 0;
}
dev_dbg(dev, "transition: %u --> %u\n", freqs.old, freqs.new);
cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
ret = prcmu_set_cpu_opp(index2opp[index]);
if (ret < 0) {
dev_err(dev, "Failed to set OPP level\n");
return ret;
}
cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
return ret;
}
static unsigned int u8500_cpufreq_getspeed(unsigned int cpu)
{
int i;
for (i = 0; prcmu_get_cpu_opp() != index2opp[i]; i++)
;
return freq_table[i].frequency;
}
static int __cpuinit u8500_cpu_init(struct cpufreq_policy *policy)
{
int res;
BUILD_BUG_ON(ARRAY_SIZE(index2opp) + 1 != ARRAY_SIZE(freq_table));
if (cpu_is_u8500v2()) {
freq_table[1].frequency = 400000;
freq_table[2].frequency = 800000;
if (prcmu_has_arm_maxopp())
freq_table[3].frequency = 1000000;
}
/* get policy fields based on the table */
res = cpufreq_frequency_table_cpuinfo(policy, freq_table);
if (!res)
cpufreq_frequency_table_get_attr(freq_table, policy->cpu);
else {
dev_err(dev, "u8500-cpufreq : Failed to read policy table\n");
return res;
}
policy->min = policy->cpuinfo.min_freq;
policy->max = policy->cpuinfo.max_freq;
policy->cur = u8500_cpufreq_getspeed(policy->cpu);
policy->governor = CPUFREQ_DEFAULT_GOVERNOR;
/*
* FIXME : Need to take time measurement across the target()
* function with no/some/all drivers in the notification
* list.
*/
policy->cpuinfo.transition_latency = 200 * 1000; /* in ns */
/* policy sharing between dual CPUs */
cpumask_copy(policy->cpus, &cpu_present_map);
policy->shared_type = CPUFREQ_SHARED_TYPE_ALL;
return res;
}
static struct freq_attr *u8500_cpufreq_attr[] = {
&cpufreq_freq_attr_scaling_available_freqs,
NULL,
};
static int u8500_cpu_exit(struct cpufreq_policy *policy)
{
cpufreq_frequency_table_put_attr(policy->cpu);
return 0;
}
static struct cpufreq_driver u8500_driver = {
.owner = THIS_MODULE,
.flags = CPUFREQ_STICKY,
.verify = u8500_cpufreq_verify_speed,
.target = u8500_cpufreq_target,
.get = u8500_cpufreq_getspeed,
.init = u8500_cpu_init,
.exit = u8500_cpu_exit,
.name = CPUFREQ_NAME,
.attr = u8500_cpufreq_attr,
};
static int __init u8500_cpufreq_probe(struct platform_device *pdev)
{
dev = &pdev->dev;
return cpufreq_register_driver(&u8500_driver);
}
static int __exit u8500_cpufreq_remove(struct platform_device *pdev)
{
return cpufreq_unregister_driver(&u8500_driver);
}
static struct platform_driver u8500_cpufreq_driver = {
.driver = {
.name = DRIVER_NAME,
.owner = THIS_MODULE,
},
.remove = __exit_p(u8500_cpufreq_remove),
};
static int __init u8500_cpufreq_init(void)
{
return platform_driver_probe(&u8500_cpufreq_driver,
&u8500_cpufreq_probe);
}
device_initcall(u8500_cpufreq_init);

View File

@ -17,6 +17,8 @@
#define U5500_GIC_DIST_BASE 0xA0411000
#define U5500_GIC_CPU_BASE 0xA0410100
#define U5500_DMA_BASE 0x90030000
#define U5500_STM_BASE 0x90020000
#define U5500_STM_REG_BASE (U5500_STM_BASE + 0xF000)
#define U5500_MCDE_BASE 0xA0400000
#define U5500_MODEM_BASE 0xB0000000
#define U5500_L2CC_BASE 0xA0412000
@ -29,7 +31,9 @@
#define U5500_NAND0_BASE 0x60000000
#define U5500_NAND1_BASE 0x70000000
#define U5500_TWD_BASE 0xa0410600
#define U5500_ICN_BASE 0xA0040000
#define U5500_B2R2_BASE 0xa0200000
#define U5500_BOOT_ROM_BASE 0x90000000
#define U5500_FSMC_BASE (U5500_PER1_BASE + 0x0000)
#define U5500_SDI0_BASE (U5500_PER1_BASE + 0x1000)
@ -60,6 +64,7 @@
#define U5500_MSP1_BASE (U5500_PER4_BASE + 0x9000)
#define U5500_GPIO2_BASE (U5500_PER4_BASE + 0xA000)
#define U5500_CDETECT_BASE (U5500_PER4_BASE + 0xF000)
#define U5500_PRCMU_TCDM_BASE (U5500_PER4_BASE + 0x18000)
#define U5500_SPI0_BASE (U5500_PER5_BASE + 0x0000)
#define U5500_SPI1_BASE (U5500_PER5_BASE + 0x1000)
@ -83,7 +88,7 @@
#define U5500_HASH0_BASE (U5500_PER6_BASE + 0x1000)
#define U5500_HASH1_BASE (U5500_PER6_BASE + 0x2000)
#define U5500_PKA_BASE (U5500_PER6_BASE + 0x4000)
#define U5500_PKAM_BASE (U5500_PER6_BASE + 0x5000)
#define U5500_PKAM_BASE (U5500_PER6_BASE + 0x5100)
#define U5500_MTU0_BASE (U5500_PER6_BASE + 0x6000)
#define U5500_MTU1_BASE (U5500_PER6_BASE + 0x7000)
#define U5500_CR_BASE (U5500_PER6_BASE + 0x8000)
@ -114,8 +119,19 @@
#define U5500_MBOX2_LOCAL_START (U5500_MBOX_BASE + 0x20)
#define U5500_MBOX2_LOCAL_END (U5500_MBOX_BASE + 0x3F)
#define U5500_ACCCON_BASE_SEC (0xBFFF0000)
#define U5500_ACCCON_BASE (0xBFFF1000)
#define U5500_ACCCON_CPUVEC_RESET_ADDR_OFFSET (0x00000020)
#define U5500_ACCCON_ACC_CPU_CTRL_OFFSET (0x000000BC)
#define U5500_ESRAM_BASE 0x40000000
#define U5500_ESRAM_DMA_LCPA_OFFSET 0x10000
#define U5500_DMA_LCPA_BASE (U5500_ESRAM_BASE + U5500_ESRAM_DMA_LCPA_OFFSET)
#define U5500_MCDE_SIZE 0x1000
#define U5500_DSI_LINK_SIZE 0x1000
#define U5500_DSI_LINK_COUNT 0x2
#define U5500_DSI_LINK1_BASE (U5500_MCDE_BASE + U5500_MCDE_SIZE)
#define U5500_DSI_LINK2_BASE (U5500_DSI_LINK1_BASE + U5500_DSI_LINK_SIZE)
#endif

View File

@ -15,8 +15,13 @@
#define U8500_ESRAM_BANK2 (U8500_ESRAM_BANK1 + U8500_ESRAM_BANK_SIZE)
#define U8500_ESRAM_BANK3 (U8500_ESRAM_BANK2 + U8500_ESRAM_BANK_SIZE)
#define U8500_ESRAM_BANK4 (U8500_ESRAM_BANK3 + U8500_ESRAM_BANK_SIZE)
/* Use bank 4 for DMA LCPA */
#define U8500_DMA_LCPA_BASE U8500_ESRAM_BANK4
/*
* on V1 DMA uses 4KB for logical parameters position is right after the 64KB
* reserved for security
*/
#define U8500_ESRAM_DMA_LCPA_OFFSET 0x10000
#define U8500_DMA_LCPA_BASE (U8500_ESRAM_BANK0 + U8500_ESRAM_DMA_LCPA_OFFSET)
#define U8500_DMA_LCPA_BASE_ED (U8500_ESRAM_BANK4 + 0x4000)
#define U8500_PER3_BASE 0x80000000
@ -27,9 +32,12 @@
#define U8500_B2R2_BASE 0x80130000
#define U8500_HSEM_BASE 0x80140000
#define U8500_PER4_BASE 0x80150000
#define U8500_TPIU_BASE 0x80190000
#define U8500_ICN_BASE 0x81000000
#define U8500_BOOT_ROM_BASE 0x90000000
/* ASIC ID is at 0xbf4 offset within this region */
#define U8500_ASIC_ID_BASE 0x9001D000
#define U8500_PER6_BASE 0xa03c0000
#define U8500_PER5_BASE 0xa03e0000
@ -70,13 +78,15 @@
/* per6 base addresses */
#define U8500_RNG_BASE (U8500_PER6_BASE + 0x0000)
#define U8500_PKA_BASE (U8500_PER6_BASE + 0x1000)
#define U8500_PKAM_BASE (U8500_PER6_BASE + 0x2000)
#define U8500_HASH0_BASE (U8500_PER6_BASE + 0x1000)
#define U8500_HASH1_BASE (U8500_PER6_BASE + 0x2000)
#define U8500_PKA_BASE (U8500_PER6_BASE + 0x4000)
#define U8500_PKAM_BASE (U8500_PER6_BASE + 0x5100)
#define U8500_MTU0_BASE (U8500_PER6_BASE + 0x6000) /* v1 */
#define U8500_MTU1_BASE (U8500_PER6_BASE + 0x7000) /* v1 */
#define U8500_CR_BASE (U8500_PER6_BASE + 0x8000) /* v1 */
#define U8500_CRYPTO0_BASE (U8500_PER6_BASE + 0xa000)
#define U8500_CRYPTO1_BASE (U8500_PER6_BASE + 0xb000)
#define U8500_CRYP0_BASE (U8500_PER6_BASE + 0xa000)
#define U8500_CRYP1_BASE (U8500_PER6_BASE + 0xb000)
#define U8500_CLKRST6_BASE (U8500_PER6_BASE + 0xf000)
/* per5 base addresses */
@ -94,6 +104,7 @@
#define U8500_PRCMU_BASE (U8500_PER4_BASE + 0x07000)
#define U8500_PRCMU_TCDM_BASE_V1 (U8500_PER4_BASE + 0x0f000)
#define U8500_PRCMU_TCDM_BASE (U8500_PER4_BASE + 0x68000)
#define U8500_PRCMU_TCPM_BASE (U8500_PER4_BASE + 0x60000)
/* per3 base addresses */
#define U8500_FSMC_BASE (U8500_PER3_BASE + 0x0000)
@ -124,6 +135,7 @@
#define U8500_I2C1_BASE (U8500_PER1_BASE + 0x2000)
#define U8500_MSP0_BASE (U8500_PER1_BASE + 0x3000)
#define U8500_MSP1_BASE (U8500_PER1_BASE + 0x4000)
#define U8500_MSP3_BASE (U8500_PER1_BASE + 0x5000)
#define U8500_SDI0_BASE (U8500_PER1_BASE + 0x6000)
#define U8500_I2C2_BASE (U8500_PER1_BASE + 0x8000)
#define U8500_SPI3_BASE (U8500_PER1_BASE + 0x9000)
@ -143,4 +155,15 @@
#define U8500_GPIOBANK7_BASE (U8500_GPIO2_BASE + 0x80)
#define U8500_GPIOBANK8_BASE U8500_GPIO3_BASE
#define U8500_MCDE_SIZE 0x1000
#define U8500_DSI_LINK_SIZE 0x1000
#define U8500_DSI_LINK1_BASE (U8500_MCDE_BASE + U8500_MCDE_SIZE)
#define U8500_DSI_LINK2_BASE (U8500_DSI_LINK1_BASE + U8500_DSI_LINK_SIZE)
#define U8500_DSI_LINK3_BASE (U8500_DSI_LINK2_BASE + U8500_DSI_LINK_SIZE)
#define U8500_DSI_LINK_COUNT 0x3
/* Modem and APE physical addresses */
#define U8500_MODEM_BASE 0xe000000
#define U8500_APE_BASE 0x6000000
#endif

View File

@ -35,6 +35,7 @@
#ifndef __ASSEMBLY__
#include <mach/id.h>
extern void __iomem *_PRCMU_BASE;
#define ARRAY_AND_SIZE(x) (x), ARRAY_SIZE(x)

View File

@ -75,6 +75,26 @@ static inline bool __attribute_const__ cpu_is_u8500v2(void)
return cpu_is_u8500() && ((dbx500_revision() & 0xf0) == 0xB0);
}
static inline bool cpu_is_u8500v20(void)
{
return cpu_is_u8500() && (dbx500_revision() == 0xB0);
}
static inline bool cpu_is_u8500v21(void)
{
return cpu_is_u8500() && (dbx500_revision() == 0xB1);
}
static inline bool cpu_is_u8500v20_or_later(void)
{
return cpu_is_u8500() && !cpu_is_u8500v10() && !cpu_is_u8500v11();
}
static inline bool ux500_is_svp(void)
{
return false;
}
#define ux500_unknown_soc() BUG()
#endif

View File

@ -50,6 +50,11 @@
#define MOP500_IRQ_END MOP500_NR_IRQS
/*
* We may have several boards, but only one will run at a
* time, so the one with most IRQs will bump this ahead,
* but the IRQ_BOARD_START remains the same for either board.
*/
#if MOP500_IRQ_END > IRQ_BOARD_END
#undef IRQ_BOARD_END
#define IRQ_BOARD_END MOP500_IRQ_END

View File

@ -0,0 +1,21 @@
/*
* Copyright (C) ST-Ericsson SA 2010
*
* License terms: GNU General Public License (GPL) version 2
*/
#ifndef __MACH_IRQS_BOARD_U5500_H
#define __MACH_IRQS_BOARD_U5500_H
#define AB5500_NR_IRQS 5
#define IRQ_AB5500_BASE IRQ_BOARD_START
#define IRQ_AB5500_END (IRQ_AB5500_BASE + AB5500_NR_IRQS)
#define U5500_IRQ_END IRQ_AB5500_END
#if IRQ_BOARD_END < U5500_IRQ_END
#undef IRQ_BOARD_END
#define IRQ_BOARD_END U5500_IRQ_END
#endif
#endif

View File

@ -83,4 +83,31 @@
#define IRQ_DB5500_GPIO6 (IRQ_SHPI_START + 125)
#define IRQ_DB5500_GPIO7 (IRQ_SHPI_START + 126)
#ifdef CONFIG_UX500_SOC_DB5500
/*
* After the GPIO ones we reserve a range of IRQ:s in which virtual
* IRQ:s representing modem IRQ:s can be allocated
*/
#define IRQ_MODEM_EVENTS_BASE IRQ_SOC_START
#define IRQ_MODEM_EVENTS_NBR 72
#define IRQ_MODEM_EVENTS_END (IRQ_MODEM_EVENTS_BASE + IRQ_MODEM_EVENTS_NBR)
/* List of virtual IRQ:s that are allocated from the range above */
#define MBOX_PAIR0_VIRT_IRQ (IRQ_MODEM_EVENTS_BASE + 43)
#define MBOX_PAIR1_VIRT_IRQ (IRQ_MODEM_EVENTS_BASE + 45)
#define MBOX_PAIR2_VIRT_IRQ (IRQ_MODEM_EVENTS_BASE + 41)
/*
* We may have several SoCs, but only one will run at a
* time, so the one with most IRQs will bump this ahead,
* but the IRQ_SOC_START remains the same for either SoC.
*/
#if IRQ_SOC_END < IRQ_MODEM_EVENTS_END
#undef IRQ_SOC_END
#define IRQ_SOC_END IRQ_MODEM_EVENTS_END
#endif
#endif /* CONFIG_UX500_SOC_DB5500 */
#endif

View File

@ -93,4 +93,58 @@
#define IRQ_DB8500_GPIO7 (IRQ_SHPI_START + 126)
#define IRQ_DB8500_GPIO8 (IRQ_SHPI_START + 127)
#define IRQ_CA_WAKE_REQ_ED (IRQ_SHPI_START + 71)
#define IRQ_AC_READ_NOTIFICATION_0_ED (IRQ_SHPI_START + 66)
#define IRQ_AC_READ_NOTIFICATION_1_ED (IRQ_SHPI_START + 64)
#define IRQ_CA_MSG_PEND_NOTIFICATION_0_ED (IRQ_SHPI_START + 67)
#define IRQ_CA_MSG_PEND_NOTIFICATION_1_ED (IRQ_SHPI_START + 65)
#define IRQ_CA_WAKE_REQ_V1 (IRQ_SHPI_START + 83)
#define IRQ_AC_READ_NOTIFICATION_0_V1 (IRQ_SHPI_START + 78)
#define IRQ_AC_READ_NOTIFICATION_1_V1 (IRQ_SHPI_START + 76)
#define IRQ_CA_MSG_PEND_NOTIFICATION_0_V1 (IRQ_SHPI_START + 79)
#define IRQ_CA_MSG_PEND_NOTIFICATION_1_V1 (IRQ_SHPI_START + 77)
#ifdef CONFIG_UX500_SOC_DB8500
/* Virtual interrupts corresponding to the PRCMU wakeups. */
#define IRQ_PRCMU_BASE IRQ_SOC_START
#define NUM_PRCMU_WAKEUPS (IRQ_PRCMU_END - IRQ_PRCMU_BASE)
#define IRQ_PRCMU_RTC (IRQ_PRCMU_BASE)
#define IRQ_PRCMU_RTT0 (IRQ_PRCMU_BASE + 1)
#define IRQ_PRCMU_RTT1 (IRQ_PRCMU_BASE + 2)
#define IRQ_PRCMU_HSI0 (IRQ_PRCMU_BASE + 3)
#define IRQ_PRCMU_HSI1 (IRQ_PRCMU_BASE + 4)
#define IRQ_PRCMU_CA_WAKE (IRQ_PRCMU_BASE + 5)
#define IRQ_PRCMU_USB (IRQ_PRCMU_BASE + 6)
#define IRQ_PRCMU_ABB (IRQ_PRCMU_BASE + 7)
#define IRQ_PRCMU_ABB_FIFO (IRQ_PRCMU_BASE + 8)
#define IRQ_PRCMU_ARM (IRQ_PRCMU_BASE + 9)
#define IRQ_PRCMU_MODEM_SW_RESET_REQ (IRQ_PRCMU_BASE + 10)
#define IRQ_PRCMU_GPIO0 (IRQ_PRCMU_BASE + 11)
#define IRQ_PRCMU_GPIO1 (IRQ_PRCMU_BASE + 12)
#define IRQ_PRCMU_GPIO2 (IRQ_PRCMU_BASE + 13)
#define IRQ_PRCMU_GPIO3 (IRQ_PRCMU_BASE + 14)
#define IRQ_PRCMU_GPIO4 (IRQ_PRCMU_BASE + 15)
#define IRQ_PRCMU_GPIO5 (IRQ_PRCMU_BASE + 16)
#define IRQ_PRCMU_GPIO6 (IRQ_PRCMU_BASE + 17)
#define IRQ_PRCMU_GPIO7 (IRQ_PRCMU_BASE + 18)
#define IRQ_PRCMU_GPIO8 (IRQ_PRCMU_BASE + 19)
#define IRQ_PRCMU_CA_SLEEP (IRQ_PRCMU_BASE + 20)
#define IRQ_PRCMU_HOTMON_LOW (IRQ_PRCMU_BASE + 21)
#define IRQ_PRCMU_HOTMON_HIGH (IRQ_PRCMU_BASE + 22)
#define IRQ_PRCMU_END (IRQ_PRCMU_BASE + 23)
/*
* We may have several SoCs, but only one will run at a
* time, so the one with most IRQs will bump this ahead,
* but the IRQ_SOC_START remains the same for either SoC.
*/
#if IRQ_SOC_END < IRQ_PRCMU_END
#undef IRQ_SOC_END
#define IRQ_SOC_END IRQ_PRCMU_END
#endif
#endif /* CONFIG_UX500_SOC_DB8500 */
#endif

View File

@ -10,8 +10,7 @@
#ifndef ASM_ARCH_IRQS_H
#define ASM_ARCH_IRQS_H
#include <mach/irqs-db5500.h>
#include <mach/irqs-db8500.h>
#include <mach/hardware.h>
#define IRQ_LOCALTIMER 29
#define IRQ_LOCALWDOG 30
@ -19,20 +18,28 @@
/* Shared Peripheral Interrupt (SHPI) */
#define IRQ_SHPI_START 32
/* Interrupt numbers generic for shared peripheral */
/*
* MTU0 preserved for now until plat-nomadik is taught not to use it. Don't
* add any other IRQs here, use the irqs-dbx500.h files.
*/
#define IRQ_MTU0 (IRQ_SHPI_START + 4)
/* There are 128 shared peripheral interrupts assigned to
* INTID[160:32]. The first 32 interrupts are reserved.
*/
#define DBX500_NR_INTERNAL_IRQS 161
#define DBX500_NR_INTERNAL_IRQS 160
/* After chip-specific IRQ numbers we have the GPIO ones */
#define NOMADIK_NR_GPIO 288
#define NOMADIK_GPIO_TO_IRQ(gpio) ((gpio) + DBX500_NR_INTERNAL_IRQS)
#define NOMADIK_IRQ_TO_GPIO(irq) ((irq) - DBX500_NR_INTERNAL_IRQS)
#define IRQ_BOARD_START NOMADIK_GPIO_TO_IRQ(NOMADIK_NR_GPIO)
#define IRQ_GPIO_END NOMADIK_GPIO_TO_IRQ(NOMADIK_NR_GPIO)
#define IRQ_SOC_START IRQ_GPIO_END
/* This will be overridden by SoC-specific irq headers */
#define IRQ_SOC_END IRQ_SOC_START
#include <mach/irqs-db5500.h>
#include <mach/irqs-db8500.h>
#define IRQ_BOARD_START IRQ_SOC_END
/* This will be overridden by board-specific irq headers */
#define IRQ_BOARD_END IRQ_BOARD_START
@ -40,19 +47,10 @@
#include <mach/irqs-board-mop500.h>
#endif
/*
* After the board specific IRQ:s we reserve a range of IRQ:s in which virtual
* IRQ:s representing modem IRQ:s can be allocated
*/
#define IRQ_MODEM_EVENTS_BASE (IRQ_BOARD_END + 1)
#define IRQ_MODEM_EVENTS_NBR 72
#define IRQ_MODEM_EVENTS_END (IRQ_MODEM_EVENTS_BASE + IRQ_MODEM_EVENTS_NBR)
#ifdef CONFIG_MACH_U5500
#include <mach/irqs-board-u5500.h>
#endif
/* List of virtual IRQ:s that are allocated from the range above */
#define MBOX_PAIR0_VIRT_IRQ (IRQ_MODEM_EVENTS_BASE + 43)
#define MBOX_PAIR1_VIRT_IRQ (IRQ_MODEM_EVENTS_BASE + 45)
#define MBOX_PAIR2_VIRT_IRQ (IRQ_MODEM_EVENTS_BASE + 41)
#define NR_IRQS IRQ_MODEM_EVENTS_END
#define NR_IRQS IRQ_BOARD_END
#endif /* ASM_ARCH_IRQS_H */

View File

@ -1,30 +0,0 @@
/*
* Copyright (C) STMicroelectronics 2009
* Copyright (C) ST-Ericsson SA 2010
*
* Author: Sundar Iyer <sundar.iyer@stericsson.com>
* Author: Martin Persson <martin.persson@stericsson.com>
*
* License Terms: GNU General Public License v2
*
* PRCM Unit definitions
*/
#ifndef __MACH_PRCMU_DEFS_H
#define __MACH_PRCMU_DEFS_H
enum prcmu_cpu_opp {
CPU_OPP_INIT = 0x00,
CPU_OPP_NO_CHANGE = 0x01,
CPU_OPP_100 = 0x02,
CPU_OPP_50 = 0x03,
CPU_OPP_MAX = 0x04,
CPU_OPP_EXT_CLK = 0x07
};
enum prcmu_ape_opp {
APE_OPP_NO_CHANGE = 0x00,
APE_OPP_100 = 0x02,
APE_OPP_50 = 0x03,
};
#endif /* __MACH_PRCMU_DEFS_H */

View File

@ -1,28 +0,0 @@
/*
* Copyright (C) STMicroelectronics 2009
* Copyright (C) ST-Ericsson SA 2010
*
* Author: Kumar Sanghvi <kumar.sanghvi@stericsson.com>
* Author: Sundar Iyer <sundar.iyer@stericsson.com>
* Author: Mattias Nilsson <mattias.i.nilsson@stericsson.com>
*
* License Terms: GNU General Public License v2
*
* PRCM Unit f/w API
*/
#ifndef __MACH_PRCMU_H
#define __MACH_PRCMU_H
#include <mach/prcmu-defs.h>
void __init prcmu_early_init(void);
int prcmu_abb_read(u8 slave, u8 reg, u8 *value, u8 size);
int prcmu_abb_write(u8 slave, u8 reg, u8 *value, u8 size);
int prcmu_set_ape_opp(enum prcmu_ape_opp opp);
int prcmu_set_cpu_opp(enum prcmu_cpu_opp opp);
int prcmu_set_ape_cpu_opps(enum prcmu_ape_opp ape_opp,
enum prcmu_cpu_opp cpu_opp);
int prcmu_get_ape_opp(void);
int prcmu_get_cpu_opp(void);
bool prcmu_has_arm_maxopp(void);
#endif /* __MACH_PRCMU_H */

View File

@ -1,394 +0,0 @@
/*
* Copyright (C) STMicroelectronics 2009
* Copyright (C) ST-Ericsson SA 2010
*
* License Terms: GNU General Public License v2
* Author: Kumar Sanghvi <kumar.sanghvi@stericsson.com>
* Author: Sundar Iyer <sundar.iyer@stericsson.com>
* Author: Mattias Nilsson <mattias.i.nilsson@stericsson.com>
*
* U8500 PRCM Unit interface driver
*
*/
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/errno.h>
#include <linux/err.h>
#include <linux/io.h>
#include <linux/mutex.h>
#include <linux/completion.h>
#include <linux/jiffies.h>
#include <linux/bitops.h>
#include <linux/interrupt.h>
#include <mach/hardware.h>
#include <mach/prcmu-regs.h>
#include <mach/prcmu-defs.h>
/* Global var to runtime determine TCDM base for v2 or v1 */
static __iomem void *tcdm_base;
#define _MBOX_HEADER (tcdm_base + 0xFE8)
#define MBOX_HEADER_REQ_MB0 (_MBOX_HEADER + 0x0)
#define REQ_MB1 (tcdm_base + 0xFD0)
#define REQ_MB5 (tcdm_base + 0xE44)
#define REQ_MB1_ARMOPP (REQ_MB1 + 0x0)
#define REQ_MB1_APEOPP (REQ_MB1 + 0x1)
#define REQ_MB1_BOOSTOPP (REQ_MB1 + 0x2)
#define ACK_MB1 (tcdm_base + 0xE04)
#define ACK_MB5 (tcdm_base + 0xDF4)
#define ACK_MB1_CURR_ARMOPP (ACK_MB1 + 0x0)
#define ACK_MB1_CURR_APEOPP (ACK_MB1 + 0x1)
#define REQ_MB5_I2C_SLAVE_OP (REQ_MB5)
#define REQ_MB5_I2C_HW_BITS (REQ_MB5 + 1)
#define REQ_MB5_I2C_REG (REQ_MB5 + 2)
#define REQ_MB5_I2C_VAL (REQ_MB5 + 3)
#define ACK_MB5_I2C_STATUS (ACK_MB5 + 1)
#define ACK_MB5_I2C_VAL (ACK_MB5 + 3)
#define PRCM_AVS_VARM_MAX_OPP (tcdm_base + 0x2E4)
#define PRCM_AVS_ISMODEENABLE 7
#define PRCM_AVS_ISMODEENABLE_MASK (1 << PRCM_AVS_ISMODEENABLE)
#define I2C_WRITE(slave) \
(((slave) << 1) | (cpu_is_u8500v2() ? BIT(6) : 0))
#define I2C_READ(slave) \
(((slave) << 1) | (cpu_is_u8500v2() ? BIT(6) : 0) | BIT(0))
#define I2C_STOP_EN BIT(3)
enum mb1_h {
MB1H_ARM_OPP = 1,
MB1H_APE_OPP,
MB1H_ARM_APE_OPP,
};
static struct {
struct mutex lock;
struct completion work;
struct {
u8 arm_opp;
u8 ape_opp;
u8 arm_status;
u8 ape_status;
} ack;
} mb1_transfer;
enum ack_mb5_status {
I2C_WR_OK = 0x01,
I2C_RD_OK = 0x02,
};
#define MBOX_BIT BIT
#define NUM_MBOX 8
static struct {
struct mutex lock;
struct completion work;
bool failed;
struct {
u8 status;
u8 value;
} ack;
} mb5_transfer;
/**
* prcmu_abb_read() - Read register value(s) from the ABB.
* @slave: The I2C slave address.
* @reg: The (start) register address.
* @value: The read out value(s).
* @size: The number of registers to read.
*
* Reads register value(s) from the ABB.
* @size has to be 1 for the current firmware version.
*/
int prcmu_abb_read(u8 slave, u8 reg, u8 *value, u8 size)
{
int r;
if (size != 1)
return -EINVAL;
r = mutex_lock_interruptible(&mb5_transfer.lock);
if (r)
return r;
while (readl(PRCM_MBOX_CPU_VAL) & MBOX_BIT(5))
cpu_relax();
writeb(I2C_READ(slave), REQ_MB5_I2C_SLAVE_OP);
writeb(I2C_STOP_EN, REQ_MB5_I2C_HW_BITS);
writeb(reg, REQ_MB5_I2C_REG);
writel(MBOX_BIT(5), PRCM_MBOX_CPU_SET);
if (!wait_for_completion_timeout(&mb5_transfer.work,
msecs_to_jiffies(500))) {
pr_err("prcmu: prcmu_abb_read timed out.\n");
r = -EIO;
goto unlock_and_return;
}
r = ((mb5_transfer.ack.status == I2C_RD_OK) ? 0 : -EIO);
if (!r)
*value = mb5_transfer.ack.value;
unlock_and_return:
mutex_unlock(&mb5_transfer.lock);
return r;
}
EXPORT_SYMBOL(prcmu_abb_read);
/**
* prcmu_abb_write() - Write register value(s) to the ABB.
* @slave: The I2C slave address.
* @reg: The (start) register address.
* @value: The value(s) to write.
* @size: The number of registers to write.
*
* Reads register value(s) from the ABB.
* @size has to be 1 for the current firmware version.
*/
int prcmu_abb_write(u8 slave, u8 reg, u8 *value, u8 size)
{
int r;
if (size != 1)
return -EINVAL;
r = mutex_lock_interruptible(&mb5_transfer.lock);
if (r)
return r;
while (readl(PRCM_MBOX_CPU_VAL) & MBOX_BIT(5))
cpu_relax();
writeb(I2C_WRITE(slave), REQ_MB5_I2C_SLAVE_OP);
writeb(I2C_STOP_EN, REQ_MB5_I2C_HW_BITS);
writeb(reg, REQ_MB5_I2C_REG);
writeb(*value, REQ_MB5_I2C_VAL);
writel(MBOX_BIT(5), PRCM_MBOX_CPU_SET);
if (!wait_for_completion_timeout(&mb5_transfer.work,
msecs_to_jiffies(500))) {
pr_err("prcmu: prcmu_abb_write timed out.\n");
r = -EIO;
goto unlock_and_return;
}
r = ((mb5_transfer.ack.status == I2C_WR_OK) ? 0 : -EIO);
unlock_and_return:
mutex_unlock(&mb5_transfer.lock);
return r;
}
EXPORT_SYMBOL(prcmu_abb_write);
static int set_ape_cpu_opps(u8 header, enum prcmu_ape_opp ape_opp,
enum prcmu_cpu_opp cpu_opp)
{
bool do_ape;
bool do_arm;
int err = 0;
do_ape = ((header == MB1H_APE_OPP) || (header == MB1H_ARM_APE_OPP));
do_arm = ((header == MB1H_ARM_OPP) || (header == MB1H_ARM_APE_OPP));
mutex_lock(&mb1_transfer.lock);
while (readl(PRCM_MBOX_CPU_VAL) & MBOX_BIT(1))
cpu_relax();
writeb(0, MBOX_HEADER_REQ_MB0);
writeb(cpu_opp, REQ_MB1_ARMOPP);
writeb(ape_opp, REQ_MB1_APEOPP);
writeb(0, REQ_MB1_BOOSTOPP);
writel(MBOX_BIT(1), PRCM_MBOX_CPU_SET);
wait_for_completion(&mb1_transfer.work);
if ((do_ape) && (mb1_transfer.ack.ape_status != 0))
err = -EIO;
if ((do_arm) && (mb1_transfer.ack.arm_status != 0))
err = -EIO;
mutex_unlock(&mb1_transfer.lock);
return err;
}
/**
* prcmu_set_ape_opp() - Set the OPP of the APE.
* @opp: The OPP to set.
*
* This function sets the OPP of the APE.
*/
int prcmu_set_ape_opp(enum prcmu_ape_opp opp)
{
return set_ape_cpu_opps(MB1H_APE_OPP, opp, APE_OPP_NO_CHANGE);
}
EXPORT_SYMBOL(prcmu_set_ape_opp);
/**
* prcmu_set_cpu_opp() - Set the OPP of the CPU.
* @opp: The OPP to set.
*
* This function sets the OPP of the CPU.
*/
int prcmu_set_cpu_opp(enum prcmu_cpu_opp opp)
{
return set_ape_cpu_opps(MB1H_ARM_OPP, CPU_OPP_NO_CHANGE, opp);
}
EXPORT_SYMBOL(prcmu_set_cpu_opp);
/**
* prcmu_set_ape_cpu_opps() - Set the OPPs of the APE and the CPU.
* @ape_opp: The APE OPP to set.
* @cpu_opp: The CPU OPP to set.
*
* This function sets the OPPs of the APE and the CPU.
*/
int prcmu_set_ape_cpu_opps(enum prcmu_ape_opp ape_opp,
enum prcmu_cpu_opp cpu_opp)
{
return set_ape_cpu_opps(MB1H_ARM_APE_OPP, ape_opp, cpu_opp);
}
EXPORT_SYMBOL(prcmu_set_ape_cpu_opps);
/**
* prcmu_get_ape_opp() - Get the OPP of the APE.
*
* This function gets the OPP of the APE.
*/
enum prcmu_ape_opp prcmu_get_ape_opp(void)
{
return readb(ACK_MB1_CURR_APEOPP);
}
EXPORT_SYMBOL(prcmu_get_ape_opp);
/**
* prcmu_get_cpu_opp() - Get the OPP of the CPU.
*
* This function gets the OPP of the CPU. The OPP is specified in %%.
* PRCMU_OPP_EXT is a special OPP value, not specified in %%.
*/
int prcmu_get_cpu_opp(void)
{
return readb(ACK_MB1_CURR_ARMOPP);
}
EXPORT_SYMBOL(prcmu_get_cpu_opp);
bool prcmu_has_arm_maxopp(void)
{
return (readb(PRCM_AVS_VARM_MAX_OPP) & PRCM_AVS_ISMODEENABLE_MASK)
== PRCM_AVS_ISMODEENABLE_MASK;
}
static void read_mailbox_0(void)
{
writel(MBOX_BIT(0), PRCM_ARM_IT1_CLEAR);
}
static void read_mailbox_1(void)
{
mb1_transfer.ack.arm_opp = readb(ACK_MB1_CURR_ARMOPP);
mb1_transfer.ack.ape_opp = readb(ACK_MB1_CURR_APEOPP);
complete(&mb1_transfer.work);
writel(MBOX_BIT(1), PRCM_ARM_IT1_CLEAR);
}
static void read_mailbox_2(void)
{
writel(MBOX_BIT(2), PRCM_ARM_IT1_CLEAR);
}
static void read_mailbox_3(void)
{
writel(MBOX_BIT(3), PRCM_ARM_IT1_CLEAR);
}
static void read_mailbox_4(void)
{
writel(MBOX_BIT(4), PRCM_ARM_IT1_CLEAR);
}
static void read_mailbox_5(void)
{
mb5_transfer.ack.status = readb(ACK_MB5_I2C_STATUS);
mb5_transfer.ack.value = readb(ACK_MB5_I2C_VAL);
complete(&mb5_transfer.work);
writel(MBOX_BIT(5), PRCM_ARM_IT1_CLEAR);
}
static void read_mailbox_6(void)
{
writel(MBOX_BIT(6), PRCM_ARM_IT1_CLEAR);
}
static void read_mailbox_7(void)
{
writel(MBOX_BIT(7), PRCM_ARM_IT1_CLEAR);
}
static void (* const read_mailbox[NUM_MBOX])(void) = {
read_mailbox_0,
read_mailbox_1,
read_mailbox_2,
read_mailbox_3,
read_mailbox_4,
read_mailbox_5,
read_mailbox_6,
read_mailbox_7
};
static irqreturn_t prcmu_irq_handler(int irq, void *data)
{
u32 bits;
u8 n;
bits = (readl(PRCM_ARM_IT1_VAL) & (MBOX_BIT(NUM_MBOX) - 1));
if (unlikely(!bits))
return IRQ_NONE;
for (n = 0; bits; n++) {
if (bits & MBOX_BIT(n)) {
bits -= MBOX_BIT(n);
read_mailbox[n]();
}
}
return IRQ_HANDLED;
}
void __init prcmu_early_init(void)
{
if (cpu_is_u8500v11() || cpu_is_u8500ed()) {
tcdm_base = __io_address(U8500_PRCMU_TCDM_BASE_V1);
} else if (cpu_is_u8500v2()) {
tcdm_base = __io_address(U8500_PRCMU_TCDM_BASE);
} else {
pr_err("prcmu: Unsupported chip version\n");
BUG();
}
}
static int __init prcmu_init(void)
{
if (cpu_is_u8500ed()) {
pr_err("prcmu: Unsupported chip version\n");
return 0;
}
mutex_init(&mb1_transfer.lock);
init_completion(&mb1_transfer.work);
mutex_init(&mb5_transfer.lock);
init_completion(&mb5_transfer.work);
/* Clean up the mailbox interrupts after pre-kernel code. */
writel((MBOX_BIT(NUM_MBOX) - 1), PRCM_ARM_IT1_CLEAR);
return request_irq(IRQ_DB8500_PRCMU1, prcmu_irq_handler, 0,
"prcmu", NULL);
}
arch_initcall(prcmu_init);

View File

@ -39,3 +39,5 @@ obj-$(CONFIG_X86_CPUFREQ_NFORCE2) += cpufreq-nforce2.o
##################################################################################d
# ARM SoC drivers
obj-$(CONFIG_UX500_SOC_DB8500) += db8500-cpufreq.o

View File

@ -0,0 +1,169 @@
/*
* Copyright (C) STMicroelectronics 2009
* Copyright (C) ST-Ericsson SA 2010
*
* License Terms: GNU General Public License v2
* Author: Sundar Iyer <sundar.iyer@stericsson.com>
* Author: Martin Persson <martin.persson@stericsson.com>
* Author: Jonas Aaberg <jonas.aberg@stericsson.com>
*
*/
#include <linux/kernel.h>
#include <linux/cpufreq.h>
#include <linux/delay.h>
#include <linux/slab.h>
#include <linux/mfd/db8500-prcmu.h>
#include <mach/id.h>
static struct cpufreq_frequency_table freq_table[] = {
[0] = {
.index = 0,
.frequency = 300000,
},
[1] = {
.index = 1,
.frequency = 600000,
},
[2] = {
/* Used for MAX_OPP, if available */
.index = 2,
.frequency = CPUFREQ_TABLE_END,
},
[3] = {
.index = 3,
.frequency = CPUFREQ_TABLE_END,
},
};
static enum arm_opp idx2opp[] = {
ARM_50_OPP,
ARM_100_OPP,
ARM_MAX_OPP
};
static struct freq_attr *db8500_cpufreq_attr[] = {
&cpufreq_freq_attr_scaling_available_freqs,
NULL,
};
static int db8500_cpufreq_verify_speed(struct cpufreq_policy *policy)
{
return cpufreq_frequency_table_verify(policy, freq_table);
}
static int db8500_cpufreq_target(struct cpufreq_policy *policy,
unsigned int target_freq,
unsigned int relation)
{
struct cpufreq_freqs freqs;
unsigned int idx;
/* scale the target frequency to one of the extremes supported */
if (target_freq < policy->cpuinfo.min_freq)
target_freq = policy->cpuinfo.min_freq;
if (target_freq > policy->cpuinfo.max_freq)
target_freq = policy->cpuinfo.max_freq;
/* Lookup the next frequency */
if (cpufreq_frequency_table_target
(policy, freq_table, target_freq, relation, &idx)) {
return -EINVAL;
}
freqs.old = policy->cur;
freqs.new = freq_table[idx].frequency;
freqs.cpu = policy->cpu;
if (freqs.old == freqs.new)
return 0;
/* pre-change notification */
cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
/* request the PRCM unit for opp change */
if (prcmu_set_arm_opp(idx2opp[idx])) {
pr_err("db8500-cpufreq: Failed to set OPP level\n");
return -EINVAL;
}
/* post change notification */
cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
return 0;
}
static unsigned int db8500_cpufreq_getspeed(unsigned int cpu)
{
int i;
/* request the prcm to get the current ARM opp */
for (i = 0; prcmu_get_arm_opp() != idx2opp[i]; i++)
;
return freq_table[i].frequency;
}
static int __cpuinit db8500_cpufreq_init(struct cpufreq_policy *policy)
{
int res;
int i;
BUILD_BUG_ON(ARRAY_SIZE(idx2opp) + 1 != ARRAY_SIZE(freq_table));
if (cpu_is_u8500v2() && !prcmu_is_u8400()) {
freq_table[0].frequency = 400000;
freq_table[1].frequency = 800000;
if (prcmu_has_arm_maxopp())
freq_table[2].frequency = 1000000;
}
/* get policy fields based on the table */
res = cpufreq_frequency_table_cpuinfo(policy, freq_table);
if (!res)
cpufreq_frequency_table_get_attr(freq_table, policy->cpu);
else {
pr_err("db8500-cpufreq : Failed to read policy table\n");
return res;
}
policy->min = policy->cpuinfo.min_freq;
policy->max = policy->cpuinfo.max_freq;
policy->cur = db8500_cpufreq_getspeed(policy->cpu);
for (i = 0; freq_table[i].frequency != policy->cur; i++)
;
policy->governor = CPUFREQ_DEFAULT_GOVERNOR;
/*
* FIXME : Need to take time measurement across the target()
* function with no/some/all drivers in the notification
* list.
*/
policy->cpuinfo.transition_latency = 20 * 1000; /* in ns */
/* policy sharing between dual CPUs */
cpumask_copy(policy->cpus, &cpu_present_map);
policy->shared_type = CPUFREQ_SHARED_TYPE_ALL;
return 0;
}
static struct cpufreq_driver db8500_cpufreq_driver = {
.flags = CPUFREQ_STICKY,
.verify = db8500_cpufreq_verify_speed,
.target = db8500_cpufreq_target,
.get = db8500_cpufreq_getspeed,
.init = db8500_cpufreq_init,
.name = "DB8500",
.attr = db8500_cpufreq_attr,
};
static int __init db8500_cpufreq_register(void)
{
if (!cpu_is_u8500v20_or_later())
return -ENODEV;
pr_info("cpufreq for DB8500 started\n");
return cpufreq_register_driver(&db8500_cpufreq_driver);
}
device_initcall(db8500_cpufreq_register);

View File

@ -538,7 +538,7 @@ config AB8500_CORE
config AB8500_I2C_CORE
bool "AB8500 register access via PRCMU I2C"
depends on AB8500_CORE && UX500_SOC_DB8500
depends on AB8500_CORE && MFD_DB8500_PRCMU
default y
help
This enables register access to the AB8500 chip via PRCMU I2C.
@ -575,6 +575,26 @@ config AB3550_CORE
LEDs, vibrator, system power and temperature, power management
and ALSA sound.
config MFD_DB8500_PRCMU
bool "ST-Ericsson DB8500 Power Reset Control Management Unit"
depends on UX500_SOC_DB8500
select MFD_CORE
help
Select this option to enable support for the DB8500 Power Reset
and Control Management Unit. This is basically an autonomous
system controller running an XP70 microprocessor, which is accessed
through a register map.
config MFD_DB5500_PRCMU
bool "ST-Ericsson DB5500 Power Reset Control Management Unit"
depends on UX500_SOC_DB5500
select MFD_CORE
help
Select this option to enable support for the DB5500 Power Reset
and Control Management Unit. This is basically an autonomous
system controller running an XP70 microprocessor, which is accessed
through a register map.
config MFD_CS5535
tristate "Support for CS5535 and CS5536 southbridge core functions"
select MFD_CORE

View File

@ -74,9 +74,12 @@ obj-$(CONFIG_AB3100_CORE) += ab3100-core.o
obj-$(CONFIG_AB3100_OTP) += ab3100-otp.o
obj-$(CONFIG_AB3550_CORE) += ab3550-core.o
obj-$(CONFIG_AB8500_CORE) += ab8500-core.o ab8500-sysctrl.o
obj-$(CONFIG_AB8500_I2C_CORE) += ab8500-i2c.o
obj-$(CONFIG_AB8500_DEBUG) += ab8500-debugfs.o
obj-$(CONFIG_AB8500_GPADC) += ab8500-gpadc.o
obj-$(CONFIG_MFD_DB8500_PRCMU) += db8500-prcmu.o
# ab8500-i2c need to come after db8500-prcmu (which provides the channel)
obj-$(CONFIG_AB8500_I2C_CORE) += ab8500-i2c.o
obj-$(CONFIG_MFD_DB5500_PRCMU) += db5500-prcmu.o
obj-$(CONFIG_MFD_TIMBERDALE) += timberdale.o
obj-$(CONFIG_PMIC_ADP5520) += adp5520.o
obj-$(CONFIG_LPC_SCH) += lpc_sch.o

View File

@ -11,8 +11,7 @@
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/mfd/ab8500.h>
#include <mach/prcmu.h>
#include <linux/mfd/db8500-prcmu.h>
static int ab8500_i2c_write(struct ab8500 *ab8500, u16 addr, u8 data)
{

View File

@ -15,11 +15,20 @@
#include <mach/hardware.h>
#define _PRCMU_BASE IO_ADDRESS(U8500_PRCMU_BASE)
#define PRCM_ARM_PLLDIVPS (_PRCMU_BASE + 0x118)
#define PRCM_ARM_PLLDIVPS_ARM_BRM_RATE 0x3f
#define PRCM_ARM_PLLDIVPS_MAX_MASK 0xf
#define PRCM_PLLARM_LOCKP (_PRCMU_BASE + 0x0a8)
#define PRCM_PLLARM_LOCKP_PRCM_PLLARM_LOCKP3 0x2
#define PRCM_ARM_CHGCLKREQ (_PRCMU_BASE + 0x114)
#define PRCM_ARM_CHGCLKREQ_PRCM_ARM_CHGCLKREQ 0x1
#define PRCM_PLLARM_ENABLE (_PRCMU_BASE + 0x98)
#define PRCM_PLLARM_ENABLE_PRCM_PLLARM_ENABLE 0x1
#define PRCM_PLLARM_ENABLE_PRCM_PLLARM_COUNTON 0x100
#define PRCM_ARMCLKFIX_MGT (_PRCMU_BASE + 0x0)
#define PRCM_A9_RESETN_CLR (_PRCMU_BASE + 0x1f4)
#define PRCM_A9_RESETN_SET (_PRCMU_BASE + 0x1f0)
@ -28,7 +37,8 @@
/* ARM WFI Standby signal register */
#define PRCM_ARM_WFI_STANDBY (_PRCMU_BASE + 0x130)
#define PRCMU_IOCR (_PRCMU_BASE + 0x310)
#define PRCM_IOCR (_PRCMU_BASE + 0x310)
#define PRCM_IOCR_IOFORCE 0x1
/* CPU mailbox registers */
#define PRCM_MBOX_CPU_VAL (_PRCMU_BASE + 0x0fc)
@ -37,6 +47,8 @@
/* Dual A9 core interrupt management unit registers */
#define PRCM_A9_MASK_REQ (_PRCMU_BASE + 0x328)
#define PRCM_A9_MASK_REQ_PRCM_A9_MASK_REQ 0x1
#define PRCM_A9_MASK_ACK (_PRCMU_BASE + 0x32c)
#define PRCM_ARMITMSK31TO0 (_PRCMU_BASE + 0x11c)
#define PRCM_ARMITMSK63TO32 (_PRCMU_BASE + 0x120)
@ -74,14 +86,17 @@
/* PRCMU clock/PLL/reset registers */
#define PRCM_PLLDSI_FREQ (_PRCMU_BASE + 0x500)
#define PRCM_PLLDSI_ENABLE (_PRCMU_BASE + 0x504)
#define PRCM_PLLDSI_LOCKP (_PRCMU_BASE + 0x508)
#define PRCM_LCDCLK_MGT (_PRCMU_BASE + 0x044)
#define PRCM_MCDECLK_MGT (_PRCMU_BASE + 0x064)
#define PRCM_HDMICLK_MGT (_PRCMU_BASE + 0x058)
#define PRCM_TVCLK_MGT (_PRCMU_BASE + 0x07c)
#define PRCM_DSI_PLLOUT_SEL (_PRCMU_BASE + 0x530)
#define PRCM_DSITVCLK_DIV (_PRCMU_BASE + 0x52C)
#define PRCM_PLLDSI_LOCKP (_PRCMU_BASE + 0x508)
#define PRCM_APE_RESETN_SET (_PRCMU_BASE + 0x1E4)
#define PRCM_APE_RESETN_CLR (_PRCMU_BASE + 0x1E8)
#define PRCM_CLKOCR (_PRCMU_BASE + 0x1CC)
/* ePOD and memory power signal control registers */
#define PRCM_EPOD_C_SET (_PRCMU_BASE + 0x410)
@ -92,5 +107,9 @@
/* Miscellaneous unit registers */
#define PRCM_DSI_SW_RESET (_PRCMU_BASE + 0x324)
#define PRCM_GPIOCR (_PRCMU_BASE + 0x138)
#define PRCM_GPIOCR_DBG_STM_MOD_CMD1 0x800
#define PRCM_GPIOCR_DBG_UARTMOD_CMD0 0x1
#endif /* __MACH_PRCMU_REGS_H */
#endif /* __MACH_PRCMU__REGS_H */

448
drivers/mfd/db5500-prcmu.c Normal file
View File

@ -0,0 +1,448 @@
/*
* Copyright (C) ST-Ericsson SA 2010
*
* License Terms: GNU General Public License v2
* Author: Mattias Nilsson <mattias.i.nilsson@stericsson.com>
*
* U5500 PRCM Unit interface driver
*/
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/delay.h>
#include <linux/errno.h>
#include <linux/err.h>
#include <linux/spinlock.h>
#include <linux/io.h>
#include <linux/slab.h>
#include <linux/mutex.h>
#include <linux/completion.h>
#include <linux/irq.h>
#include <linux/jiffies.h>
#include <linux/bitops.h>
#include <linux/interrupt.h>
#include <linux/mfd/db5500-prcmu.h>
#include <mach/hardware.h>
#include <mach/irqs.h>
#include <mach/db5500-regs.h>
#include "db5500-prcmu-regs.h"
#define _PRCM_MB_HEADER (tcdm_base + 0xFE8)
#define PRCM_REQ_MB0_HEADER (_PRCM_MB_HEADER + 0x0)
#define PRCM_REQ_MB1_HEADER (_PRCM_MB_HEADER + 0x1)
#define PRCM_REQ_MB2_HEADER (_PRCM_MB_HEADER + 0x2)
#define PRCM_REQ_MB3_HEADER (_PRCM_MB_HEADER + 0x3)
#define PRCM_REQ_MB4_HEADER (_PRCM_MB_HEADER + 0x4)
#define PRCM_REQ_MB5_HEADER (_PRCM_MB_HEADER + 0x5)
#define PRCM_REQ_MB6_HEADER (_PRCM_MB_HEADER + 0x6)
#define PRCM_REQ_MB7_HEADER (_PRCM_MB_HEADER + 0x7)
#define PRCM_ACK_MB0_HEADER (_PRCM_MB_HEADER + 0x8)
#define PRCM_ACK_MB1_HEADER (_PRCM_MB_HEADER + 0x9)
#define PRCM_ACK_MB2_HEADER (_PRCM_MB_HEADER + 0xa)
#define PRCM_ACK_MB3_HEADER (_PRCM_MB_HEADER + 0xb)
#define PRCM_ACK_MB4_HEADER (_PRCM_MB_HEADER + 0xc)
#define PRCM_ACK_MB5_HEADER (_PRCM_MB_HEADER + 0xd)
#define PRCM_ACK_MB6_HEADER (_PRCM_MB_HEADER + 0xe)
#define PRCM_ACK_MB7_HEADER (_PRCM_MB_HEADER + 0xf)
/* Req Mailboxes */
#define PRCM_REQ_MB0 (tcdm_base + 0xFD8)
#define PRCM_REQ_MB1 (tcdm_base + 0xFCC)
#define PRCM_REQ_MB2 (tcdm_base + 0xFC4)
#define PRCM_REQ_MB3 (tcdm_base + 0xFC0)
#define PRCM_REQ_MB4 (tcdm_base + 0xF98)
#define PRCM_REQ_MB5 (tcdm_base + 0xF90)
#define PRCM_REQ_MB6 (tcdm_base + 0xF8C)
#define PRCM_REQ_MB7 (tcdm_base + 0xF84)
/* Ack Mailboxes */
#define PRCM_ACK_MB0 (tcdm_base + 0xF38)
#define PRCM_ACK_MB1 (tcdm_base + 0xF30)
#define PRCM_ACK_MB2 (tcdm_base + 0xF24)
#define PRCM_ACK_MB3 (tcdm_base + 0xF20)
#define PRCM_ACK_MB4 (tcdm_base + 0xF1C)
#define PRCM_ACK_MB5 (tcdm_base + 0xF14)
#define PRCM_ACK_MB6 (tcdm_base + 0xF0C)
#define PRCM_ACK_MB7 (tcdm_base + 0xF08)
enum mb_return_code {
RC_SUCCESS,
RC_FAIL,
};
/* Mailbox 0 headers. */
enum mb0_header {
/* request */
RMB0H_PWR_STATE_TRANS = 1,
RMB0H_WAKE_UP_CFG,
RMB0H_RD_WAKE_UP_ACK,
/* acknowledge */
AMB0H_WAKE_UP = 1,
};
/* Mailbox 5 headers. */
enum mb5_header {
MB5H_I2C_WRITE = 1,
MB5H_I2C_READ,
};
/* Request mailbox 5 fields. */
#define PRCM_REQ_MB5_I2C_SLAVE (PRCM_REQ_MB5 + 0)
#define PRCM_REQ_MB5_I2C_REG (PRCM_REQ_MB5 + 1)
#define PRCM_REQ_MB5_I2C_SIZE (PRCM_REQ_MB5 + 2)
#define PRCM_REQ_MB5_I2C_DATA (PRCM_REQ_MB5 + 4)
/* Acknowledge mailbox 5 fields. */
#define PRCM_ACK_MB5_RETURN_CODE (PRCM_ACK_MB5 + 0)
#define PRCM_ACK_MB5_I2C_DATA (PRCM_ACK_MB5 + 4)
#define NUM_MB 8
#define MBOX_BIT BIT
#define ALL_MBOX_BITS (MBOX_BIT(NUM_MB) - 1)
/*
* Used by MCDE to setup all necessary PRCMU registers
*/
#define PRCMU_RESET_DSIPLL 0x00004000
#define PRCMU_UNCLAMP_DSIPLL 0x00400800
/* HDMI CLK MGT PLLSW=001 (PLLSOC0), PLLDIV=0x8, = 50 Mhz*/
#define PRCMU_DSI_CLOCK_SETTING 0x00000128
/* TVCLK_MGT PLLSW=001 (PLLSOC0) PLLDIV=0x13, = 19.05 MHZ */
#define PRCMU_DSI_LP_CLOCK_SETTING 0x00000135
#define PRCMU_PLLDSI_FREQ_SETTING 0x0004013C
#define PRCMU_DSI_PLLOUT_SEL_SETTING 0x00000002
#define PRCMU_ENABLE_ESCAPE_CLOCK_DIV 0x03000101
#define PRCMU_DISABLE_ESCAPE_CLOCK_DIV 0x00000101
#define PRCMU_ENABLE_PLLDSI 0x00000001
#define PRCMU_DISABLE_PLLDSI 0x00000000
#define PRCMU_DSI_RESET_SW 0x00000003
#define PRCMU_PLLDSI_LOCKP_LOCKED 0x3
/*
* mb0_transfer - state needed for mailbox 0 communication.
* @lock: The transaction lock.
*/
static struct {
spinlock_t lock;
} mb0_transfer;
/*
* mb5_transfer - state needed for mailbox 5 communication.
* @lock: The transaction lock.
* @work: The transaction completion structure.
* @ack: Reply ("acknowledge") data.
*/
static struct {
struct mutex lock;
struct completion work;
struct {
u8 header;
u8 status;
u8 value[4];
} ack;
} mb5_transfer;
/* PRCMU TCDM base IO address. */
static __iomem void *tcdm_base;
/**
* db5500_prcmu_abb_read() - Read register value(s) from the ABB.
* @slave: The I2C slave address.
* @reg: The (start) register address.
* @value: The read out value(s).
* @size: The number of registers to read.
*
* Reads register value(s) from the ABB.
* @size has to be <= 4.
*/
int db5500_prcmu_abb_read(u8 slave, u8 reg, u8 *value, u8 size)
{
int r;
if ((size < 1) || (4 < size))
return -EINVAL;
mutex_lock(&mb5_transfer.lock);
while (readl(PRCM_MBOX_CPU_VAL) & MBOX_BIT(5))
cpu_relax();
writeb(slave, PRCM_REQ_MB5_I2C_SLAVE);
writeb(reg, PRCM_REQ_MB5_I2C_REG);
writeb(size, PRCM_REQ_MB5_I2C_SIZE);
writeb(MB5H_I2C_READ, PRCM_REQ_MB5_HEADER);
writel(MBOX_BIT(5), PRCM_MBOX_CPU_SET);
wait_for_completion(&mb5_transfer.work);
r = 0;
if ((mb5_transfer.ack.header == MB5H_I2C_READ) &&
(mb5_transfer.ack.status == RC_SUCCESS))
memcpy(value, mb5_transfer.ack.value, (size_t)size);
else
r = -EIO;
mutex_unlock(&mb5_transfer.lock);
return r;
}
/**
* db5500_prcmu_abb_write() - Write register value(s) to the ABB.
* @slave: The I2C slave address.
* @reg: The (start) register address.
* @value: The value(s) to write.
* @size: The number of registers to write.
*
* Writes register value(s) to the ABB.
* @size has to be <= 4.
*/
int db5500_prcmu_abb_write(u8 slave, u8 reg, u8 *value, u8 size)
{
int r;
if ((size < 1) || (4 < size))
return -EINVAL;
mutex_lock(&mb5_transfer.lock);
while (readl(PRCM_MBOX_CPU_VAL) & MBOX_BIT(5))
cpu_relax();
writeb(slave, PRCM_REQ_MB5_I2C_SLAVE);
writeb(reg, PRCM_REQ_MB5_I2C_REG);
writeb(size, PRCM_REQ_MB5_I2C_SIZE);
memcpy_toio(PRCM_REQ_MB5_I2C_DATA, value, size);
writeb(MB5H_I2C_WRITE, PRCM_REQ_MB5_HEADER);
writel(MBOX_BIT(5), PRCM_MBOX_CPU_SET);
wait_for_completion(&mb5_transfer.work);
if ((mb5_transfer.ack.header == MB5H_I2C_WRITE) &&
(mb5_transfer.ack.status == RC_SUCCESS))
r = 0;
else
r = -EIO;
mutex_unlock(&mb5_transfer.lock);
return r;
}
int db5500_prcmu_enable_dsipll(void)
{
int i;
/* Enable DSIPLL_RESETN resets */
writel(PRCMU_RESET_DSIPLL, PRCM_APE_RESETN_CLR);
/* Unclamp DSIPLL in/out */
writel(PRCMU_UNCLAMP_DSIPLL, PRCM_MMIP_LS_CLAMP_CLR);
/* Set DSI PLL FREQ */
writel(PRCMU_PLLDSI_FREQ_SETTING, PRCM_PLLDSI_FREQ);
writel(PRCMU_DSI_PLLOUT_SEL_SETTING,
PRCM_DSI_PLLOUT_SEL);
/* Enable Escape clocks */
writel(PRCMU_ENABLE_ESCAPE_CLOCK_DIV, PRCM_DSITVCLK_DIV);
/* Start DSI PLL */
writel(PRCMU_ENABLE_PLLDSI, PRCM_PLLDSI_ENABLE);
/* Reset DSI PLL */
writel(PRCMU_DSI_RESET_SW, PRCM_DSI_SW_RESET);
for (i = 0; i < 10; i++) {
if ((readl(PRCM_PLLDSI_LOCKP) &
PRCMU_PLLDSI_LOCKP_LOCKED) == PRCMU_PLLDSI_LOCKP_LOCKED)
break;
udelay(100);
}
/* Release DSIPLL_RESETN */
writel(PRCMU_RESET_DSIPLL, PRCM_APE_RESETN_SET);
return 0;
}
int db5500_prcmu_disable_dsipll(void)
{
/* Disable dsi pll */
writel(PRCMU_DISABLE_PLLDSI, PRCM_PLLDSI_ENABLE);
/* Disable escapeclock */
writel(PRCMU_DISABLE_ESCAPE_CLOCK_DIV, PRCM_DSITVCLK_DIV);
return 0;
}
int db5500_prcmu_set_display_clocks(void)
{
/* HDMI and TVCLK Should be handled somewhere else */
/* PLLDIV=8, PLLSW=2, CLKEN=1 */
writel(PRCMU_DSI_CLOCK_SETTING, PRCM_HDMICLK_MGT);
/* PLLDIV=14, PLLSW=2, CLKEN=1 */
writel(PRCMU_DSI_LP_CLOCK_SETTING, PRCM_TVCLK_MGT);
return 0;
}
static void ack_dbb_wakeup(void)
{
unsigned long flags;
spin_lock_irqsave(&mb0_transfer.lock, flags);
while (readl(PRCM_MBOX_CPU_VAL) & MBOX_BIT(0))
cpu_relax();
writeb(RMB0H_RD_WAKE_UP_ACK, PRCM_REQ_MB0_HEADER);
writel(MBOX_BIT(0), PRCM_MBOX_CPU_SET);
spin_unlock_irqrestore(&mb0_transfer.lock, flags);
}
static inline void print_unknown_header_warning(u8 n, u8 header)
{
pr_warning("prcmu: Unknown message header (%d) in mailbox %d.\n",
header, n);
}
static bool read_mailbox_0(void)
{
bool r;
u8 header;
header = readb(PRCM_ACK_MB0_HEADER);
switch (header) {
case AMB0H_WAKE_UP:
r = true;
break;
default:
print_unknown_header_warning(0, header);
r = false;
break;
}
writel(MBOX_BIT(0), PRCM_ARM_IT1_CLEAR);
return r;
}
static bool read_mailbox_1(void)
{
writel(MBOX_BIT(1), PRCM_ARM_IT1_CLEAR);
return false;
}
static bool read_mailbox_2(void)
{
writel(MBOX_BIT(2), PRCM_ARM_IT1_CLEAR);
return false;
}
static bool read_mailbox_3(void)
{
writel(MBOX_BIT(3), PRCM_ARM_IT1_CLEAR);
return false;
}
static bool read_mailbox_4(void)
{
writel(MBOX_BIT(4), PRCM_ARM_IT1_CLEAR);
return false;
}
static bool read_mailbox_5(void)
{
u8 header;
header = readb(PRCM_ACK_MB5_HEADER);
switch (header) {
case MB5H_I2C_READ:
memcpy_fromio(mb5_transfer.ack.value, PRCM_ACK_MB5_I2C_DATA, 4);
case MB5H_I2C_WRITE:
mb5_transfer.ack.header = header;
mb5_transfer.ack.status = readb(PRCM_ACK_MB5_RETURN_CODE);
complete(&mb5_transfer.work);
break;
default:
print_unknown_header_warning(5, header);
break;
}
writel(MBOX_BIT(5), PRCM_ARM_IT1_CLEAR);
return false;
}
static bool read_mailbox_6(void)
{
writel(MBOX_BIT(6), PRCM_ARM_IT1_CLEAR);
return false;
}
static bool read_mailbox_7(void)
{
writel(MBOX_BIT(7), PRCM_ARM_IT1_CLEAR);
return false;
}
static bool (* const read_mailbox[NUM_MB])(void) = {
read_mailbox_0,
read_mailbox_1,
read_mailbox_2,
read_mailbox_3,
read_mailbox_4,
read_mailbox_5,
read_mailbox_6,
read_mailbox_7
};
static irqreturn_t prcmu_irq_handler(int irq, void *data)
{
u32 bits;
u8 n;
irqreturn_t r;
bits = (readl(PRCM_ARM_IT1_VAL) & ALL_MBOX_BITS);
if (unlikely(!bits))
return IRQ_NONE;
r = IRQ_HANDLED;
for (n = 0; bits; n++) {
if (bits & MBOX_BIT(n)) {
bits -= MBOX_BIT(n);
if (read_mailbox[n]())
r = IRQ_WAKE_THREAD;
}
}
return r;
}
static irqreturn_t prcmu_irq_thread_fn(int irq, void *data)
{
ack_dbb_wakeup();
return IRQ_HANDLED;
}
void __init db5500_prcmu_early_init(void)
{
tcdm_base = __io_address(U5500_PRCMU_TCDM_BASE);
spin_lock_init(&mb0_transfer.lock);
mutex_init(&mb5_transfer.lock);
init_completion(&mb5_transfer.work);
}
/**
* prcmu_fw_init - arch init call for the Linux PRCMU fw init logic
*
*/
int __init db5500_prcmu_init(void)
{
int r = 0;
if (ux500_is_svp() || !cpu_is_u5500())
return -ENODEV;
/* Clean up the mailbox interrupts after pre-kernel code. */
writel(ALL_MBOX_BITS, PRCM_ARM_IT1_CLEAR);
r = request_threaded_irq(IRQ_DB5500_PRCMU1, prcmu_irq_handler,
prcmu_irq_thread_fn, 0, "prcmu", NULL);
if (r < 0) {
pr_err("prcmu: Failed to allocate IRQ_DB5500_PRCMU1.\n");
return -EBUSY;
}
return 0;
}
arch_initcall(db5500_prcmu_init);

View File

@ -0,0 +1,166 @@
/*
* Copyright (C) STMicroelectronics 2009
* Copyright (C) ST-Ericsson SA 2010
*
* Author: Kumar Sanghvi <kumar.sanghvi@stericsson.com>
* Author: Sundar Iyer <sundar.iyer@stericsson.com>
*
* License Terms: GNU General Public License v2
*
* PRCM Unit registers
*/
#ifndef __DB8500_PRCMU_REGS_H
#define __DB8500_PRCMU_REGS_H
#include <linux/bitops.h>
#include <mach/hardware.h>
#define BITS(_start, _end) ((BIT(_end) - BIT(_start)) + BIT(_end))
#define PRCM_ARM_PLLDIVPS 0x118
#define PRCM_ARM_PLLDIVPS_ARM_BRM_RATE BITS(0, 5)
#define PRCM_ARM_PLLDIVPS_MAX_MASK 0xF
#define PRCM_PLLARM_LOCKP 0x0A8
#define PRCM_PLLARM_LOCKP_PRCM_PLLARM_LOCKP3 BIT(1)
#define PRCM_ARM_CHGCLKREQ 0x114
#define PRCM_ARM_CHGCLKREQ_PRCM_ARM_CHGCLKREQ BIT(0)
#define PRCM_PLLARM_ENABLE 0x98
#define PRCM_PLLARM_ENABLE_PRCM_PLLARM_ENABLE BIT(0)
#define PRCM_PLLARM_ENABLE_PRCM_PLLARM_COUNTON BIT(8)
#define PRCM_ARMCLKFIX_MGT 0x0
#define PRCM_A9_RESETN_CLR 0x1f4
#define PRCM_A9_RESETN_SET 0x1f0
#define PRCM_ARM_LS_CLAMP 0x30C
#define PRCM_SRAM_A9 0x308
/* ARM WFI Standby signal register */
#define PRCM_ARM_WFI_STANDBY 0x130
#define PRCM_IOCR 0x310
#define PRCM_IOCR_IOFORCE BIT(0)
/* CPU mailbox registers */
#define PRCM_MBOX_CPU_VAL 0x0FC
#define PRCM_MBOX_CPU_SET 0x100
/* Dual A9 core interrupt management unit registers */
#define PRCM_A9_MASK_REQ 0x328
#define PRCM_A9_MASK_REQ_PRCM_A9_MASK_REQ BIT(0)
#define PRCM_A9_MASK_ACK 0x32C
#define PRCM_ARMITMSK31TO0 0x11C
#define PRCM_ARMITMSK63TO32 0x120
#define PRCM_ARMITMSK95TO64 0x124
#define PRCM_ARMITMSK127TO96 0x128
#define PRCM_POWER_STATE_VAL 0x25C
#define PRCM_ARMITVAL31TO0 0x260
#define PRCM_ARMITVAL63TO32 0x264
#define PRCM_ARMITVAL95TO64 0x268
#define PRCM_ARMITVAL127TO96 0x26C
#define PRCM_HOSTACCESS_REQ 0x334
#define PRCM_HOSTACCESS_REQ_HOSTACCESS_REQ BIT(0)
#define PRCM_ARM_IT1_CLR 0x48C
#define PRCM_ARM_IT1_VAL 0x494
#define PRCM_ITSTATUS0 0x148
#define PRCM_ITSTATUS1 0x150
#define PRCM_ITSTATUS2 0x158
#define PRCM_ITSTATUS3 0x160
#define PRCM_ITSTATUS4 0x168
#define PRCM_ITSTATUS5 0x484
#define PRCM_ITCLEAR5 0x488
#define PRCM_ARMIT_MASKXP70_IT 0x1018
/* System reset register */
#define PRCM_APE_SOFTRST 0x228
/* Level shifter and clamp control registers */
#define PRCM_MMIP_LS_CLAMP_SET 0x420
#define PRCM_MMIP_LS_CLAMP_CLR 0x424
/* PRCMU HW semaphore */
#define PRCM_SEM 0x400
#define PRCM_SEM_PRCM_SEM BIT(0)
/* PRCMU clock/PLL/reset registers */
#define PRCM_PLLDSI_FREQ 0x500
#define PRCM_PLLDSI_ENABLE 0x504
#define PRCM_PLLDSI_LOCKP 0x508
#define PRCM_DSI_PLLOUT_SEL 0x530
#define PRCM_DSITVCLK_DIV 0x52C
#define PRCM_APE_RESETN_SET 0x1E4
#define PRCM_APE_RESETN_CLR 0x1E8
#define PRCM_TCR 0x1C8
#define PRCM_TCR_TENSEL_MASK BITS(0, 7)
#define PRCM_TCR_STOP_TIMERS BIT(16)
#define PRCM_TCR_DOZE_MODE BIT(17)
#define PRCM_CLKOCR 0x1CC
#define PRCM_CLKOCR_CLKODIV0_SHIFT 0
#define PRCM_CLKOCR_CLKODIV0_MASK BITS(0, 5)
#define PRCM_CLKOCR_CLKOSEL0_SHIFT 6
#define PRCM_CLKOCR_CLKOSEL0_MASK BITS(6, 8)
#define PRCM_CLKOCR_CLKODIV1_SHIFT 16
#define PRCM_CLKOCR_CLKODIV1_MASK BITS(16, 21)
#define PRCM_CLKOCR_CLKOSEL1_SHIFT 22
#define PRCM_CLKOCR_CLKOSEL1_MASK BITS(22, 24)
#define PRCM_CLKOCR_CLK1TYPE BIT(28)
#define PRCM_SGACLK_MGT 0x014
#define PRCM_UARTCLK_MGT 0x018
#define PRCM_MSP02CLK_MGT 0x01C
#define PRCM_MSP1CLK_MGT 0x288
#define PRCM_I2CCLK_MGT 0x020
#define PRCM_SDMMCCLK_MGT 0x024
#define PRCM_SLIMCLK_MGT 0x028
#define PRCM_PER1CLK_MGT 0x02C
#define PRCM_PER2CLK_MGT 0x030
#define PRCM_PER3CLK_MGT 0x034
#define PRCM_PER5CLK_MGT 0x038
#define PRCM_PER6CLK_MGT 0x03C
#define PRCM_PER7CLK_MGT 0x040
#define PRCM_LCDCLK_MGT 0x044
#define PRCM_BMLCLK_MGT 0x04C
#define PRCM_HSITXCLK_MGT 0x050
#define PRCM_HSIRXCLK_MGT 0x054
#define PRCM_HDMICLK_MGT 0x058
#define PRCM_APEATCLK_MGT 0x05C
#define PRCM_APETRACECLK_MGT 0x060
#define PRCM_MCDECLK_MGT 0x064
#define PRCM_IPI2CCLK_MGT 0x068
#define PRCM_DSIALTCLK_MGT 0x06C
#define PRCM_DMACLK_MGT 0x074
#define PRCM_B2R2CLK_MGT 0x078
#define PRCM_TVCLK_MGT 0x07C
#define PRCM_UNIPROCLK_MGT 0x278
#define PRCM_SSPCLK_MGT 0x280
#define PRCM_RNGCLK_MGT 0x284
#define PRCM_UICCCLK_MGT 0x27C
#define PRCM_CLK_MGT_CLKPLLDIV_MASK BITS(0, 4)
#define PRCM_CLK_MGT_CLKPLLSW_MASK BITS(5, 7)
#define PRCM_CLK_MGT_CLKEN BIT(8)
/* ePOD and memory power signal control registers */
#define PRCM_EPOD_C_SET 0x410
#define PRCM_SRAM_LS_SLEEP 0x304
/* Debug power control unit registers */
#define PRCM_POWER_STATE_SET 0x254
/* Miscellaneous unit registers */
#define PRCM_DSI_SW_RESET 0x324
#define PRCM_GPIOCR 0x138
/* GPIOCR register */
#define PRCM_GPIOCR_SPI2_SELECT BIT(23)
#define PRCM_DDR_SUBSYS_APE_MINBW 0x438
#endif /* __DB8500_PRCMU_REGS_H */

2069
drivers/mfd/db8500-prcmu.c Normal file

File diff suppressed because it is too large Load Diff

View File

@ -274,6 +274,13 @@ config REGULATOR_AB8500
This driver supports the regulators found on the ST-Ericsson mixed
signal AB8500 PMIC
config REGULATOR_DB8500_PRCMU
bool "ST-Ericsson DB8500 Voltage Domain Regulators"
depends on MFD_DB8500_PRCMU
help
This driver supports the voltage domain regulators controlled by the
DB8500 PRCMU
config REGULATOR_TPS6586X
tristate "TI TPS6586X Power regulators"
depends on MFD_TPS6586X

View File

@ -41,5 +41,6 @@ obj-$(CONFIG_REGULATOR_TPS6524X) += tps6524x-regulator.o
obj-$(CONFIG_REGULATOR_88PM8607) += 88pm8607.o
obj-$(CONFIG_REGULATOR_ISL6271A) += isl6271a-regulator.o
obj-$(CONFIG_REGULATOR_AB8500) += ab8500.o
obj-$(CONFIG_REGULATOR_DB8500_PRCMU) += db8500-prcmu.o
ccflags-$(CONFIG_REGULATOR_DEBUG) += -DDEBUG

View File

@ -0,0 +1,558 @@
/*
* Copyright (C) ST-Ericsson SA 2010
*
* License Terms: GNU General Public License v2
* Authors: Sundar Iyer <sundar.iyer@stericsson.com> for ST-Ericsson
* Bengt Jonsson <bengt.g.jonsson@stericsson.com> for ST-Ericsson
*
* Power domain regulators on DB8500
*/
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/err.h>
#include <linux/spinlock.h>
#include <linux/platform_device.h>
#include <linux/mfd/core.h>
#include <linux/mfd/db8500-prcmu.h>
#include <linux/regulator/driver.h>
#include <linux/regulator/machine.h>
#include <linux/regulator/db8500-prcmu.h>
/*
* power state reference count
*/
static int power_state_active_cnt; /* will initialize to zero */
static DEFINE_SPINLOCK(power_state_active_lock);
static void power_state_active_enable(void)
{
unsigned long flags;
spin_lock_irqsave(&power_state_active_lock, flags);
power_state_active_cnt++;
spin_unlock_irqrestore(&power_state_active_lock, flags);
}
static int power_state_active_disable(void)
{
int ret = 0;
unsigned long flags;
spin_lock_irqsave(&power_state_active_lock, flags);
if (power_state_active_cnt <= 0) {
pr_err("power state: unbalanced enable/disable calls\n");
ret = -EINVAL;
goto out;
}
power_state_active_cnt--;
out:
spin_unlock_irqrestore(&power_state_active_lock, flags);
return ret;
}
/*
* Exported interface for CPUIdle only. This function is called when interrupts
* are turned off. Hence, no locking.
*/
int power_state_active_is_enabled(void)
{
return (power_state_active_cnt > 0);
}
/**
* struct db8500_regulator_info - db8500 regulator information
* @dev: device pointer
* @desc: regulator description
* @rdev: regulator device pointer
* @is_enabled: status of the regulator
* @epod_id: id for EPOD (power domain)
* @is_ramret: RAM retention switch for EPOD (power domain)
* @operating_point: operating point (only for vape, to be removed)
*
*/
struct db8500_regulator_info {
struct device *dev;
struct regulator_desc desc;
struct regulator_dev *rdev;
bool is_enabled;
u16 epod_id;
bool is_ramret;
bool exclude_from_power_state;
unsigned int operating_point;
};
static int db8500_regulator_enable(struct regulator_dev *rdev)
{
struct db8500_regulator_info *info = rdev_get_drvdata(rdev);
if (info == NULL)
return -EINVAL;
dev_vdbg(rdev_get_dev(rdev), "regulator-%s-enable\n",
info->desc.name);
info->is_enabled = true;
if (!info->exclude_from_power_state)
power_state_active_enable();
return 0;
}
static int db8500_regulator_disable(struct regulator_dev *rdev)
{
struct db8500_regulator_info *info = rdev_get_drvdata(rdev);
int ret = 0;
if (info == NULL)
return -EINVAL;
dev_vdbg(rdev_get_dev(rdev), "regulator-%s-disable\n",
info->desc.name);
info->is_enabled = false;
if (!info->exclude_from_power_state)
ret = power_state_active_disable();
return ret;
}
static int db8500_regulator_is_enabled(struct regulator_dev *rdev)
{
struct db8500_regulator_info *info = rdev_get_drvdata(rdev);
if (info == NULL)
return -EINVAL;
dev_vdbg(rdev_get_dev(rdev), "regulator-%s-is_enabled (is_enabled):"
" %i\n", info->desc.name, info->is_enabled);
return info->is_enabled;
}
/* db8500 regulator operations */
static struct regulator_ops db8500_regulator_ops = {
.enable = db8500_regulator_enable,
.disable = db8500_regulator_disable,
.is_enabled = db8500_regulator_is_enabled,
};
/*
* EPOD control
*/
static bool epod_on[NUM_EPOD_ID];
static bool epod_ramret[NUM_EPOD_ID];
static int enable_epod(u16 epod_id, bool ramret)
{
int ret;
if (ramret) {
if (!epod_on[epod_id]) {
ret = prcmu_set_epod(epod_id, EPOD_STATE_RAMRET);
if (ret < 0)
return ret;
}
epod_ramret[epod_id] = true;
} else {
ret = prcmu_set_epod(epod_id, EPOD_STATE_ON);
if (ret < 0)
return ret;
epod_on[epod_id] = true;
}
return 0;
}
static int disable_epod(u16 epod_id, bool ramret)
{
int ret;
if (ramret) {
if (!epod_on[epod_id]) {
ret = prcmu_set_epod(epod_id, EPOD_STATE_OFF);
if (ret < 0)
return ret;
}
epod_ramret[epod_id] = false;
} else {
if (epod_ramret[epod_id]) {
ret = prcmu_set_epod(epod_id, EPOD_STATE_RAMRET);
if (ret < 0)
return ret;
} else {
ret = prcmu_set_epod(epod_id, EPOD_STATE_OFF);
if (ret < 0)
return ret;
}
epod_on[epod_id] = false;
}
return 0;
}
/*
* Regulator switch
*/
static int db8500_regulator_switch_enable(struct regulator_dev *rdev)
{
struct db8500_regulator_info *info = rdev_get_drvdata(rdev);
int ret;
if (info == NULL)
return -EINVAL;
dev_vdbg(rdev_get_dev(rdev), "regulator-switch-%s-enable\n",
info->desc.name);
ret = enable_epod(info->epod_id, info->is_ramret);
if (ret < 0) {
dev_err(rdev_get_dev(rdev),
"regulator-switch-%s-enable: prcmu call failed\n",
info->desc.name);
goto out;
}
info->is_enabled = true;
out:
return ret;
}
static int db8500_regulator_switch_disable(struct regulator_dev *rdev)
{
struct db8500_regulator_info *info = rdev_get_drvdata(rdev);
int ret;
if (info == NULL)
return -EINVAL;
dev_vdbg(rdev_get_dev(rdev), "regulator-switch-%s-disable\n",
info->desc.name);
ret = disable_epod(info->epod_id, info->is_ramret);
if (ret < 0) {
dev_err(rdev_get_dev(rdev),
"regulator_switch-%s-disable: prcmu call failed\n",
info->desc.name);
goto out;
}
info->is_enabled = 0;
out:
return ret;
}
static int db8500_regulator_switch_is_enabled(struct regulator_dev *rdev)
{
struct db8500_regulator_info *info = rdev_get_drvdata(rdev);
if (info == NULL)
return -EINVAL;
dev_vdbg(rdev_get_dev(rdev),
"regulator-switch-%s-is_enabled (is_enabled): %i\n",
info->desc.name, info->is_enabled);
return info->is_enabled;
}
static struct regulator_ops db8500_regulator_switch_ops = {
.enable = db8500_regulator_switch_enable,
.disable = db8500_regulator_switch_disable,
.is_enabled = db8500_regulator_switch_is_enabled,
};
/*
* Regulator information
*/
static struct db8500_regulator_info
db8500_regulator_info[DB8500_NUM_REGULATORS] = {
[DB8500_REGULATOR_VAPE] = {
.desc = {
.name = "db8500-vape",
.id = DB8500_REGULATOR_VAPE,
.ops = &db8500_regulator_ops,
.type = REGULATOR_VOLTAGE,
.owner = THIS_MODULE,
},
},
[DB8500_REGULATOR_VARM] = {
.desc = {
.name = "db8500-varm",
.id = DB8500_REGULATOR_VARM,
.ops = &db8500_regulator_ops,
.type = REGULATOR_VOLTAGE,
.owner = THIS_MODULE,
},
},
[DB8500_REGULATOR_VMODEM] = {
.desc = {
.name = "db8500-vmodem",
.id = DB8500_REGULATOR_VMODEM,
.ops = &db8500_regulator_ops,
.type = REGULATOR_VOLTAGE,
.owner = THIS_MODULE,
},
},
[DB8500_REGULATOR_VPLL] = {
.desc = {
.name = "db8500-vpll",
.id = DB8500_REGULATOR_VPLL,
.ops = &db8500_regulator_ops,
.type = REGULATOR_VOLTAGE,
.owner = THIS_MODULE,
},
},
[DB8500_REGULATOR_VSMPS1] = {
.desc = {
.name = "db8500-vsmps1",
.id = DB8500_REGULATOR_VSMPS1,
.ops = &db8500_regulator_ops,
.type = REGULATOR_VOLTAGE,
.owner = THIS_MODULE,
},
},
[DB8500_REGULATOR_VSMPS2] = {
.desc = {
.name = "db8500-vsmps2",
.id = DB8500_REGULATOR_VSMPS2,
.ops = &db8500_regulator_ops,
.type = REGULATOR_VOLTAGE,
.owner = THIS_MODULE,
},
.exclude_from_power_state = true,
},
[DB8500_REGULATOR_VSMPS3] = {
.desc = {
.name = "db8500-vsmps3",
.id = DB8500_REGULATOR_VSMPS3,
.ops = &db8500_regulator_ops,
.type = REGULATOR_VOLTAGE,
.owner = THIS_MODULE,
},
},
[DB8500_REGULATOR_VRF1] = {
.desc = {
.name = "db8500-vrf1",
.id = DB8500_REGULATOR_VRF1,
.ops = &db8500_regulator_ops,
.type = REGULATOR_VOLTAGE,
.owner = THIS_MODULE,
},
},
[DB8500_REGULATOR_SWITCH_SVAMMDSP] = {
.desc = {
.name = "db8500-sva-mmdsp",
.id = DB8500_REGULATOR_SWITCH_SVAMMDSP,
.ops = &db8500_regulator_switch_ops,
.type = REGULATOR_VOLTAGE,
.owner = THIS_MODULE,
},
.epod_id = EPOD_ID_SVAMMDSP,
},
[DB8500_REGULATOR_SWITCH_SVAMMDSPRET] = {
.desc = {
.name = "db8500-sva-mmdsp-ret",
.id = DB8500_REGULATOR_SWITCH_SVAMMDSPRET,
.ops = &db8500_regulator_switch_ops,
.type = REGULATOR_VOLTAGE,
.owner = THIS_MODULE,
},
.epod_id = EPOD_ID_SVAMMDSP,
.is_ramret = true,
},
[DB8500_REGULATOR_SWITCH_SVAPIPE] = {
.desc = {
.name = "db8500-sva-pipe",
.id = DB8500_REGULATOR_SWITCH_SVAPIPE,
.ops = &db8500_regulator_switch_ops,
.type = REGULATOR_VOLTAGE,
.owner = THIS_MODULE,
},
.epod_id = EPOD_ID_SVAPIPE,
},
[DB8500_REGULATOR_SWITCH_SIAMMDSP] = {
.desc = {
.name = "db8500-sia-mmdsp",
.id = DB8500_REGULATOR_SWITCH_SIAMMDSP,
.ops = &db8500_regulator_switch_ops,
.type = REGULATOR_VOLTAGE,
.owner = THIS_MODULE,
},
.epod_id = EPOD_ID_SIAMMDSP,
},
[DB8500_REGULATOR_SWITCH_SIAMMDSPRET] = {
.desc = {
.name = "db8500-sia-mmdsp-ret",
.id = DB8500_REGULATOR_SWITCH_SIAMMDSPRET,
.ops = &db8500_regulator_switch_ops,
.type = REGULATOR_VOLTAGE,
.owner = THIS_MODULE,
},
.epod_id = EPOD_ID_SIAMMDSP,
.is_ramret = true,
},
[DB8500_REGULATOR_SWITCH_SIAPIPE] = {
.desc = {
.name = "db8500-sia-pipe",
.id = DB8500_REGULATOR_SWITCH_SIAPIPE,
.ops = &db8500_regulator_switch_ops,
.type = REGULATOR_VOLTAGE,
.owner = THIS_MODULE,
},
.epod_id = EPOD_ID_SIAPIPE,
},
[DB8500_REGULATOR_SWITCH_SGA] = {
.desc = {
.name = "db8500-sga",
.id = DB8500_REGULATOR_SWITCH_SGA,
.ops = &db8500_regulator_switch_ops,
.type = REGULATOR_VOLTAGE,
.owner = THIS_MODULE,
},
.epod_id = EPOD_ID_SGA,
},
[DB8500_REGULATOR_SWITCH_B2R2_MCDE] = {
.desc = {
.name = "db8500-b2r2-mcde",
.id = DB8500_REGULATOR_SWITCH_B2R2_MCDE,
.ops = &db8500_regulator_switch_ops,
.type = REGULATOR_VOLTAGE,
.owner = THIS_MODULE,
},
.epod_id = EPOD_ID_B2R2_MCDE,
},
[DB8500_REGULATOR_SWITCH_ESRAM12] = {
.desc = {
.name = "db8500-esram12",
.id = DB8500_REGULATOR_SWITCH_ESRAM12,
.ops = &db8500_regulator_switch_ops,
.type = REGULATOR_VOLTAGE,
.owner = THIS_MODULE,
},
.epod_id = EPOD_ID_ESRAM12,
.is_enabled = true,
},
[DB8500_REGULATOR_SWITCH_ESRAM12RET] = {
.desc = {
.name = "db8500-esram12-ret",
.id = DB8500_REGULATOR_SWITCH_ESRAM12RET,
.ops = &db8500_regulator_switch_ops,
.type = REGULATOR_VOLTAGE,
.owner = THIS_MODULE,
},
.epod_id = EPOD_ID_ESRAM12,
.is_ramret = true,
},
[DB8500_REGULATOR_SWITCH_ESRAM34] = {
.desc = {
.name = "db8500-esram34",
.id = DB8500_REGULATOR_SWITCH_ESRAM34,
.ops = &db8500_regulator_switch_ops,
.type = REGULATOR_VOLTAGE,
.owner = THIS_MODULE,
},
.epod_id = EPOD_ID_ESRAM34,
.is_enabled = true,
},
[DB8500_REGULATOR_SWITCH_ESRAM34RET] = {
.desc = {
.name = "db8500-esram34-ret",
.id = DB8500_REGULATOR_SWITCH_ESRAM34RET,
.ops = &db8500_regulator_switch_ops,
.type = REGULATOR_VOLTAGE,
.owner = THIS_MODULE,
},
.epod_id = EPOD_ID_ESRAM34,
.is_ramret = true,
},
};
static int __devinit db8500_regulator_probe(struct platform_device *pdev)
{
struct regulator_init_data *db8500_init_data = mfd_get_data(pdev);
int i, err;
/* register all regulators */
for (i = 0; i < ARRAY_SIZE(db8500_regulator_info); i++) {
struct db8500_regulator_info *info;
struct regulator_init_data *init_data = &db8500_init_data[i];
/* assign per-regulator data */
info = &db8500_regulator_info[i];
info->dev = &pdev->dev;
/* register with the regulator framework */
info->rdev = regulator_register(&info->desc, &pdev->dev,
init_data, info);
if (IS_ERR(info->rdev)) {
err = PTR_ERR(info->rdev);
dev_err(&pdev->dev, "failed to register %s: err %i\n",
info->desc.name, err);
/* if failing, unregister all earlier regulators */
i--;
while (i >= 0) {
info = &db8500_regulator_info[i];
regulator_unregister(info->rdev);
i--;
}
return err;
}
dev_dbg(rdev_get_dev(info->rdev),
"regulator-%s-probed\n", info->desc.name);
}
return 0;
}
static int __exit db8500_regulator_remove(struct platform_device *pdev)
{
int i;
for (i = 0; i < ARRAY_SIZE(db8500_regulator_info); i++) {
struct db8500_regulator_info *info;
info = &db8500_regulator_info[i];
dev_vdbg(rdev_get_dev(info->rdev),
"regulator-%s-remove\n", info->desc.name);
regulator_unregister(info->rdev);
}
return 0;
}
static struct platform_driver db8500_regulator_driver = {
.driver = {
.name = "db8500-prcmu-regulators",
.owner = THIS_MODULE,
},
.probe = db8500_regulator_probe,
.remove = __exit_p(db8500_regulator_remove),
};
static int __init db8500_regulator_init(void)
{
int ret;
ret = platform_driver_register(&db8500_regulator_driver);
if (ret < 0)
return -ENODEV;
return 0;
}
static void __exit db8500_regulator_exit(void)
{
platform_driver_unregister(&db8500_regulator_driver);
}
arch_initcall(db8500_regulator_init);
module_exit(db8500_regulator_exit);
MODULE_AUTHOR("STMicroelectronics/ST-Ericsson");
MODULE_DESCRIPTION("DB8500 regulator driver");
MODULE_LICENSE("GPL v2");

View File

@ -0,0 +1,45 @@
/*
* Copyright (C) ST-Ericsson SA 2010
*
* License Terms: GNU General Public License v2
*
* U5500 PRCMU API.
*/
#ifndef __MACH_PRCMU_U5500_H
#define __MACH_PRCMU_U5500_H
#ifdef CONFIG_UX500_SOC_DB5500
void db5500_prcmu_early_init(void);
int db5500_prcmu_abb_read(u8 slave, u8 reg, u8 *value, u8 size);
int db5500_prcmu_abb_write(u8 slave, u8 reg, u8 *value, u8 size);
#else /* !CONFIG_UX500_SOC_DB5500 */
static inline void db5500_prcmu_early_init(void)
{
}
static inline int db5500_prcmu_abb_read(u8 slave, u8 reg, u8 *value, u8 size)
{
return -ENOSYS;
}
static inline int db5500_prcmu_abb_write(u8 slave, u8 reg, u8 *value, u8 size)
{
return -ENOSYS;
}
#endif /* CONFIG_UX500_SOC_DB5500 */
static inline int db5500_prcmu_config_abb_event_readout(u32 abb_events)
{
#ifdef CONFIG_MACH_U5500_SIMULATOR
return 0;
#else
return -1;
#endif
}
#endif /* __MACH_PRCMU_U5500_H */

View File

@ -0,0 +1,978 @@
/*
* Copyright (C) STMicroelectronics 2009
* Copyright (C) ST-Ericsson SA 2010
*
* License Terms: GNU General Public License v2
* Author: Kumar Sanghvi <kumar.sanghvi@stericsson.com>
*
* PRCMU f/w APIs
*/
#ifndef __MFD_DB8500_PRCMU_H
#define __MFD_DB8500_PRCMU_H
#include <linux/interrupt.h>
#include <linux/notifier.h>
/* This portion previously known as <mach/prcmu-fw-defs_v1.h> */
/**
* enum state - ON/OFF state definition
* @OFF: State is ON
* @ON: State is OFF
*
*/
enum state {
OFF = 0x0,
ON = 0x1,
};
/**
* enum ret_state - general purpose On/Off/Retention states
*
*/
enum ret_state {
OFFST = 0,
ONST = 1,
RETST = 2
};
/**
* enum clk_arm - ARM Cortex A9 clock schemes
* @A9_OFF:
* @A9_BOOT:
* @A9_OPPT1:
* @A9_OPPT2:
* @A9_EXTCLK:
*/
enum clk_arm {
A9_OFF,
A9_BOOT,
A9_OPPT1,
A9_OPPT2,
A9_EXTCLK
};
/**
* enum clk_gen - GEN#0/GEN#1 clock schemes
* @GEN_OFF:
* @GEN_BOOT:
* @GEN_OPPT1:
*/
enum clk_gen {
GEN_OFF,
GEN_BOOT,
GEN_OPPT1,
};
/* some information between arm and xp70 */
/**
* enum romcode_write - Romcode message written by A9 AND read by XP70
* @RDY_2_DS: Value set when ApDeepSleep state can be executed by XP70
* @RDY_2_XP70_RST: Value set when 0x0F has been successfully polled by the
* romcode. The xp70 will go into self-reset
*/
enum romcode_write {
RDY_2_DS = 0x09,
RDY_2_XP70_RST = 0x10
};
/**
* enum romcode_read - Romcode message written by XP70 and read by A9
* @INIT: Init value when romcode field is not used
* @FS_2_DS: Value set when power state is going from ApExecute to
* ApDeepSleep
* @END_DS: Value set when ApDeepSleep power state is reached coming from
* ApExecute state
* @DS_TO_FS: Value set when power state is going from ApDeepSleep to
* ApExecute
* @END_FS: Value set when ApExecute power state is reached coming from
* ApDeepSleep state
* @SWR: Value set when power state is going to ApReset
* @END_SWR: Value set when the xp70 finished executing ApReset actions and
* waits for romcode acknowledgment to go to self-reset
*/
enum romcode_read {
INIT = 0x00,
FS_2_DS = 0x0A,
END_DS = 0x0B,
DS_TO_FS = 0x0C,
END_FS = 0x0D,
SWR = 0x0E,
END_SWR = 0x0F
};
/**
* enum ap_pwrst - current power states defined in PRCMU firmware
* @NO_PWRST: Current power state init
* @AP_BOOT: Current power state is apBoot
* @AP_EXECUTE: Current power state is apExecute
* @AP_DEEP_SLEEP: Current power state is apDeepSleep
* @AP_SLEEP: Current power state is apSleep
* @AP_IDLE: Current power state is apIdle
* @AP_RESET: Current power state is apReset
*/
enum ap_pwrst {
NO_PWRST = 0x00,
AP_BOOT = 0x01,
AP_EXECUTE = 0x02,
AP_DEEP_SLEEP = 0x03,
AP_SLEEP = 0x04,
AP_IDLE = 0x05,
AP_RESET = 0x06
};
/**
* enum ap_pwrst_trans - Transition states defined in PRCMU firmware
* @NO_TRANSITION: No power state transition
* @APEXECUTE_TO_APSLEEP: Power state transition from ApExecute to ApSleep
* @APIDLE_TO_APSLEEP: Power state transition from ApIdle to ApSleep
* @APBOOT_TO_APEXECUTE: Power state transition from ApBoot to ApExecute
* @APEXECUTE_TO_APDEEPSLEEP: Power state transition from ApExecute to
* ApDeepSleep
* @APEXECUTE_TO_APIDLE: Power state transition from ApExecute to ApIdle
*/
enum ap_pwrst_trans {
NO_TRANSITION = 0x00,
APEXECUTE_TO_APSLEEP = 0x01,
APIDLE_TO_APSLEEP = 0x02, /* To be removed */
PRCMU_AP_SLEEP = 0x01,
APBOOT_TO_APEXECUTE = 0x03,
APEXECUTE_TO_APDEEPSLEEP = 0x04, /* To be removed */
PRCMU_AP_DEEP_SLEEP = 0x04,
APEXECUTE_TO_APIDLE = 0x05, /* To be removed */
PRCMU_AP_IDLE = 0x05,
PRCMU_AP_DEEP_IDLE = 0x07,
};
/**
* enum ddr_pwrst - DDR power states definition
* @DDR_PWR_STATE_UNCHANGED: SDRAM and DDR controller state is unchanged
* @DDR_PWR_STATE_ON:
* @DDR_PWR_STATE_OFFLOWLAT:
* @DDR_PWR_STATE_OFFHIGHLAT:
*/
enum ddr_pwrst {
DDR_PWR_STATE_UNCHANGED = 0x00,
DDR_PWR_STATE_ON = 0x01,
DDR_PWR_STATE_OFFLOWLAT = 0x02,
DDR_PWR_STATE_OFFHIGHLAT = 0x03
};
/**
* enum arm_opp - ARM OPP states definition
* @ARM_OPP_INIT:
* @ARM_NO_CHANGE: The ARM operating point is unchanged
* @ARM_100_OPP: The new ARM operating point is arm100opp
* @ARM_50_OPP: The new ARM operating point is arm50opp
* @ARM_MAX_OPP: Operating point is "max" (more than 100)
* @ARM_MAX_FREQ100OPP: Set max opp if available, else 100
* @ARM_EXTCLK: The new ARM operating point is armExtClk
*/
enum arm_opp {
ARM_OPP_INIT = 0x00,
ARM_NO_CHANGE = 0x01,
ARM_100_OPP = 0x02,
ARM_50_OPP = 0x03,
ARM_MAX_OPP = 0x04,
ARM_MAX_FREQ100OPP = 0x05,
ARM_EXTCLK = 0x07
};
/**
* enum ape_opp - APE OPP states definition
* @APE_OPP_INIT:
* @APE_NO_CHANGE: The APE operating point is unchanged
* @APE_100_OPP: The new APE operating point is ape100opp
* @APE_50_OPP: 50%
*/
enum ape_opp {
APE_OPP_INIT = 0x00,
APE_NO_CHANGE = 0x01,
APE_100_OPP = 0x02,
APE_50_OPP = 0x03
};
/**
* enum hw_acc_state - State definition for hardware accelerator
* @HW_NO_CHANGE: The hardware accelerator state must remain unchanged
* @HW_OFF: The hardware accelerator must be switched off
* @HW_OFF_RAMRET: The hardware accelerator must be switched off with its
* internal RAM in retention
* @HW_ON: The hwa hardware accelerator hwa must be switched on
*
* NOTE! Deprecated, to be removed when all users switched over to use the
* regulator API.
*/
enum hw_acc_state {
HW_NO_CHANGE = 0x00,
HW_OFF = 0x01,
HW_OFF_RAMRET = 0x02,
HW_ON = 0x04
};
/**
* enum mbox_2_arm_stat - Status messages definition for mbox_arm
* @BOOT_TO_EXECUTEOK: The apBoot to apExecute state transition has been
* completed
* @DEEPSLEEPOK: The apExecute to apDeepSleep state transition has been
* completed
* @SLEEPOK: The apExecute to apSleep state transition has been completed
* @IDLEOK: The apExecute to apIdle state transition has been completed
* @SOFTRESETOK: The A9 watchdog/ SoftReset state has been completed
* @SOFTRESETGO : The A9 watchdog/SoftReset state is on going
* @BOOT_TO_EXECUTE: The apBoot to apExecute state transition is on going
* @EXECUTE_TO_DEEPSLEEP: The apExecute to apDeepSleep state transition is on
* going
* @DEEPSLEEP_TO_EXECUTE: The apDeepSleep to apExecute state transition is on
* going
* @DEEPSLEEP_TO_EXECUTEOK: The apDeepSleep to apExecute state transition has
* been completed
* @EXECUTE_TO_SLEEP: The apExecute to apSleep state transition is on going
* @SLEEP_TO_EXECUTE: The apSleep to apExecute state transition is on going
* @SLEEP_TO_EXECUTEOK: The apSleep to apExecute state transition has been
* completed
* @EXECUTE_TO_IDLE: The apExecute to apIdle state transition is on going
* @IDLE_TO_EXECUTE: The apIdle to apExecute state transition is on going
* @IDLE_TO_EXECUTEOK: The apIdle to apExecute state transition has been
* completed
* @INIT_STATUS: Status init
*/
enum ap_pwrsttr_status {
BOOT_TO_EXECUTEOK = 0xFF,
DEEPSLEEPOK = 0xFE,
SLEEPOK = 0xFD,
IDLEOK = 0xFC,
SOFTRESETOK = 0xFB,
SOFTRESETGO = 0xFA,
BOOT_TO_EXECUTE = 0xF9,
EXECUTE_TO_DEEPSLEEP = 0xF8,
DEEPSLEEP_TO_EXECUTE = 0xF7,
DEEPSLEEP_TO_EXECUTEOK = 0xF6,
EXECUTE_TO_SLEEP = 0xF5,
SLEEP_TO_EXECUTE = 0xF4,
SLEEP_TO_EXECUTEOK = 0xF3,
EXECUTE_TO_IDLE = 0xF2,
IDLE_TO_EXECUTE = 0xF1,
IDLE_TO_EXECUTEOK = 0xF0,
RDYTODS_RETURNTOEXE = 0xEF,
NORDYTODS_RETURNTOEXE = 0xEE,
EXETOSLEEP_RETURNTOEXE = 0xED,
EXETOIDLE_RETURNTOEXE = 0xEC,
INIT_STATUS = 0xEB,
/*error messages */
INITERROR = 0x00,
PLLARMLOCKP_ER = 0x01,
PLLDDRLOCKP_ER = 0x02,
PLLSOCLOCKP_ER = 0x03,
PLLSOCK1LOCKP_ER = 0x04,
ARMWFI_ER = 0x05,
SYSCLKOK_ER = 0x06,
I2C_NACK_DATA_ER = 0x07,
BOOT_ER = 0x08,
I2C_STATUS_ALWAYS_1 = 0x0A,
I2C_NACK_REG_ADDR_ER = 0x0B,
I2C_NACK_DATA0123_ER = 0x1B,
I2C_NACK_ADDR_ER = 0x1F,
CURAPPWRSTISNOT_BOOT = 0x20,
CURAPPWRSTISNOT_EXECUTE = 0x21,
CURAPPWRSTISNOT_SLEEPMODE = 0x22,
CURAPPWRSTISNOT_CORRECTFORIT10 = 0x23,
FIFO4500WUISNOT_WUPEVENT = 0x24,
PLL32KLOCKP_ER = 0x29,
DDRDEEPSLEEPOK_ER = 0x2A,
ROMCODEREADY_ER = 0x50,
WUPBEFOREDS = 0x51,
DDRCONFIG_ER = 0x52,
WUPBEFORESLEEP = 0x53,
WUPBEFOREIDLE = 0x54
}; /* earlier called as mbox_2_arm_stat */
/**
* enum dvfs_stat - DVFS status messages definition
* @DVFS_GO: A state transition DVFS is on going
* @DVFS_ARM100OPPOK: The state transition DVFS has been completed for 100OPP
* @DVFS_ARM50OPPOK: The state transition DVFS has been completed for 50OPP
* @DVFS_ARMEXTCLKOK: The state transition DVFS has been completed for EXTCLK
* @DVFS_NOCHGTCLKOK: The state transition DVFS has been completed for
* NOCHGCLK
* @DVFS_INITSTATUS: Value init
*/
enum dvfs_stat {
DVFS_GO = 0xFF,
DVFS_ARM100OPPOK = 0xFE,
DVFS_ARM50OPPOK = 0xFD,
DVFS_ARMEXTCLKOK = 0xFC,
DVFS_NOCHGTCLKOK = 0xFB,
DVFS_INITSTATUS = 0x00
};
/**
* enum sva_mmdsp_stat - SVA MMDSP status messages
* @SVA_MMDSP_GO: SVAMMDSP interrupt has happened
* @SVA_MMDSP_INIT: Status init
*/
enum sva_mmdsp_stat {
SVA_MMDSP_GO = 0xFF,
SVA_MMDSP_INIT = 0x00
};
/**
* enum sia_mmdsp_stat - SIA MMDSP status messages
* @SIA_MMDSP_GO: SIAMMDSP interrupt has happened
* @SIA_MMDSP_INIT: Status init
*/
enum sia_mmdsp_stat {
SIA_MMDSP_GO = 0xFF,
SIA_MMDSP_INIT = 0x00
};
/**
* enum mbox_to_arm_err - Error messages definition
* @INIT_ERR: Init value
* @PLLARMLOCKP_ERR: PLLARM has not been correctly locked in given time
* @PLLDDRLOCKP_ERR: PLLDDR has not been correctly locked in the given time
* @PLLSOC0LOCKP_ERR: PLLSOC0 has not been correctly locked in the given time
* @PLLSOC1LOCKP_ERR: PLLSOC1 has not been correctly locked in the given time
* @ARMWFI_ERR: The ARM WFI has not been correctly executed in the given time
* @SYSCLKOK_ERR: The SYSCLK is not available in the given time
* @BOOT_ERR: Romcode has not validated the XP70 self reset in the given time
* @ROMCODESAVECONTEXT: The Romcode didn.t correctly save it secure context
* @VARMHIGHSPEEDVALTO_ERR: The ARM high speed supply value transfered
* through I2C has not been correctly executed in the given time
* @VARMHIGHSPEEDACCESS_ERR: The command value of VarmHighSpeedVal transfered
* through I2C has not been correctly executed in the given time
* @VARMLOWSPEEDVALTO_ERR:The ARM low speed supply value transfered through
* I2C has not been correctly executed in the given time
* @VARMLOWSPEEDACCESS_ERR: The command value of VarmLowSpeedVal transfered
* through I2C has not been correctly executed in the given time
* @VARMRETENTIONVALTO_ERR: The ARM retention supply value transfered through
* I2C has not been correctly executed in the given time
* @VARMRETENTIONACCESS_ERR: The command value of VarmRetentionVal transfered
* through I2C has not been correctly executed in the given time
* @VAPEHIGHSPEEDVALTO_ERR: The APE highspeed supply value transfered through
* I2C has not been correctly executed in the given time
* @VSAFEHPVALTO_ERR: The SAFE high power supply value transfered through I2C
* has not been correctly executed in the given time
* @VMODSEL1VALTO_ERR: The MODEM sel1 supply value transfered through I2C has
* not been correctly executed in the given time
* @VMODSEL2VALTO_ERR: The MODEM sel2 supply value transfered through I2C has
* not been correctly executed in the given time
* @VARMOFFACCESS_ERR: The command value of Varm ON/OFF transfered through
* I2C has not been correctly executed in the given time
* @VAPEOFFACCESS_ERR: The command value of Vape ON/OFF transfered through
* I2C has not been correctly executed in the given time
* @VARMRETACCES_ERR: The command value of Varm retention ON/OFF transfered
* through I2C has not been correctly executed in the given time
* @CURAPPWRSTISNOTBOOT:Generated when Arm want to do power state transition
* ApBoot to ApExecute but the power current state is not Apboot
* @CURAPPWRSTISNOTEXECUTE: Generated when Arm want to do power state
* transition from ApExecute to others power state but the
* power current state is not ApExecute
* @CURAPPWRSTISNOTSLEEPMODE: Generated when wake up events are transmitted
* but the power current state is not ApDeepSleep/ApSleep/ApIdle
* @CURAPPWRSTISNOTCORRECTDBG: Generated when wake up events are transmitted
* but the power current state is not correct
* @ARMREGU1VALTO_ERR:The ArmRegu1 value transferred through I2C has not
* been correctly executed in the given time
* @ARMREGU2VALTO_ERR: The ArmRegu2 value transferred through I2C has not
* been correctly executed in the given time
* @VAPEREGUVALTO_ERR: The VApeRegu value transfered through I2C has not
* been correctly executed in the given time
* @VSMPS3REGUVALTO_ERR: The VSmps3Regu value transfered through I2C has not
* been correctly executed in the given time
* @VMODREGUVALTO_ERR: The VModemRegu value transfered through I2C has not
* been correctly executed in the given time
*/
enum mbox_to_arm_err {
INIT_ERR = 0x00,
PLLARMLOCKP_ERR = 0x01,
PLLDDRLOCKP_ERR = 0x02,
PLLSOC0LOCKP_ERR = 0x03,
PLLSOC1LOCKP_ERR = 0x04,
ARMWFI_ERR = 0x05,
SYSCLKOK_ERR = 0x06,
BOOT_ERR = 0x07,
ROMCODESAVECONTEXT = 0x08,
VARMHIGHSPEEDVALTO_ERR = 0x10,
VARMHIGHSPEEDACCESS_ERR = 0x11,
VARMLOWSPEEDVALTO_ERR = 0x12,
VARMLOWSPEEDACCESS_ERR = 0x13,
VARMRETENTIONVALTO_ERR = 0x14,
VARMRETENTIONACCESS_ERR = 0x15,
VAPEHIGHSPEEDVALTO_ERR = 0x16,
VSAFEHPVALTO_ERR = 0x17,
VMODSEL1VALTO_ERR = 0x18,
VMODSEL2VALTO_ERR = 0x19,
VARMOFFACCESS_ERR = 0x1A,
VAPEOFFACCESS_ERR = 0x1B,
VARMRETACCES_ERR = 0x1C,
CURAPPWRSTISNOTBOOT = 0x20,
CURAPPWRSTISNOTEXECUTE = 0x21,
CURAPPWRSTISNOTSLEEPMODE = 0x22,
CURAPPWRSTISNOTCORRECTDBG = 0x23,
ARMREGU1VALTO_ERR = 0x24,
ARMREGU2VALTO_ERR = 0x25,
VAPEREGUVALTO_ERR = 0x26,
VSMPS3REGUVALTO_ERR = 0x27,
VMODREGUVALTO_ERR = 0x28
};
enum hw_acc {
SVAMMDSP = 0,
SVAPIPE = 1,
SIAMMDSP = 2,
SIAPIPE = 3,
SGA = 4,
B2R2MCDE = 5,
ESRAM12 = 6,
ESRAM34 = 7,
};
enum cs_pwrmgt {
PWRDNCS0 = 0,
WKUPCS0 = 1,
PWRDNCS1 = 2,
WKUPCS1 = 3
};
/* Defs related to autonomous power management */
/**
* enum sia_sva_pwr_policy - Power policy
* @NO_CHGT: No change
* @DSPOFF_HWPOFF:
* @DSPOFFRAMRET_HWPOFF:
* @DSPCLKOFF_HWPOFF:
* @DSPCLKOFF_HWPCLKOFF:
*
*/
enum sia_sva_pwr_policy {
NO_CHGT = 0x0,
DSPOFF_HWPOFF = 0x1,
DSPOFFRAMRET_HWPOFF = 0x2,
DSPCLKOFF_HWPOFF = 0x3,
DSPCLKOFF_HWPCLKOFF = 0x4,
};
/**
* enum auto_enable - Auto Power enable
* @AUTO_OFF:
* @AUTO_ON:
*
*/
enum auto_enable {
AUTO_OFF = 0x0,
AUTO_ON = 0x1,
};
/* End of file previously known as prcmu-fw-defs_v1.h */
/* PRCMU Wakeup defines */
enum prcmu_wakeup_index {
PRCMU_WAKEUP_INDEX_RTC,
PRCMU_WAKEUP_INDEX_RTT0,
PRCMU_WAKEUP_INDEX_RTT1,
PRCMU_WAKEUP_INDEX_HSI0,
PRCMU_WAKEUP_INDEX_HSI1,
PRCMU_WAKEUP_INDEX_USB,
PRCMU_WAKEUP_INDEX_ABB,
PRCMU_WAKEUP_INDEX_ABB_FIFO,
PRCMU_WAKEUP_INDEX_ARM,
NUM_PRCMU_WAKEUP_INDICES
};
#define PRCMU_WAKEUP(_name) (BIT(PRCMU_WAKEUP_INDEX_##_name))
/* PRCMU QoS APE OPP class */
#define PRCMU_QOS_APE_OPP 1
#define PRCMU_QOS_DDR_OPP 2
#define PRCMU_QOS_DEFAULT_VALUE -1
/**
* enum hw_acc_dev - enum for hw accelerators
* @HW_ACC_SVAMMDSP: for SVAMMDSP
* @HW_ACC_SVAPIPE: for SVAPIPE
* @HW_ACC_SIAMMDSP: for SIAMMDSP
* @HW_ACC_SIAPIPE: for SIAPIPE
* @HW_ACC_SGA: for SGA
* @HW_ACC_B2R2: for B2R2
* @HW_ACC_MCDE: for MCDE
* @HW_ACC_ESRAM1: for ESRAM1
* @HW_ACC_ESRAM2: for ESRAM2
* @HW_ACC_ESRAM3: for ESRAM3
* @HW_ACC_ESRAM4: for ESRAM4
* @NUM_HW_ACC: number of hardware accelerators
*
* Different hw accelerators which can be turned ON/
* OFF or put into retention (MMDSPs and ESRAMs).
* Used with EPOD API.
*
* NOTE! Deprecated, to be removed when all users switched over to use the
* regulator API.
*/
enum hw_acc_dev {
HW_ACC_SVAMMDSP,
HW_ACC_SVAPIPE,
HW_ACC_SIAMMDSP,
HW_ACC_SIAPIPE,
HW_ACC_SGA,
HW_ACC_B2R2,
HW_ACC_MCDE,
HW_ACC_ESRAM1,
HW_ACC_ESRAM2,
HW_ACC_ESRAM3,
HW_ACC_ESRAM4,
NUM_HW_ACC
};
/*
* Ids for all EPODs (power domains)
* - EPOD_ID_SVAMMDSP: power domain for SVA MMDSP
* - EPOD_ID_SVAPIPE: power domain for SVA pipe
* - EPOD_ID_SIAMMDSP: power domain for SIA MMDSP
* - EPOD_ID_SIAPIPE: power domain for SIA pipe
* - EPOD_ID_SGA: power domain for SGA
* - EPOD_ID_B2R2_MCDE: power domain for B2R2 and MCDE
* - EPOD_ID_ESRAM12: power domain for ESRAM 1 and 2
* - EPOD_ID_ESRAM34: power domain for ESRAM 3 and 4
* - NUM_EPOD_ID: number of power domains
*/
#define EPOD_ID_SVAMMDSP 0
#define EPOD_ID_SVAPIPE 1
#define EPOD_ID_SIAMMDSP 2
#define EPOD_ID_SIAPIPE 3
#define EPOD_ID_SGA 4
#define EPOD_ID_B2R2_MCDE 5
#define EPOD_ID_ESRAM12 6
#define EPOD_ID_ESRAM34 7
#define NUM_EPOD_ID 8
/*
* state definition for EPOD (power domain)
* - EPOD_STATE_NO_CHANGE: The EPOD should remain unchanged
* - EPOD_STATE_OFF: The EPOD is switched off
* - EPOD_STATE_RAMRET: The EPOD is switched off with its internal RAM in
* retention
* - EPOD_STATE_ON_CLK_OFF: The EPOD is switched on, clock is still off
* - EPOD_STATE_ON: Same as above, but with clock enabled
*/
#define EPOD_STATE_NO_CHANGE 0x00
#define EPOD_STATE_OFF 0x01
#define EPOD_STATE_RAMRET 0x02
#define EPOD_STATE_ON_CLK_OFF 0x03
#define EPOD_STATE_ON 0x04
/*
* CLKOUT sources
*/
#define PRCMU_CLKSRC_CLK38M 0x00
#define PRCMU_CLKSRC_ACLK 0x01
#define PRCMU_CLKSRC_SYSCLK 0x02
#define PRCMU_CLKSRC_LCDCLK 0x03
#define PRCMU_CLKSRC_SDMMCCLK 0x04
#define PRCMU_CLKSRC_TVCLK 0x05
#define PRCMU_CLKSRC_TIMCLK 0x06
#define PRCMU_CLKSRC_CLK009 0x07
/* These are only valid for CLKOUT1: */
#define PRCMU_CLKSRC_SIAMMDSPCLK 0x40
#define PRCMU_CLKSRC_I2CCLK 0x41
#define PRCMU_CLKSRC_MSP02CLK 0x42
#define PRCMU_CLKSRC_ARMPLL_OBSCLK 0x43
#define PRCMU_CLKSRC_HSIRXCLK 0x44
#define PRCMU_CLKSRC_HSITXCLK 0x45
#define PRCMU_CLKSRC_ARMCLKFIX 0x46
#define PRCMU_CLKSRC_HDMICLK 0x47
/*
* Definitions for autonomous power management configuration.
*/
#define PRCMU_AUTO_PM_OFF 0
#define PRCMU_AUTO_PM_ON 1
#define PRCMU_AUTO_PM_POWER_ON_HSEM BIT(0)
#define PRCMU_AUTO_PM_POWER_ON_ABB_FIFO_IT BIT(1)
enum prcmu_auto_pm_policy {
PRCMU_AUTO_PM_POLICY_NO_CHANGE,
PRCMU_AUTO_PM_POLICY_DSP_OFF_HWP_OFF,
PRCMU_AUTO_PM_POLICY_DSP_OFF_RAMRET_HWP_OFF,
PRCMU_AUTO_PM_POLICY_DSP_CLK_OFF_HWP_OFF,
PRCMU_AUTO_PM_POLICY_DSP_CLK_OFF_HWP_CLK_OFF,
};
/**
* struct prcmu_auto_pm_config - Autonomous power management configuration.
* @sia_auto_pm_enable: SIA autonomous pm enable. (PRCMU_AUTO_PM_{OFF,ON})
* @sia_power_on: SIA power ON enable. (PRCMU_AUTO_PM_POWER_ON_* bitmask)
* @sia_policy: SIA power policy. (enum prcmu_auto_pm_policy)
* @sva_auto_pm_enable: SVA autonomous pm enable. (PRCMU_AUTO_PM_{OFF,ON})
* @sva_power_on: SVA power ON enable. (PRCMU_AUTO_PM_POWER_ON_* bitmask)
* @sva_policy: SVA power policy. (enum prcmu_auto_pm_policy)
*/
struct prcmu_auto_pm_config {
u8 sia_auto_pm_enable;
u8 sia_power_on;
u8 sia_policy;
u8 sva_auto_pm_enable;
u8 sva_power_on;
u8 sva_policy;
};
/**
* enum ddr_opp - DDR OPP states definition
* @DDR_100_OPP: The new DDR operating point is ddr100opp
* @DDR_50_OPP: The new DDR operating point is ddr50opp
* @DDR_25_OPP: The new DDR operating point is ddr25opp
*/
enum ddr_opp {
DDR_100_OPP = 0x00,
DDR_50_OPP = 0x01,
DDR_25_OPP = 0x02,
};
/*
* Clock identifiers.
*/
enum prcmu_clock {
PRCMU_SGACLK,
PRCMU_UARTCLK,
PRCMU_MSP02CLK,
PRCMU_MSP1CLK,
PRCMU_I2CCLK,
PRCMU_SDMMCCLK,
PRCMU_SLIMCLK,
PRCMU_PER1CLK,
PRCMU_PER2CLK,
PRCMU_PER3CLK,
PRCMU_PER5CLK,
PRCMU_PER6CLK,
PRCMU_PER7CLK,
PRCMU_LCDCLK,
PRCMU_BMLCLK,
PRCMU_HSITXCLK,
PRCMU_HSIRXCLK,
PRCMU_HDMICLK,
PRCMU_APEATCLK,
PRCMU_APETRACECLK,
PRCMU_MCDECLK,
PRCMU_IPI2CCLK,
PRCMU_DSIALTCLK,
PRCMU_DMACLK,
PRCMU_B2R2CLK,
PRCMU_TVCLK,
PRCMU_SSPCLK,
PRCMU_RNGCLK,
PRCMU_UICCCLK,
PRCMU_NUM_REG_CLOCKS,
PRCMU_SYSCLK = PRCMU_NUM_REG_CLOCKS,
PRCMU_TIMCLK,
};
/*
* Definitions for controlling ESRAM0 in deep sleep.
*/
#define ESRAM0_DEEP_SLEEP_STATE_OFF 1
#define ESRAM0_DEEP_SLEEP_STATE_RET 2
#ifdef CONFIG_MFD_DB8500_PRCMU
void __init prcmu_early_init(void);
int prcmu_set_display_clocks(void);
int prcmu_disable_dsipll(void);
int prcmu_enable_dsipll(void);
#else
static inline void __init prcmu_early_init(void) {}
#endif
#ifdef CONFIG_MFD_DB8500_PRCMU
int prcmu_set_rc_a2p(enum romcode_write);
enum romcode_read prcmu_get_rc_p2a(void);
enum ap_pwrst prcmu_get_xp70_current_state(void);
int prcmu_set_power_state(u8 state, bool keep_ulp_clk, bool keep_ap_pll);
void prcmu_enable_wakeups(u32 wakeups);
static inline void prcmu_disable_wakeups(void)
{
prcmu_enable_wakeups(0);
}
void prcmu_config_abb_event_readout(u32 abb_events);
void prcmu_get_abb_event_buffer(void __iomem **buf);
int prcmu_set_arm_opp(u8 opp);
int prcmu_get_arm_opp(void);
bool prcmu_has_arm_maxopp(void);
bool prcmu_is_u8400(void);
int prcmu_set_ape_opp(u8 opp);
int prcmu_get_ape_opp(void);
int prcmu_request_ape_opp_100_voltage(bool enable);
int prcmu_release_usb_wakeup_state(void);
int prcmu_set_ddr_opp(u8 opp);
int prcmu_get_ddr_opp(void);
unsigned long prcmu_qos_get_cpufreq_opp_delay(void);
void prcmu_qos_set_cpufreq_opp_delay(unsigned long);
/* NOTE! Use regulator framework instead */
int prcmu_set_hwacc(u16 hw_acc_dev, u8 state);
int prcmu_set_epod(u16 epod_id, u8 epod_state);
void prcmu_configure_auto_pm(struct prcmu_auto_pm_config *sleep,
struct prcmu_auto_pm_config *idle);
bool prcmu_is_auto_pm_enabled(void);
int prcmu_config_clkout(u8 clkout, u8 source, u8 div);
int prcmu_request_clock(u8 clock, bool enable);
int prcmu_set_clock_divider(u8 clock, u8 divider);
int prcmu_config_esram0_deep_sleep(u8 state);
int prcmu_config_hotdog(u8 threshold);
int prcmu_config_hotmon(u8 low, u8 high);
int prcmu_start_temp_sense(u16 cycles32k);
int prcmu_stop_temp_sense(void);
int prcmu_abb_read(u8 slave, u8 reg, u8 *value, u8 size);
int prcmu_abb_write(u8 slave, u8 reg, u8 *value, u8 size);
void prcmu_ac_wake_req(void);
void prcmu_ac_sleep_req(void);
void prcmu_system_reset(u16 reset_code);
void prcmu_modem_reset(void);
bool prcmu_is_ac_wake_requested(void);
void prcmu_enable_spi2(void);
void prcmu_disable_spi2(void);
#else /* !CONFIG_MFD_DB8500_PRCMU */
static inline int prcmu_set_rc_a2p(enum romcode_write code)
{
return 0;
}
static inline enum romcode_read prcmu_get_rc_p2a(void)
{
return INIT;
}
static inline enum ap_pwrst prcmu_get_xp70_current_state(void)
{
return AP_EXECUTE;
}
static inline int prcmu_set_power_state(u8 state, bool keep_ulp_clk,
bool keep_ap_pll)
{
return 0;
}
static inline void prcmu_enable_wakeups(u32 wakeups) {}
static inline void prcmu_disable_wakeups(void) {}
static inline void prcmu_config_abb_event_readout(u32 abb_events) {}
static inline int prcmu_set_arm_opp(u8 opp)
{
return 0;
}
static inline int prcmu_get_arm_opp(void)
{
return ARM_100_OPP;
}
static bool prcmu_has_arm_maxopp(void)
{
return false;
}
static bool prcmu_is_u8400(void)
{
return false;
}
static inline int prcmu_set_ape_opp(u8 opp)
{
return 0;
}
static inline int prcmu_get_ape_opp(void)
{
return APE_100_OPP;
}
static inline int prcmu_request_ape_opp_100_voltage(bool enable)
{
return 0;
}
static inline int prcmu_release_usb_wakeup_state(void)
{
return 0;
}
static inline int prcmu_set_ddr_opp(u8 opp)
{
return 0;
}
static inline int prcmu_get_ddr_opp(void)
{
return DDR_100_OPP;
}
static inline unsigned long prcmu_qos_get_cpufreq_opp_delay(void)
{
return 0;
}
static inline void prcmu_qos_set_cpufreq_opp_delay(unsigned long n) {}
static inline int prcmu_set_hwacc(u16 hw_acc_dev, u8 state)
{
return 0;
}
static inline void prcmu_configure_auto_pm(struct prcmu_auto_pm_config *sleep,
struct prcmu_auto_pm_config *idle)
{
}
static inline bool prcmu_is_auto_pm_enabled(void)
{
return false;
}
static inline int prcmu_config_clkout(u8 clkout, u8 source, u8 div)
{
return 0;
}
static inline int prcmu_request_clock(u8 clock, bool enable)
{
return 0;
}
static inline int prcmu_set_clock_divider(u8 clock, u8 divider)
{
return 0;
}
int prcmu_config_esram0_deep_sleep(u8 state)
{
return 0;
}
static inline int prcmu_config_hotdog(u8 threshold)
{
return 0;
}
static inline int prcmu_config_hotmon(u8 low, u8 high)
{
return 0;
}
static inline int prcmu_start_temp_sense(u16 cycles32k)
{
return 0;
}
static inline int prcmu_stop_temp_sense(void)
{
return 0;
}
static inline int prcmu_abb_read(u8 slave, u8 reg, u8 *value, u8 size)
{
return -ENOSYS;
}
static inline int prcmu_abb_write(u8 slave, u8 reg, u8 *value, u8 size)
{
return -ENOSYS;
}
static inline void prcmu_ac_wake_req(void) {}
static inline void prcmu_ac_sleep_req(void) {}
static inline void prcmu_system_reset(u16 reset_code) {}
static inline void prcmu_modem_reset(void) {}
static inline bool prcmu_is_ac_wake_requested(void)
{
return false;
}
#ifndef CONFIG_UX500_SOC_DB5500
static inline int prcmu_set_display_clocks(void)
{
return 0;
}
static inline int prcmu_disable_dsipll(void)
{
return 0;
}
static inline int prcmu_enable_dsipll(void)
{
return 0;
}
#endif
static inline int prcmu_enable_spi2(void)
{
return 0;
}
static inline int prcmu_disable_spi2(void)
{
return 0;
}
#endif /* !CONFIG_MFD_DB8500_PRCMU */
#ifdef CONFIG_UX500_PRCMU_QOS_POWER
int prcmu_qos_requirement(int pm_qos_class);
int prcmu_qos_add_requirement(int pm_qos_class, char *name, s32 value);
int prcmu_qos_update_requirement(int pm_qos_class, char *name, s32 new_value);
void prcmu_qos_remove_requirement(int pm_qos_class, char *name);
int prcmu_qos_add_notifier(int prcmu_qos_class,
struct notifier_block *notifier);
int prcmu_qos_remove_notifier(int prcmu_qos_class,
struct notifier_block *notifier);
#else
static inline int prcmu_qos_requirement(int prcmu_qos_class)
{
return 0;
}
static inline int prcmu_qos_add_requirement(int prcmu_qos_class,
char *name, s32 value)
{
return 0;
}
static inline int prcmu_qos_update_requirement(int prcmu_qos_class,
char *name, s32 new_value)
{
return 0;
}
static inline void prcmu_qos_remove_requirement(int prcmu_qos_class, char *name)
{
}
static inline int prcmu_qos_add_notifier(int prcmu_qos_class,
struct notifier_block *notifier)
{
return 0;
}
static inline int prcmu_qos_remove_notifier(int prcmu_qos_class,
struct notifier_block *notifier)
{
return 0;
}
#endif
#endif /* __MFD_DB8500_PRCMU_H */

View File

@ -0,0 +1,45 @@
/*
* Copyright (C) ST-Ericsson SA 2010
*
* License Terms: GNU General Public License v2
*
* Author: Bengt Jonsson <bengt.g.jonsson@stericsson.com> for ST-Ericsson
*
* Interface to power domain regulators on DB8500
*/
#ifndef __REGULATOR_H__
#define __REGULATOR_H__
/* Number of DB8500 regulators and regulator enumeration */
enum db8500_regulator_id {
DB8500_REGULATOR_VAPE,
DB8500_REGULATOR_VARM,
DB8500_REGULATOR_VMODEM,
DB8500_REGULATOR_VPLL,
DB8500_REGULATOR_VSMPS1,
DB8500_REGULATOR_VSMPS2,
DB8500_REGULATOR_VSMPS3,
DB8500_REGULATOR_VRF1,
DB8500_REGULATOR_SWITCH_SVAMMDSP,
DB8500_REGULATOR_SWITCH_SVAMMDSPRET,
DB8500_REGULATOR_SWITCH_SVAPIPE,
DB8500_REGULATOR_SWITCH_SIAMMDSP,
DB8500_REGULATOR_SWITCH_SIAMMDSPRET,
DB8500_REGULATOR_SWITCH_SIAPIPE,
DB8500_REGULATOR_SWITCH_SGA,
DB8500_REGULATOR_SWITCH_B2R2_MCDE,
DB8500_REGULATOR_SWITCH_ESRAM12,
DB8500_REGULATOR_SWITCH_ESRAM12RET,
DB8500_REGULATOR_SWITCH_ESRAM34,
DB8500_REGULATOR_SWITCH_ESRAM34RET,
DB8500_NUM_REGULATORS
};
/*
* Exported interface for CPUIdle only. This function is called with all
* interrupts turned off.
*/
int power_state_active_is_enabled(void);
#endif